PHP - strtotime, укажите часовой пояс - PullRequest
50 голосов
/ 25 августа 2010

У меня есть строка даты, скажем '2008-09-11'. Я хочу получить временную метку из этого, но мне нужно динамически указывать часовой пояс (а не PHP по умолчанию).

Подводя итог, у меня есть две строки:

$dateStr = '2008-09-11';
$timezone = 'Americas/New_York';

Как получить метку времени для этого?

РЕДАКТИРОВАТЬ: время дня будет полуночи этого дня .... $ dateStr = '2008-09-11 00:00:00';

Ответы [ 6 ]

71 голосов
/ 25 августа 2010
$date = new DateTime($dateStr, new DateTimeZone($timezone));

$timestamp = $date->format('U');

23 голосов
/ 31 июля 2013

Принятый ответ - отличный вариант, если вы используете PHP> 5.2 (я думаю, это версия, в которую они добавили класс DateTime). Если вы хотите поддерживать более старую версию, вы не хотите вводить слишком много текста, или если вы просто предпочитаете функциональный подход, есть другой способ, который также не изменяет глобальные настройки:

$dateStr = '2008-09-11 00:00:00';
$timezone = 'America/New_York';
$dtUtcDate = strtotime($dateStr. ' '. $timezone);
16 голосов
/ 25 августа 2010

Это будет работать, если по какой-то причине вы используете <5.2 (Небесный запрет). </p>

$reset = date_default_timezone_get();
date_default_timezone_set('America/New_York');
$stamp = strtotime($dateStr);
date_default_timezone_set($reset);

Но что-то 5.2 и выше, я настоятельно рекомендую вам выбрать ответ @ salathe.*

4 голосов
/ 14 января 2015

Если вы собираетесь использовать часовые пояса, я предлагаю вам использовать класс DateTime, и в этом случае функцию DateTime :: createFromFormat (), которая позволит вам делать что-то вроде этого:

$start = "2015-01-14 11:59:43";
$timezone = "America/Montreal";

$tz = new DateTimeZone($timezone);
$dt = DateTime::createFromFormat('Y-m-d H:i:s', $start, $tz);

Когда вы помещаете $ tz в функцию DateTime :: createFromFormat, вы сообщаете ему, в каком часовом поясе находится указанная вами дата, поэтому, когда вам нужно преобразовать ее в другой часовой пояс, все, что вам нужно сделать, это примерно так :

$start = $dt->setTimeZone(new DateTimeZone('UTC'));
2 голосов
/ 28 июня 2016

Всякий раз, когда вы говорите о точном моменте времени, сохраняйте время в соответствии с единым стандартом, который не зависит от перехода на летнее время. (GMT и UTC эквивалентны в этом отношении, но предпочтительнее использовать термин UTC. Обратите внимание, что UTC также называется Zulu или Z time.)

Если вместо этого вы выберете сохранение времени с использованием значения местного времени, включите смещение по местному времени от UTC, чтобы метка времени впоследствии могла быть однозначно интерпретирована.

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

При сохранении меток времени в виде числового значения используйте время Unix - это количество целых секунд с 1970-01-01T00: 00: 00Z (исключая високосные секунды). Если вам требуется более высокая точность, используйте вместо этого миллисекунды. Это значение всегда должно основываться на UTC, без каких-либо настроек часового пояса.

Если вам позже потребуется изменить метку времени, включите исходный идентификатор часового пояса, чтобы вы могли определить, могло ли смещение измениться по сравнению с записанным исходным значением.

При планировании будущих событий обычно предпочтительнее местное время, а не UTC, поскольку смещение обычно меняется. Смотрите ответ и сообщение в блоге.

Помните, что смещения часовых поясов не всегда являются целым числом часов (например, индийское стандартное время - UTC + 05: 30, а Непал использует UTC + 05: 45).

Если используется Java, используйте java.time для Java 8 или Joda Time для Java 7 или ниже. Если вы используете .NET, рассмотрите возможность использования Noda Time. Если вы используете .NET без Noda Time, учтите, что DateTimeOffset часто является лучшим выбором, чем DateTime. Если вы используете Perl, используйте DateTime. Если вы используете Python, используйте pytz или dateutil. Если вы используете JavaScript, используйте moment.js с расширением moment-timezone. Если используется PHP> 5.2, используйте собственные преобразования часовых поясов, предоставляемые классами DateTime и DateTimeZone. Будьте осторожны при использовании.

