正しいタイムゾーンで日付を表示する方法は?


18

コンテンツタイプに日時範囲フィールド(field_date)があります。コンテンツタイプを作成したら、開始日を次のように設定します。

2017-02-27 19:30:01

ここに画像の説明を入力してください

ここで、値を取得して日付を他の形式で表示したいので、次のコードを使用してみてください。

// Loading the node.
$node = Node::load(2100);
// Getting the start date value.
$date = $node->field_date->value;
// Printing to see what is the output.
dpm($node->field_date->value);
$date = strtotime($date);
// Printing my timezone.
dpm(drupal_get_user_timezone());
// Applying my custom format.
$date = \Drupal::service('date.formatter')->format($date, 'custom', 'Y-m-d H:i:s', drupal_get_user_timezone());
// Printing to see the output.
dpm($date);

これは私の出力です:

// It's fine.
2017-02-28T00:30:01
// Its fine.
America/New_York
// This is not what I waiting for. I'm waiting here: 2017-02-27 19:30:01
2017-02-28 00:30:01

だから、正しいタイムゾーンで日付を表示する方法は?

回答:


20

問題はのニュアンスに関係があると思うstrtotime()

strtotime()ほぼすべての文字列を取得し、Unixタイムスタンプに変換できます。問題は、文字列に明示的なタイムゾーンが含まれていない場合、によって設定されたものが使用されることdate_default_timezone_get()です。ただし、これは現在のユーザーから設定する必要があります(アカウントプロキシによって設定されます)。ただし、引き出している文字列$node->field_date->valueは暗黙的にUTCにあります。つまり、文字列が解析されるのstrtotime()は、「UTC」ではなく「America / New_York」のように解釈されていると思います。

良いニュースは、状況を大幅に簡素化できることです。日付範囲のフィールドアイテムは4つの部分で構成されます

  • 「値」は、UTCの文字列としての開始日です
  • 「start_date」は「value」を表すDrupalDateTimeオブジェクトです
  • 'end_value'は、UTCの文字列としての終了日です
  • 「end_date」は「end_value」を表すDrupalDateTimeオブジェクトです

単純な日付時刻フィールドの場合、それらは

  • 「値」はUTCの文字列としての日付です
  • 「日付」は「値」を表すDrupalDateTimeオブジェクトです

そのため、DrupalDateTime()オブジェクトを直接操作できます。さらに、そのdate.formatterサービスは、デフォルトで(ユーザーのアクティブな言語の使用に加えて)ページを表示しているユーザーが使用する適切なタイムゾーンを取り込む必要があります。

このようなことがうまくいくと思う

$node = Node::load(2100);
$start_date = $node->field_date->start_date;
$formatted = \Drupal::service('date.formatter')->format(
  $start_date->getTimestamp(), 'custom', 'Y-m-d H:i:s P'
);

注:システムに使用されているタイムゾーンを確認できるように、「P」形式のプレースホルダーを追加しました。

admin / config / regional / settingsに適切なタイムゾーンが設定されていることと、ユーザーのタイムゾーンが期待どおりであることを確認してください。また、php.iniに適切なタイムゾーンが設定されていることを確認してください(date.timezone設定です)。これが設定されていない場合、奇妙なことが起こります(そして、頭の中で、設定されていないときにインストーラーまたはステータスレポートに警告が表示されるかどうかは思い出せません。問題を覚えていますが、関与する)。


1
@mpdonadio助けてくれてありがとう!dateDrupalDateTimeにアクセスする機能については知りませんでした。好奇心からどのようにこれを理解しましたか?私のフィールドはタイプDateTimeItemであることがわかりましたが、その中には、そのクラスのパブリックメンバーdate(またはvalue)があることは明らかではないようです。
プザンノ

1
@Pzanno私はDrupal 8のコアdatetime.moduleの共同保守者であり、他の多くのコアの日付/時刻関連のものも私の方法です:)プロパティは魔法のメソッドです。を見るとDateTimeItem::propertyDefinitions()、何が公開されているかがわかります。次にDateTimeComputed::getValue()、その仕組みを確認します。すべてのItemクラスはその方法で検査できますが、計算値を使用するのはほんの一握りです。これをAPIに公開するより良い方法があればいいのにと思います。
mpdonadio

