PHP - strtotime,指定时区

Posted

技术标签:

【中文标题】PHP - strtotime,指定时区【英文标题】:PHP - strtotime, specify timezone 【发布时间】:2011-04-03 21:32:59 【问题描述】:

我有一个日期字符串,比如“2008-09-11”。我想从中得到一个时间戳,但我需要动态指定一个时区(而不是 php 默认)。

回顾一下,我有两个字符串:

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

我如何获得这个时间戳?

编辑:一天中的时间将是当天的午夜.... $dateStr = '2008-09-11 00:00:00';

【问题讨论】:

在没有指定时间的情况下为什么要考虑时区? 很抱歉给您带来了困惑。这将是当天的午夜(指定日期的开始)。 如果您将午夜作为默认时间,这很重要... php.net/manual/en/function.date-default-timezone-set.php 您的时区无效,应该是America/New_York 【参考方案1】:
$date = new DateTime($dateStr, new DateTimeZone($timezone));

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

【讨论】:

我不需要指定要转换的时区吗?还是只是从 PHP 默认转换而来? @whydna 你没有转换任何东西(除非我误读了)。该代码在指定时区创建该日期的表示。 @whydna 不,你没有转换。您正在解释日期字符串,就好像引用了指定的时区一样。为您转换新的$d = new DateTime($dateStr, $timezonefrom); $d->setTimezone($timezoneto); @whydna 是的,当然会有所不同。但时间并不存在于真空中。它有一个关联的时区。如果您要在创建 DateTime 对象时对实际时区撒谎,那就是您的问题。但这不是正确的时区转换。转换需要从一个时区到另一个时区。在这种情况下,你会从哪里转换? Artefacto,你是对的。只是花了我一点时间来解决它。谢谢!【参考方案2】:

如果您运行的是 PHP > 5.2(我认为这是他们添加 DateTime 类的版本),则接受的答案非常好。如果您想支持旧版本,您不想输入太多,或者如果您只是喜欢函数式方法,还有另一种方式也不会修改全局设置:

$dateStr = '2008-09-11 00:00:00';
$timezone = 'America/New_York';
$dtUtcDate = strtotime($dateStr. ' '. $timezone);

【讨论】:

我看不到接受的答案如何修改全局设置。 它没有。它确实使用类并且需要 PHP > 5.2。修改全局设置的是 Jonahs 的回答。 如果您将时间添加到 $dateStr。输出会出错。【参考方案3】:

如果您出于某种原因使用

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

但任何 5.2 及以上版本,我强烈建议您选择@salathe 的答案。

【讨论】:

有效,但别忘了改回来!我认为 salathes 解决方案更好 “改回来”是什么意思?是的,1 行对 4 行。嗯。 :D 如果整个应用程序需要在该进程的特定时区运行,这个解决方案(这不是 OP 想要的,这就是我发表评论的原因)非常棒 - 只是不近优雅的一次性需求。 旁注: 在 5.5 及更高版本中,strtotime() 将始终为UTC 提供seconds since epoch。因此,请按照此答案中的建议使用 DateTime【参考方案4】:

如果您要使用时区,我建议您使用 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'));

【讨论】:

【参考方案5】:

当您指的是一个确切的时间点时,请根据不受夏令时影响的统一标准来坚持时间。 (GMT 和 UTC 在这方面是等价的,但最好使用 UTC 一词。请注意,UTC 也称为 Zulu 或 Z 时间。)

如果您选择使用本地时间值保留时间,请包含与 UTC 的本地时间偏移量,以便稍后可以明确地解释时间戳。

在某些情况下,您可能需要同时存储 UTC 时间和等效的本地时间。这通常使用两个单独的字段来完成,但有些平台支持可以将两者都存储在单个字段中的 datetimeoffset 类型。

将时间戳存储为数值时,请使用 Unix 时间 - 这是自 1970-01-01T00:00:00Z 以来的整秒数(不包括闰秒)。如果您需要更高的精度,请改用毫秒。此值应始终基于 UTC,无需任何时区调整。

