Drupal - How to show a date in the correct timezone?
I suspect the problem has to do with some of the nuances of strtotime()
.
strtotime()
can take just about any string, and convert it into a Unix timestamp. The problem is that when the string doesn't contain an explicit timezone, it will use what is set by date_default_timezone_get()
. That should be set from the current user, though (it is set by the account proxy). However, the string that you are pulling out of $node->field_date->value
is implicitly in UTC. In other words, I think the string is being parsed by strtotime()
is being interpreted as in 'America/New_York' and not 'UTC'.
The good news is that you can simplify your situation a lot. The field item for a date range consists of four parts
- 'value' is the start date as a string in UTC
- 'start_date' is a DrupalDateTime object representing 'value'
- 'end_value' is the end date as a string in UTC
- 'end_date' is a DrupalDateTime object representing 'end_value'
For a plain date time field they are
- 'value' is the date as a string in UTC
- 'date' is a DrupalDateTime object representing 'value'
So, you can work with the DrupalDateTime()
object directly. In addition, that date.formatter
service should pull in the proper timezone in use by the user viewing the page by default (in addition to using the user's active language).
I suspect something like this will work
$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'
);
Note I added the 'P' format placeholder in there so you can see what what timezone the system thinks is in use.
Make sure you have the proper timezone set up on admin/config/regional/settings, and that your user timezone is what you are expecting. Also ensure that you have the proper timezone set in your php.ini (it's the date.timezone
setting); weird things happen when this isn't set (And off the top of my head, I don't recall if that causes a warning in the installer or on the status report when not set. I remember the issue, but not whether it got committed).
Based in Handling timezone conversion with PHP DateTime I modified my code to this:
$node = Node::load(2100);
$userTimezone = new DateTimeZone(date_default_timezone_get());
$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);
And now my output date it's fine:
2017-02-27 19:30:01
This works. But I'm sure that there is a way to do this using the Drupal API.
I usually solve it this way.:
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 );