2016-09-28 1 views
5

У меня возникли трудности с использованием PHP DateTime для преобразования даты, полученной с часовым поясом GMT -8 (PST), в человекообразный формат с часовой пояс GMT -7 (PDT).Использование PHP DateTime для анализа и преобразования временной зоны PST в PDT (GMT -8 - GMT -7)

Вот пример:

$tz = new DateTimeZone('America/Los_Angeles'); 
$saleEndDate = new DateTime("2016-11-07T17:30:00-08:00"); 
$saleEndDate->setTimezone($tz); 
echo $saleEndDate->format('Y-m-d H:i:s'); 

Выход выше код: 2016-11-07 17:30:00. Тем не менее, он должен отображать 2016-11-07 18:30:00, потому что America/Los_Angeles теперь находится в летнем режиме (GMT -7, PDT).

Из того, что я прочитал в DateTime docs, команда new DateTime должна иметь возможность интерпретировать, что строка 2016-11-07T17:30:00-08:00 имеет GMT -8 часовой пояс:

В часовой пояс параметр и текущий часовой пояс, игнорируются когда параметр либо содержит временную метку UNIX (например, 946684800), либо указывает часовой пояс (например, 2010-01-28T15: 00: 00 + 02: 00).

Несмотря на это, я не думаю, что DateTime правильно признает GMT -8.

Кто-нибудь знает, какой подход необходим для правильной конвертации между часовыми поясами?

Update:

Я также попытался переходящая в DateTimeZone в качестве второго параметра в DateTime конструктора, но также безрезультатно:

$tz = new DateTimeZone('America/Los_Angeles'); 
$saleEndDate = new DateTime("2016-11-07T17:30:00-08:00", new DateTimeZone("America/Los_Angeles")); 
$saleEndDate->setTimezone($tz); 
echo $saleEndDate->format('Y-m-d H:i:s'); 

Также не работает:

$tz = new DateTimeZone('America/Los_Angeles'); 
$saleEndDate = new DateTime("2016-11-07T17:30:00", new DateTimeZone("PST")); 
$saleEndDate->setTimezone($tz); 
echo $saleEndDate->format('Y-m-d H:i:s'); 

Также не работает:

$tz = new DateTimeZone("PDT"); 
$saleEndDate = new DateTime("2016-11-07T17:30:00", new DateTimeZone("PST")); 
$saleEndDate->setTimezone($tz); 
echo $saleEndDate->format('Y-m-d H:i:s'); 
+0

Я не спустил вниз, не одобрил ... но, может быть, я не понимаю здесь что-то ... почему вы думаете, что он должен преобразовать в 18:30 только потому, что сейчас это летнее время? -8 - это в основном Лос-Анджелес, поэтому, возможно, здесь нечего конвертировать. –

+1

http://stackoverflow.com/questions/17694894/different-timezone-types-on-datetime-object «Только объекты DateTime с прикрепленными временными часами типа 3 позволят правильно выполнять DST». Ваш '$ saleEndDate' создается как тип 1. – ceejayoz

+0

@PawelDubiel он должен преобразовать, потому что время предоставлено' -8', но набор часовых поясов '-7' – zerkms

ответ

2

Не самый большой, но это единственный способ, которым я могу думать, чтобы сделать это

$tz = new DateTimeZone('America/Los_Angeles'); 
$saleEndDate = new DateTime("2016-11-07T17:30:00-08:00"); 
$saleEndDate->setTimezone($tz); 
$stamp = $saleEndDate->format('U'); 
$zone = $tz->getTransitions($stamp, $stamp); 
if(!$zone[0]['isdst']) $saleEndDate->modify('+1 hour'); 
echo $saleEndDate->format('Y-m-d H:i:s'); 

Что я делаю здесь, используя DateTimeZone::getTransitions function, чтобы определить, является ли дата Предоставленный DST или нет. Если это не так, добавим один час. Обратите внимание, что это не меняет часовой пояс, он просто корректирует DST сдвиг

You can see it in action here

1

DateTime функционирует как положено. Если вы не находитесь в районе, где наблюдался различный DST, в большую область, America/Los_Angeles покинул DST (PDT-> PST) 6 ноября (в 2016 году).

https://www.timeanddate.com/news/time/usa-canada-end-dst-2016.html

Из timezeonedb вы можете просмотреть даты, которые он использует при поиске массив для конкретной даты/времени (который сделал Machavity) и получил тот факт, что это не в DST, а затем пошел на измените его вручную. Это не ответ, поскольку он в конечном итоге завершится неудачей, если вы вручную не добавите время отсечки для ручной коррекции для остановки.

Осматривая переходные даты вокруг даты показывает:

date_default_timezone_set('America/Los_Angeles'); 
$theDate = new DateTime("2016-11-07T17:30:00",new DateTimeZone("America/Los_Angeles")); 
$theDateBefore = new DateTime("2016-03-01"); 
$theDateAfter = new DateTime("2017-03-15"); 
echo "<pre>"; 
print_r($theDate->getTimezone()->getTransitions(
    $theDateBefore->getTimestamp(),$theDateAfter->getTimestamp())); 
echo "</pre>"; 

в результате массив 4:

Array 
(
    [0] => Array 
     (
      [ts] => 1456819200 
      [time] => 2016-03-01T08:00:00+0000 
      [offset] => -28800 
      [isdst] => 
      [abbr] => PST 
     ) 

    [1] => Array 
     (
      [ts] => 1457863200 
      [time] => 2016-03-13T10:00:00+0000 
      [offset] => -25200 
      [isdst] => 1 
      [abbr] => PDT 
     ) 

    [2] => Array 
     (
      [ts] => 1478422800 
      [time] => 2016-11-06T09:00:00+0000 
      [offset] => -28800 
      [isdst] => 
      [abbr] => PST 
     ) 

    [3] => Array 
     (
      [ts] => 1489312800 
      [time] => 2017-03-12T10:00:00+0000 
      [offset] => -25200 
      [isdst] => 1 
      [abbr] => PDT 
     ) 

) 

Array [0] является временная зона действует как у theDateBefore, и вы можете увидеть изменения даты действуют для вашего времени.

Ваша дата продажи падает после изменения с PDT на PST.

Чтобы вернуть код, скорректированная дата/время, необходимо будет вручную изменить его. Выполнение этого способа, которое было принято, приведет к ложным результатам. Как я уже упоминал, вам нужно будет окружить это тем, что вы хотите, чтобы пользовательский часовой пояс был задействован.