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)