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?

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).


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.


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

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

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

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

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.