如果您以后可能需要修改时间戳,请包含原始时区 ID,以便确定偏移量是否可能与记录的原始值有所不同。

在安排未来事件时,通常首选当地时间而不是 UTC,因为偏移量经常发生变化。请参阅答案和博文。

请记住,时区偏移并不总是整数小时(例如,印度标准时间是 UTC+05:30,尼泊尔使用 UTC+05:45)。

如果使用 Java,对 Java 8 使用 java.time,或者对 Java 7 或更低版本使用 Joda Time。 如果使用 .NET,请考虑使用 Noda Time。 如果在没有 Noda Time 的情况下使用 .NET,请考虑 DateTimeOffset 通常比 DateTime 更好。 如果使用 Perl,请使用 DateTime。 如果使用 Python,请使用 pytz 或 dateutil。 如果使用 javascript,请使用带有 moment-timezone 扩展名的 moment.js。 如果使用 PHP > 5.2,请使用 DateTime 和 DateTimeZone 类提供的本地时区转换。使用时要小心。

DateTimeZone::listAbbreviations() - 查看答案。为了让 PHP 保持最新的 Olson 数据,请定期安装 timezonedb PECL 包;看答案。

如果使用 C++,请务必使用正确实现 IANA 时区数据库的库。其中包括 cctz、ICU 和 Howard Hinnant 的“tz”库。

不要使用 Boost 进行时区转换。虽然其 API 声称支持标准 IANA(又名“zoneinfo”)标识符,但它粗略地将它们映射到固定偏移量,而不考虑每个区域可能发生的丰富更改历史。

(另外,该文件已停止维护。)

大多数业务规则使用民用时间,而不是 UTC 或 GMT。因此,在应用应用程序逻辑之前,请计划将 UTC 时间戳转换为本地时区。

请记住,时区和偏移量不是固定的,可能会发生变化。例如,历史上美国和英国使用相同的日期来“前进”和“后退”。

但是,美国在 2007 年更改了时钟更改的日期。现在这意味着一年中的 48 周伦敦时间和纽约时间之间的差异是 5 小时,而 4 周(春季 3 周,秋季 1 周)是 4 小时。在涉及多个区域的任何计算中,请注意此类项目。

考虑时间类型(实际事件时间、广播时间、相对时间、历史时间、重复时间)需要存储哪些元素(时间戳、时区偏移和时区名称)以进行正确检索 - 请参阅“类型时间”作为答案。

让您的操作系统、数据库和应用程序 tzdata 文件在它们自己和世界其他地方之间保持同步。

在服务器上,将硬件时钟和操作系统时钟设置为 UTC 而不是本地时区。

无论前面的要点如何,服务器端代码(包括网站)都不应期望服务器的本地时区是特定的。看答案。

在所有服务器上使用 NTP 服务。

如果使用 FAT32,请记住时间戳存储在本地时间,而不是 UTC。

在处理重复性事件(例如每周电视节目)时,请记住时间会随着 DST 的变化而变化,并且会因时区而异。

始终将日期时间值查询为包含下限、不包含上限(>=、

【讨论】:

【参考方案6】:

简洁的答案(无需更改默认时区)

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

啰嗦的回答

使用strtotime 的第二个选项来更改函数的参考框架。顺便说一句,我不想​​更新脚本的默认时区:

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

int strtotime ( string $time [, int $now = time() ] )

函数 期望得到一个包含英文日期格式的字符串,并且 将尝试将该格式解析为 Unix 时间戳( 自 1970 年 1 月 1 日 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'))
    )
);

【讨论】:

以上是关于PHP - strtotime,指定时区的主要内容,如果未能解决你的问题,请参考以下文章

PHP strtotime 函数 - 依赖系统的时区不安全?

如何修复与时区相关的 PHP 错误(function.strtotime 和 function.date)

PHP时间日期增减操作示例date strtotime实现加一天加一月等操作

php怎么将指定日期转换为时间戳

php怎么将指定日期转换为时间戳

php获取今天某个时间的时间戳的方法