Як показати дату в правильному часовому поясі?


19

У мене є тип діапазону дат (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

Отже, як показати дату в правильному часовому поясі?

Відповіді:


22

Я підозрюю, що проблема пов'язана з деякими нюансами strtotime().

strtotime()може приймати майже будь-який рядок і перетворювати його в часову позначку Unix. Проблема полягає в тому, що коли рядок не містить явного часового поясу, він буде використовувати те, що встановлено date_default_timezone_get(). Це має бути встановлено у поточного користувача (він встановлюється проксі-сервером облікового запису). Однак рядок, з якої ви витягуєтесь, $node->field_date->valueнеявно в UTC. Іншими словами, я думаю, що розбирається рядок strtotime()трактується як "America / New_York", а не "UTC".

Хороша новина полягає в тому, що ви можете значно спростити ситуацію. Елемент поля для діапазону дат складається з чотирьох частин

  • 'value' - дата початку як рядок у UTC
  • 'start_date' - об’єкт DrupalDateTime, що представляє "значення"
  • 'end_value' - дата закінчення як рядок у UTC
  • 'end_date' - об’єкт DrupalDateTime, що представляє 'end_value'

Для звичайного поля часу вони є

  • 'value' - дата у вигляді рядка в UTC
  • 'date' - об’єкт DrupalDateTime, що представляє 'value'

Отже, ви можете працювати з 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", щоб ви могли побачити, який часовий пояс використовується для системи.

Переконайтеся, що у адміністраторі / конфігурації / регіональному / налаштуваннях встановлено належний часовий пояс, і що ваш часовий пояс користувача - це те, чого ви очікуєте. Також переконайтеся, що у вашому php.ini встановлено належний часовий пояс (це date.timezoneналаштування); дивні речі трапляються, коли це не встановлено (І вгорі голови, я не пам'ятаю, чи це викликає попередження в інсталяторі чи у звіті про стан, коли не встановлено. Я пам’ятаю проблему, але чи не отримала вона вчинено).


1
@mpdonadio Дякую за допомогу! Я не знав про dateфункцію доступу до DrupalDateTime. З цікавості, як ви це зрозуміли? Я зміг зрозуміти, що моє поле такого типу, DateTimeItemале всередині цього не здається очевидним, що для цього класу є date(або value) громадський член.
Пзанно

1
@Pzanno Я є співавтором Drupal 8 core datetime.module, а також багато інших речей, пов’язаних з датою / часом, з'являються на моєму шляху :) Властивості - це магічні методи. Якщо ви подивитесь DateTimeItem::propertyDefinitions(), ви побачите, що піддається. Потім подивіться, DateTimeComputed::getValue()як це працює. Усі класи елемента можуть бути вивчені таким чином, але лише кілька користувачів використовують обчислені значення. Я хотів би, щоб був кращий спосіб викрити це в API.
mpdonadio

@mpdonadio дякую за пояснення! Я пропустив той факт, що вони навіть були визначені в DateTimeItem::propertyDefinitions(). Я подумав, що відбуваються якісь магічні методи, але хотів зрозуміти, як вони створені, щоб я міг краще зрозуміти, як отримати доступ до інших полів. Як ви сказали, було б добре, якби API було викрито, але це допомагає. Знову дякую.
Пзанно

1
У моєму випадку мені довелося це зробити $node->field_date->dateзамість цього $node->field_date->start_date.
Маркос Буарке

2
Підкріплення цієї відповіді, оскільки це найінформативніша частина документації щодо Drupal, яку я коли-небудь знайшов.
Ryan 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

Це працює. Але я впевнений, що є спосіб зробити це за допомогою API Drupal.


1
Я видалив попередній коментар. DrupalDateTime не налаштовується на часовий пояс користувача Drupal.
окнат

У моєму випадку я просто використовував це перед будь-яким викликом функції дати: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-> формат ('Ymd \ TH: i: s'); `
Йогеш Кушваха

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 тут

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.