DateTimeZone :: listAbbreviations () - см. Ответ. Чтобы поддерживать PHP в актуальном состоянии, данные Olson следует периодически устанавливать PECL-пакет timezonedb; см. ответ.

Если вы используете C ++, обязательно используйте библиотеку, которая правильно использует базу данных часовых поясов IANA. К ним относятся cctz, ICU и библиотека tz Говарда Хиннанта.

Не используйте Boost для преобразования часовых поясов. Хотя его API утверждает, что поддерживает стандартные идентификаторы IANA (он же «zoneinfo»), он грубо сопоставляет их с фиксированными смещениями без учета богатой истории изменений, которые могла иметь каждая зона.

(Также файл вышел из строя.)

В большинстве бизнес-правил используется гражданское время, а не UTC или GMT. Поэтому планируйте преобразовывать временные метки UTC в местный часовой пояс перед применением логики приложения.

Помните, что часовые пояса и смещения не являются фиксированными и могут изменяться. Например, исторически США и Великобритания использовали одни и те же даты, чтобы «прыгнуть вперед» и «отступить».

Тем не менее, в 2007 году США изменили даты, на которые меняются часы. Теперь это означает, что в течение 48 недель в году разница между лондонским и нью-йоркским временем составляет 5 часов, а в течение 4 недель (3 весной, 1 осенью) - 4 часа. Обращайте внимание на подобные элементы в любых расчетах, которые включают несколько зон.

Рассмотрите тип времени (фактическое время события, время вещания, относительное время, историческое время, повторяющееся время), какие элементы (временная метка, смещение часового пояса и имя часового пояса) вам нужно сохранить для правильного поиска - см. «Типы Время "в ответе.

Синхронизируйте файлы tzdata вашей ОС, базы данных и приложений между собой и остальным миром.

На серверах установите аппаратные часы и часы ОС на UTC, а не на местный часовой пояс.

Независимо от предыдущего пункта, серверный код, включая веб-сайты, никогда не должен ожидать, что локальный часовой пояс сервера будет чем-то конкретным.см. ответ.

Использование служб NTP на всех серверах.

При использовании FAT32 помните, что временные метки хранятся по местному времени, а не по UTC.

При работе с повторяющимися событиями (например, еженедельным телешоу) помните, что время меняется с переходом на летнее время и будет различаться по часовым поясам.

Всегда запрашивать значения даты и времени как включающие нижнюю границу, верхнюю границуисключительный (> =, <). </p>

0 голосов
/ 21 ноября 2018

Лаконичный ответ (нет необходимости изменять часовой пояс по умолчанию)

$dateStr = '2008-09-11';
$timezone = 'America/New_York';
$time = strtotime(
    $dateStr, 
    // convert timezone to offset seconds
    (new \DateTimeZone($timezone))->getOffset(new \DateTime) - (new \DateTimeZone(date_default_timezone_get()))->getOffset(new \DateTime) . ' seconds'
);

Loquacious Answer

Использовать второй параметр strtotimeкоторый меняет систему координат функции.Кстати, я предпочитаю не обновлять часовой пояс скрипта по умолчанию:

http://php.net/manual/en/function.strtotime.php

int strtotime (строка $ time [, int $now = time ()])

Функция ожидает получения строки, содержащей формат даты на английском языке, и попытается проанализировать этот формат в метку времени Unix (количество секунд с января1 1970 00:00:00 UTC), относительно отметки времени , заданной сейчас, или текущего времени, если сейчас не указано.

и помощник

/**
 * Returns the timestamp of the provided time string using a specific timezone as the reference
 * 
 * @param string $str
 * @param string $timezone
 * @return int number of the seconds
 */
function strtotimetz($str, $timezone)
{
    return strtotime(
        $str, strtotime(
            // convert timezone to offset seconds
            (new \DateTimeZone($timezone))->getOffset(new \DateTime) - (new \DateTimeZone(date_default_timezone_get()))->getOffset(new \DateTime) . ' seconds'
        )
    );
}

var_export(
    date(
        'Y-m-d', 
        strtotimetz('this monday', 'America/New_York')
    )
);

Возможно, не самый эффективный подход, но он хорошо работает, когда вы знаете часовой пояс по умолчанию и смещение.Например, если часовой пояс по умолчанию - UTC, а смещение - -8 часов:

var_dump(
    date(
        'Y-m-d', 
        strtotime('this tuesday', strtotime(-8 . ' hours'))
    )
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...