12

似乎很多人都在为 PHP 中的日期/时间问题而苦苦挣扎,而且不可避免地,许多公认的答案往往是“以这种方式使用strtotime”。

这真的是指导人们处理约会问题的最佳方式吗?我开始觉得strtotime这是一种漂亮的技巧,不一定要依赖于重要的日期/时间计算,并且由于它采用任意字符串的性质,它似乎是一个潜在的错误来源,难以- 预测行为。它无法区分 MM/DD/YYYY 和 DD/MM/YYYY 有点大问题,不是吗?

StackOverflow 通常非常擅长推广良好实践(我很少看到mysql_real_escape_string没有人说“使用 PDO 代替”的对话。)

但是 PHP 中的日期问题似乎没有一个公认的规范,很多人都依赖strtotime.

那么,如果有的话,我们应该怎么做呢?对于提出诸如“如何将 1 周添加到 X”或“如何将这种日期格式转换为另一种日期格式”之类的问题的人们,我们应该执行更好的规范吗?

处理日期/时间问题的最佳、最可靠的方法是什么,例如strtotime尝试但经常失败?

4

7 回答 7

22

我首先要说我是使用 DateTime 对象的大力倡导者,它允许您使用该DateTime::createFromFormat()函数。DateTime 对象使代码更具可读性,并避免了使用 60 * 60 * 24 进行整个 Unix 时间戳修改以提前日期天数的需要。

话虽如此,strtotime() 采用的任意字符串并不难预测。支持的日期和时间格式列出了支持的格式。

根据您无法区分 MM/DD/YYYY 和 DD/MM/YYYY 的示例,它确实根据Date Formats进行区分。使用斜线的日期始终以美国格式读取。因此,格式为 00/00/0000 的日期将始终被读取为 MM/DD/YYYY。或者使用破折号或句点将是 DMY。例如,00-00-0000 将始终被读取为 DD-MM-YYYY。

这里有些例子:

<?php
$dates = array(
    // MM DD YYYY
    '11/12/2013' => strtotime('2013-11-12'),
    // Using 0 goes to the previous month
    '0/12/2013' => strtotime('2012-12-12'), 
    // 31st of November (30 days) goes to 1st December
    '11/31/2013' => strtotime('2013-12-01'), 
    // There isn't a 25th month... expect false
    '25/12/2013' => false,

    // DD MM YYYY
    '11-12-2013' => strtotime('2013-12-11'),
    '11.12.2013' => strtotime('2013-12-11'),
    '31.12.2013' => strtotime('2013-12-31'),
    // There isn't a 25th month expect false
    '12.25.2013' => false,
);

foreach($dates as $date => $expected) {
    assert(strtotime($date) == $expected);
}

正如您所看到的,有几个关键示例25/12/201312.25.2013如果以相反的格式读取它们都是有效的,但是false根据支持的日期和时间格式,它们会返回,因为它们是无效的......

所以你可以看到行为是完全可以预测的。与往常一样,如果您收到使用输入的日期,您应该首先验证该输入。如果您不先验证输入,则任何方法都不起作用。

如果您想非常具体地了解正在读取的日期,或者您获得的格式不是受支持的格式,那么我建议使用DateTime::createFromFormat().

于 2011-03-18T10:07:36.957 回答
8

strtotime()建议是因为它从 v4.x 开始就在 PHP 中,所以基本上保证可用。可用性胜过奇怪的时间(不是双关语),它会转过身来,用错误解析的日期咬你的屁股。

当前进行日期数学的“正确”方法是使用 DateTime/DateInterval 对象,但这些是 PHP 的最新添加(我认为是 5.2/5.3),因此并不总是可用 - 仍然有很多主机在 4 。X。

于 2011-03-13T03:40:45.970 回答
2

strtotime()经常使用。问题是,您不应该将它用作拐杖,但您应该意识到它的局限性。

如果您想强制执行标准,那么我想您应该使用基于 c 的mktime(). 例如,要在 1 周后获得:

date('Y-m-d', mktime(0, 0, 0, date('n'), date('j') + 7);
于 2011-03-13T03:40:22.087 回答
0

Derek Rethans 在 Froscon 2010 上发表了关于“PHP 中的高级日期和时间处理”的演讲。

在http://derickrethans.nl/talks/time-froscon10.pdf找到 PDF 格式的幻灯片。这些依赖于最近的 PHP(5.2 及更高版本),使用它也应该是最佳实践。

于 2011-03-18T10:52:47.367 回答
0

更新:对于 PHP >= 5.3 ,应该使用date_parse_from_format()代替。Notestrptime()在不同的操作系统上可能会有不同的行为,因为它依赖于strptime()系统的 C 库所公开的内容。

PHP 中最可靠的日期计算方法是使用时间戳。

确实,它受到 32 位整数的限制,但在某些奇怪的环境中键入时,不能使用 Date 对象,例如 PHP 4。

为了确保您获得最正确的行为,我建议使用strptime()从人类可读日期获取时间戳。这比strtotime()并且更好,strftime()因为它不会尝试猜测日期的格式,而是使用您提供的日期格式。

获得正确的时间戳后,您可以在 PHP 中使用多种方法来完成工作。

于 2011-03-18T12:37:57.017 回答
0

问题是您必须在应用程序的所有层中为您的日期/时间/区域值 (ISO8601:2004) 选择严格的数据格式,并找到最能处理这种格式的 PHP 函数,即:DateTime::createFromFormat().

恕我直言,用户界面(GUI 层)具有不同的日期/时间/区域格式,试图猜测 PHP 函数中的日期输入意味着您没有从客户端对数据进行任何清理(也许使用 Javascript?)和您正在以未知格式从您的网络公式传输数据。

如果日期/时间/区域格式与服务器端的 ISO8601 不匹配,您只需拒绝它,等等!

希望这可以帮助!

于 2011-03-19T17:29:58.803 回答
0

这在 PHP 中当然是可能的:查看strtotime 手册,尤其是这个注释

如果您有可用的 MySQL 连接,则 SELECT DATE_ADD( '2011-05-31', INTERVAL 1 MONTH ) 将减少冗余,因为(正确的)功能已经实现,而无需您自己实现。

于 2013-04-19T07:10:14.560 回答