Jak wyświetlić datę we właściwej strefie czasowej?

19

Mam pole Zakres czasu i godziny (data_pola) w typie treści. Po utworzeniu typu zawartości ustawiam datę rozpoczęcia na:

27.02.2017, 19:30:01

wprowadź opis zdjęcia tutaj

Teraz chcę uzyskać wartość i wyświetlić datę w innym formacie, więc spróbuj użyć następującego kodu:

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

To jest mój wynik:

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

Jak wyświetlić datę we właściwej strefie czasowej?

Adrian Cid Almaguer
źródło

Odpowiedzi:

22

Podejrzewam, że problem dotyczy niektórych niuansów strtotime().

strtotime()może pobrać dowolny ciąg znaków i przekonwertować go na uniksowy znacznik czasu. Problem polega na tym, że gdy ciąg nie zawiera wyraźnej strefy czasowej, użyje tego, co jest ustawione date_default_timezone_get(). Powinno to być ustawione od bieżącego użytkownika (ustawia to proxy konta). Ciąg, z którego się wyciągasz, $node->field_date->valuejest jednak domyślnie w UTC. Innymi słowy, myślę, że ciąg jest analizowany przez strtotime()jest interpretowany jak w „America / New_York”, a nie „UTC”.

Dobra wiadomość jest taka, że ​​możesz bardzo uprościć swoją sytuację. Element pola dla zakresu dat składa się z czterech części

  • „wartość” to data początkowa jako ciąg znaków w UTC
  • „data_początkowa” to obiekt DrupalDateTime reprezentujący „wartość”
  • „wartość_końcowa” to data końcowa jako ciąg znaków w UTC
  • „data_końcowa” to obiekt DrupalDateTime reprezentujący „wartość_końcową”

Są to zwykłe pola daty i godziny

  • „wartość” to data w postaci ciągu w UTC
  • „data” to obiekt DrupalDateTime reprezentujący „wartość”

Możesz więc pracować z DrupalDateTime()obiektem bezpośrednio. Ponadto date.formatterusługa ta powinna pobrać odpowiednią strefę czasową używaną przez użytkownika domyślnie przeglądającego stronę (oprócz korzystania z aktywnego języka użytkownika).

Podejrzewam, że coś takiego zadziała

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

Uwaga Dodałem tam symbol zastępczy formatu „P”, abyś mógł zobaczyć, jaka strefa czasowa jest używana przez system.

Upewnij się, że masz skonfigurowaną odpowiednią strefę czasową w admin / config / regional / settings i że twoja strefa czasowa użytkownika jest tym, czego oczekujesz. Upewnij się także, że masz właściwą strefę czasową w pliku php.ini (jest to date.timezoneustawienie); dziwne rzeczy zdarzają się, gdy nie jest to ustawione (I z góry mojej głowy, nie pamiętam, czy to powoduje ostrzeżenie w instalatorze lub w raporcie stanu, gdy nie jest ustawione. Pamiętam problem, ale nie wiem, czy zobowiązany).

mpdonadio
źródło
1
@mpdonadio Dzięki za pomoc! Nie wiedziałem o datefunkcji dostępu do DrupalDateTime. Z ciekawości, jak to wymyśliłeś? Byłem w stanie dowiedzieć się, że moje pole było tego typu, DateTimeItemale nie wydaje się oczywiste, że istnieje date(lub value) członek publiczny dla tej klasy.
Pzanno 28.04.17
1
@Pzanno Jestem współzałożycielem podstawowego narzędzia datetime.module Drupal 8, a także wiele innych rzeczy związanych z datą / czasem przychodzi mi po drodze :) Właściwości to magiczne metody. Jeśli spojrzysz DateTimeItem::propertyDefinitions(), zobaczysz, co jest naświetlone. Następnie DateTimeComputed::getValue()sprawdź, jak to działa. Wszystkie klasy przedmiotów mogą być badane w ten sposób, ale tylko garstka użytych wartości obliczeniowych. Chciałbym, aby istniał lepszy sposób na udostępnienie tego interfejsu API.
mpdonadio
@mpdonadio dzięki za wyjaśnienie! Tęskniłem za faktem, że zostali nawet zdefiniowani DateTimeItem::propertyDefinitions(). Uznałem, że zdarzają się magiczne metody, ale chciałem zrozumieć, w jaki sposób zostały one stworzone, abym mógł lepiej zrozumieć, jak uzyskać dostęp do innych pól. Tak jak powiedziałeś, byłoby miło, gdyby API został ujawniony, ale to pomaga. Dzięki jeszcze raz.
Pzanno 28.04.17
1
W moim przypadku musiałem to zrobić $node->field_date->datezamiast $node->field_date->start_date.
Marcos Buarque
2
Wspiera tę odpowiedź, ponieważ jest to najbardziej pouczająca część dokumentacji Drupala, jaką kiedykolwiek znalazłem.
Ryan H
6

W oparciu o obsługę konwersji strefy czasowej za pomocą PHP DateTime zmodyfikowałem kod do tego:

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

A teraz moja data wyjścia jest w porządku:

2017-02-27 19:30:01

To działa. Ale jestem pewien, że można to zrobić za pomocą interfejsu API Drupal.

Adrian Cid Almaguer
źródło
1
Usunąłem mój poprzedni komentarz. DrupalDateTime nie dostosowuje się do strefy czasowej użytkownika Drupal.
oknate
W moim przypadku użyłem tego przed wywołaniem funkcji daty:date_default_timezone_set(drupal_get_user_timezone());
Roger,
Dzięki za to. To naprawdę pomogło mi z drupal.stackexchange.com/q/256490/2089 .
colan
@colan przyjemność mi pomóc, jeśli uważasz, że moja odpowiedź jest przydatna, myślę, że możesz sprawdzić również drugą odpowiedź.
Adrian Cid Almaguer
4

Zwykle rozwiązuję to w ten sposób:

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
źródło
2

To działało dla mnie:

// 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
źródło
Działa również dla mnie `$ dDate = DrupalDateTime :: createFromTimestamp ($ form_state-> getValue ('service_date') -> getTimestamp (), 'UTC'); // Użyj w ten sposób. $ dDate-> format ('Ymd \ TH: i: s'); `
Yogesh Kushwaha
1

Ten kod działa dla mnie.

// 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
źródło
0

Żadna z tych innych odpowiedzi nie działała dla mnie. Z tym ostatecznie skończyłem:

$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');
użytkownik1359
źródło
0

Używam tego fragmentu do pracy z datami:

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

Możesz uzyskać więcej informacji o obiekcie Datetime tutaj

Ben Cassinat
źródło