@mpdonadio説明ありがとうございます!それらがで定義されたという事実を見逃しましたDateTimeItem::propertyDefinitions()。いくつかの魔法のメソッドが発生していると思っていましたが、他のフィールドにアクセスする方法をよりよく理解できるように、これらがどのように作成されたかを理解したかったのです。あなたが言ったように、APIが公開されればいいのですが、これは役立ちます。再度、感謝します。
プザンノ

1
私の場合、の$node->field_date->date代わりにをしなければなりませんでした$node->field_date->start_date
マルコスBuarque

2
これは私がこれまでに発見した中で最も有益なDrupalドキュメントの一部であるため、この応答の小道具です。
ライアンH

6

PHP DateTimeによるタイムゾーン変換の処理に基づいて、コードを次のように変更しました。

$node = Node::load(2100);
$userTimezone = new DateTimeZone(drupal_get_user_timezone());
$gmtTimezone = new DateTimeZone('GMT');
$myDateTime = new DateTime($node->field_date->value, $gmtTimezone);
$offset = $userTimezone->getOffset($myDateTime);
$myInterval = DateInterval::createFromDateString((string)$offset . 'seconds');
$myDateTime->add($myInterval);
$result = $myDateTime->format('Y-m-d H:i:s');
dpm($result);

そして今、私の出力日は大丈夫です:

2017-02-27 19:30:01

これは動作します。しかし、Drupal APIを使用してこれを行う方法があると確信しています。


1
以前のコメントを削除しました。DrupalDateTimeは、Drupalユーザーのタイムゾーンに合わせて調整されません。
oknate

私の場合、日付関数呼び出しの前にこれを使用date_default_timezone_set(drupal_get_user_timezone());
ロジャー

これをありがとう。drupal.stackexchange.com/q/256490/2089で本当に役立ちました。
コラン

@colan喜んでお手伝いします。私の答えが役に立つと思うなら、他の答えもチェックできると思います。
エイドリアンシドアルマグエル

4

私は通常、この方法で解決します。

node = Node::load(1);    
$date_original= new DrupalDateTime( $node->field_date->value , 'UTC' );     
$result = \Drupal::service('date.formatter')->format( $date_original->getTimestamp(), 'custom', 'Y-m-d H:i:s'  );    
dpm( $result );

2

これは私のために働いた:

// Take the timestamp.
$timestamp = $form_state->getValue($form_field)->getTimestamp();
// Convert to UTC - the way its saved in database.
$date = DrupalDateTime::createFromTimestamp($timestamp, 'UTC');
// Add on the current entity.
$this->entity->{$db_field}->value = $date->format("Y-m-d\TH:i:s");

私にとっても同様に機能します `$ dDate = DrupalDateTime :: createFromTimestamp($ form_state-> getValue( 'service_date')-> getTimestamp()、 'UTC'); //このように使用します。$ dDate-> format( 'Ymd \ TH:i:s'); `
Yogesh Kushwaha

1

このコードは私のために働いています。

// set use timezone
userTimezone = new DateTimeZone(drupal_get_user_timezone());
// set gmt timezone
$gmtTimezone = new DateTimeZone('GMT');
// Take the timestamp.
$start_date = $val['field_start_time_value'];    
$startDateTime = new DateTime($start_date, $gmtTimezone);
$offset = $userTimezone->getOffset($startDateTime);
$startInterval = DateInterval::createFromDateString((string)$offset . 'seconds');
$startDateTime->add($startInterval);
$result = $startDateTime->format('Y-m-d H:i:s');

0

これらの他の答えはどれも私にとってはうまくいきませんでした。これは私が最終的に終わったものです:

$range_start = DrupalDatetime::createFromTimestamp((int)$start_date); // unix timestamp
$range_start->setTimezone(new \Datetimezone('EST'));
$node->field_date_range->value = format_date(
  $range_start->getTimestamp() , 'custom', 'Y-m-d\TH:i:s', 'EST');

0

私はこのスニペットを使用して日付を操作します:

<?php
class MyApp extends ControllerBase
{
    public function output() 
    {
        $dtime = DateTime::createFromFormat("d/m/Y - H:I:s", "22/12/1999 - 22:55:12", $this->getDateTimeZone());
        $time = $dtime->format('r');
        // My code goes here
    }

    private function getDateTimeZone()
    {
        return new DateTimeZone(drupal_get_user_timezone());
    }
}

ここで、Datetimeオブジェクトに関する詳細情報を取得できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.