使用序数值时 php strtotime 函数出现问题

发布于 2024-10-14 05:58:39 字数 183 浏览 9 评论 0原文

在 strtotime 中使用序数值时,有时会得到意想不到的结果。例如,为什么

date("M j", strtotime("second Tuesday February 2011"))

结果是“Feb 15”(实际上是 2011 年的第三星期二?

I sometime get unexpected results when using ordinal values with strtotime. For example, why does

date("M j", strtotime("second Tuesday February 2011"))

result in "Feb 15" (which is actually the third Tuesday in 2011?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

咆哮 2024-10-21 05:58:39

你漏掉了一个‘of’。

$ php -r 'echo date("M j", strtotime("2011 年 2 月第二个星期二"));'
2 月 15 日

$ php -r 'echo date("M j", strtotime("2011 年 2 月第二个星期二"));'
2月8日

PHP 版本:

$ php -v
PHP 5.3.3 (cli)(构建时间:2010 年 8 月 22 日 19:41:55)
版权所有 (c) 1997-2010 PHP 集团
Zend Engine v2.3.0,版权所有 (c) 1998-2010 Zend Technologies

文档 告诉你造成这种情况的原因:

还要注意“序数”中的“of”
空间日名空间 'of' " 和 "'last'
空间日名空间 'of' " 确实
一些特别的东西。

  • 它将月份中的某一天设置为 1。
  • “序数日名 'of' ” 不
    提前到另一天。 (例子:
    “2008 年 7 月第一个星期二”意味着
    “2008-07-01”)。
  • “序数日名”确实
    提前到另一天。 (例子:
    “2008年7月第一个星期二”是什么意思
    “2008-07-08”,另见第 4 点
    上面列出)。

You are missing an 'of'.

$ php -r 'echo date("M j", strtotime("second Tuesday February 2011"));'
Feb 15

$ php -r 'echo date("M j", strtotime("second Tuesday of February 2011"));'
Feb 8

PHP Version:

$ php -v
PHP 5.3.3 (cli) (built: Aug 22 2010 19:41:55)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

The documentation tells you the cause for this:

Also observe that the "of" in "ordinal
space dayname space 'of' " and "'last'
space dayname space 'of' " does
something special.

  • It sets the day-of-month to 1.
  • "ordinal dayname 'of' " does not
    advance to another day. (Example:
    "first tuesday of july 2008" means
    "2008-07-01").
  • "ordinal dayname " does
    advance to another day. (Example:
    "first tuesday july 2008" means
    "2008-07-08", see also point 4 in the
    list above).
冷清清 2024-10-21 05:58:39

strtotime() 手册告诉你你想要什么

在 5.2.7 之前的 PHP 5 中,请求
给定工作日的发生时间
该工作日所在的月份
该月的第一天将
错误地将一周添加到
返回时间戳。这已经是
5.2.7及以后版本修正。

简而言之,这是您正在使用的版本中的错误。

如果您正在寻找某种适用的修复方法,则删除序数值似乎可行(就好像第一/第二/第三表示整周)

echo date("M j", strtotime("Tuesday February 2011")), '<br>';
echo date("M j", strtotime("first Tuesday February 2011")), '<br>';
echo date("M j", strtotime("second Tuesday February 2011")), '<br>';
echo date("M j", strtotime("third Tuesday February 2011")), '<br>';

The manual for strtotime() tells what you seek

In PHP 5 prior to 5.2.7, requesting a
given occurrence of a given weekday in
a month where that weekday was the
first day of the month would
incorrectly add one week to the
returned timestamp. This has been
corrected in 5.2.7 and later versions.

In short, it's a bug in the version you're using.

If you're looking for some sort of applicable fix, dropping the ordinal value seems to work (as if the first/second/third indicate full weeks)

echo date("M j", strtotime("Tuesday February 2011")), '<br>';
echo date("M j", strtotime("first Tuesday February 2011")), '<br>';
echo date("M j", strtotime("second Tuesday February 2011")), '<br>';
echo date("M j", strtotime("third Tuesday February 2011")), '<br>';
旧竹 2024-10-21 05:58:39

依赖 strtotime 来处理序数日期计算似乎并不安全——至少在 PHP 版本中是这样。 5.3. (我已经用 5.2.9 和 5.2.11 进行了测试,尽管在线文档中声称该错误已在 5.2.7 中修复,但两者都不起作用。)

按照建议添加“of”显然仅适用于 php 5.3+ 并删除序数完全将返回“第一次”出现,但其他序数将休息 7 天。

PHP 5.2 的最佳解决方案似乎是这样的:

$recurrOrdinal = "last";
$dayOfWeek = "Thursday";
$monthYear = "March 2011";

echo ordinalDate($recurrOrdinal, $dayOfWeek, $monthYear);

function ordinalDate($recurrOrdinal, $dayOfWeek, $monthYear)    {
    $firstDate = date("j", strtotime($dayOfWeek . " " . $monthYear) );
    if ($recurrOrdinal == "first")
    $computed = $firstDate; 
    elseif ($recurrOrdinal == "second")
    $computed = $firstDate + 7; 
    elseif ($recurrOrdinal == "third")
    $computed = $firstDate + 14; 
    elseif ($recurrOrdinal == "fourth")
    $computed = $firstDate + 21; 
    elseif ($recurrOrdinal == "last")   {
    if ( ($firstDate + 28) <= date("t", strtotime($monthYear)) )
        $computed = $firstDate + 28; 
    else
        $computed = $firstDate + 21; 
    }
    return date("Y-m-d", strtotime($computed . " " . $monthYear) );
}

It seems that it's not safe to rely on strtotime to deal with ordinal date computations -- at least in versions of PHP < 5.3. (I've tested with 5.2.9 and 5.2.11 and neither works despite the claim in the online documentation that the bug was fixed in 5.2.7.)

Adding "of" as suggested apparently only works in php 5.3+ and dropping the ordinal altogether will return the "first" occurrence, but other ordinals will be 7 days off.

The best solution for PHP 5.2 seems to be something like this:

$recurrOrdinal = "last";
$dayOfWeek = "Thursday";
$monthYear = "March 2011";

echo ordinalDate($recurrOrdinal, $dayOfWeek, $monthYear);

function ordinalDate($recurrOrdinal, $dayOfWeek, $monthYear)    {
    $firstDate = date("j", strtotime($dayOfWeek . " " . $monthYear) );
    if ($recurrOrdinal == "first")
    $computed = $firstDate; 
    elseif ($recurrOrdinal == "second")
    $computed = $firstDate + 7; 
    elseif ($recurrOrdinal == "third")
    $computed = $firstDate + 14; 
    elseif ($recurrOrdinal == "fourth")
    $computed = $firstDate + 21; 
    elseif ($recurrOrdinal == "last")   {
    if ( ($firstDate + 28) <= date("t", strtotime($monthYear)) )
        $computed = $firstDate + 28; 
    else
        $computed = $firstDate + 21; 
    }
    return date("Y-m-d", strtotime($computed . " " . $monthYear) );
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文