Wie kann ich ein Datum in der richtigen Zeitzone anzeigen?

18

Ich habe ein Datetime Range-Feld (field_date) in einem Inhaltstyp. Sobald ich meinen Inhaltstyp erstellt habe, lege ich das Startdatum wie folgt fest:

2017-02-27 19:30:01

Bildbeschreibung hier eingeben

Jetzt möchte ich den Wert abrufen und das Datum in einem anderen Format anzeigen. Versuchen Sie also, den folgenden Code zu verwenden:

// 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);

Das ist meine Ausgabe:

// 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

Wie kann man ein Datum in der richtigen Zeitzone anzeigen?

Adrian Cid Almaguer
quelle

Antworten:

20

Ich vermute, das Problem hat mit einigen Nuancen von zu tun strtotime().

strtotime()kann fast jede beliebige Zeichenfolge aufnehmen und in einen Unix-Zeitstempel konvertieren. Das Problem ist, dass die Zeichenfolge, wenn sie keine explizite Zeitzone enthält, das verwendet, was von festgelegt wird date_default_timezone_get(). Dies sollte jedoch vom aktuellen Benutzer festgelegt werden (dies wird vom Konto-Proxy festgelegt). Die Zeichenfolge, aus der Sie ziehen, $node->field_date->valueist jedoch implizit in UTC. Mit anderen Worten, ich denke, die Zeichenfolge, die analysiert strtotime()wird, wird wie in 'America / New_York' und nicht wie in 'UTC' interpretiert.

Die gute Nachricht ist, dass Sie Ihre Situation erheblich vereinfachen können. Das Feldelement für einen Datumsbereich besteht aus vier Teilen

  • 'Wert' ist das Startdatum als Zeichenfolge in UTC
  • 'start_date' ist ein DrupalDateTime-Objekt, das 'value' darstellt
  • 'end_value' ist das Enddatum als Zeichenfolge in UTC
  • 'end_date' ist ein DrupalDateTime-Objekt, das 'end_value' darstellt

Für ein einfaches Datums- / Zeitfeld sind sie

  • 'Wert' ist das Datum als Zeichenfolge in UTC
  • 'date' ist ein DrupalDateTime-Objekt, das 'value' darstellt

Sie können also DrupalDateTime()direkt mit dem Objekt arbeiten. Darüber hinaus sollte dieser date.formatterDienst die richtige Zeitzone verwenden, die vom Benutzer verwendet wird, der die Seite standardmäßig anzeigt (zusätzlich zur aktiven Sprache des Benutzers).

Ich vermute, dass so etwas funktionieren wird

$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'
);

Hinweis: Ich habe dort den Platzhalter im P-Format hinzugefügt, damit Sie sehen können, welche Zeitzone vom System verwendet wird.

Stellen Sie sicher, dass Sie in admin / config / regional / settings die richtige Zeitzone eingerichtet haben und dass Ihre Benutzerzeitzone Ihren Erwartungen entspricht. Stellen Sie außerdem sicher, dass in Ihrer php.ini die richtige Zeitzone eingestellt ist (dies ist die date.timezoneEinstellung). komische Dinge passieren, wenn dies nicht eingestellt ist (und ich kann mich nicht erinnern, ob dies eine Warnung im Installationsprogramm oder im Statusbericht verursacht, wenn es nicht eingestellt ist. Ich erinnere mich an das Problem, aber nicht, ob es aufgetreten ist engagiert sein).

mpdonadio
quelle
1
@mpdonadio Danke für die Hilfe! Ich wusste nichts über die dateFunktion zum Zugriff auf DrupalDateTime. Wie haben Sie das aus Neugier herausgefunden? Ich konnte herausfinden, dass mein Feld vom Typ war, DateTimeItemaber es scheint nicht offensichtlich, dass es ein date(oder ein value) öffentliches Mitglied für diese Klasse gibt.
Pzanno
1
@Pzanno Ich bin der Mitbetreuer des Drupal 8-Kerns datetime.module, und auch viele andere wichtige datums- und zeitbezogene Dinge kommen mir in den Sinn :) Die Eigenschaften sind magische Methoden. Wenn Sie schauen DateTimeItem::propertyDefinitions(), werden Sie sehen, was ausgesetzt ist. Dann schauen Sie sich an DateTimeComputed::getValue(), wie das funktioniert. Auf diese Weise können alle Objektklassen untersucht werden, aber nur wenige verwenden berechnete Werte. Ich wünschte, es gäbe eine bessere Möglichkeit, dies der API zugänglich zu machen.
mpdonadio
@mpdonadio danke für die Erklärung! Ich vermisste die Tatsache, dass sie sogar in definiert wurden DateTimeItem::propertyDefinitions(). Ich nahm an, dass es einige magische Methoden gibt, wollte aber verstehen, wie diese erstellt wurden, damit ich besser verstehen konnte, wie ich auch auf andere Felder zugreifen kann. Wie Sie sagten, wäre es schön, wenn die API verfügbar gemacht würde, aber das hilft. Danke noch einmal.
Pzanno
1
In meinem Fall musste ich $node->field_date->datestatt $node->field_date->start_date.
Marcos Buarque
2
Dies ist die informativste Drupal-Dokumentation, die ich je gefunden habe.
Ryan H
6

Basierend auf der Behandlung der Zeitzonen-Konvertierung mit PHP DateTime habe ich meinen Code folgendermaßen geändert:

$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);

Und jetzt ist mein Ausgabedatum in Ordnung:

2017-02-27 19:30:01

Das funktioniert. Aber ich bin mir sicher, dass es eine Möglichkeit gibt, dies mit der Drupal-API zu tun.

Adrian Cid Almaguer
quelle
1
Ich habe meinen vorherigen Kommentar entfernt. DrupalDateTime passt sich nicht der Zeitzone des Drupal-Benutzers an.
OKNATE
In meinem Fall habe ich dies nur vor einem date_default_timezone_set(drupal_get_user_timezone());
Roger
Danke dafür. Es hat mir bei drupal.stackexchange.com/q/256490/2089 sehr geholfen .
Colan
@colan eine Freude, wenn Sie denken, dass meine Antwort nützlich ist, denke ich, dass Sie die andere Antwort auch überprüfen können.
Adrian Cid Almaguer
4

Ich löse es normalerweise so:

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 );
Ytacol
quelle
2

Das hat bei mir funktioniert:

// 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");
Dan Poenaru
quelle
Es funktioniert auch bei mir: $ dDate = DrupalDateTime :: createFromTimestamp ($ form_state-> getValue ('service_date') -> getTimestamp (), 'UTC') // So verwenden. $ dDate-> format ('Ymd \ TH: i: s'); `
Yogesh Kushwaha
1

Dieser Code funktioniert für mich.

// 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');
Arun Mishra
quelle
0

Keine dieser anderen Antworten hat für mich funktioniert. Dies ist, womit ich letztendlich fertig wurde:

$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');
user1359
quelle
0

Ich benutze dieses Snippet, um mit Daten zu arbeiten:

<?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());
    }
}

Weitere Informationen zum Datetime-Objekt erhalten Sie hier

Ben Cassinat
quelle