You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP IntlDateFormatter周首日获取异常问题求助

问题分析与解决方案

我先帮你拆解下这个问题:你用IntlDateFormatter的'e'格式符获取2018-01-15(周一)的星期数值,得到了2,但根据你参考的ICU文档,预期应该是1(因为系统将周一设为周首日)。这个差异其实是ICU格式符'e'的定义细节,以及PHP Intl扩展的实现逻辑导致的。

为什么会出现不符合预期的结果?

先回顾你的代码:

$timezone = new \DateTimeZone('Europe/Amsterdam');
$date = new \DateTime('2018-01-15', $timezone);
$formatter = new \IntlDateFormatter('nl_NL', null, null);

// 正确输出"Monday"(2018-01-15确实是周一)
echo $formatter->formatObject($date, 'EEEE');

// 输出"2",不符合预期的"1"
echo $formatter->formatObject($date, 'e');

这里的核心矛盾点在于'e'格式符的实际行为:

  • 你参考的ICU文档可能标注'e'为**“本地星期几(1=周首日,7=周末日)”,但PHP的Intl扩展(依赖特定版本的ICU)中,'e'的实际逻辑是直接返回IntlCalendar的星期常量值**——而IntlCalendar的星期计数是从周日开始的:IntlCalendar::DOW_SUNDAY = 1,IntlCalendar::DOW_MONDAY = 2,以此类推。
  • 你提到“系统将周一(对应数值2)设为周首日”,这里的数值2是IntlCalendar的常量值,并非“周首日为1”的偏移计数,所以'e'会直接返回这个常量值,而非你预期的1。

如何得到“周首日为1”的星期数值?

如果你需要的是以系统/区域设置的周首日为起点的计数(比如周一=1、周二=2…周日=7,当周首日是周一的时候),不能直接用'e'格式符,需要借助IntlCalendar手动计算:

$timezone = new \DateTimeZone('Europe/Amsterdam');
$date = new \DateTime('2018-01-15', $timezone);

// 创建对应区域和时区的IntlCalendar实例
$calendar = IntlCalendar::createInstance($timezone, 'nl_NL');
// 将DateTime的时间同步到IntlCalendar(注意IntlCalendar使用毫秒时间戳)
$calendar->setTime($date->getTimestamp() * 1000);

// 获取当前区域的周首日(nl_NL返回IntlCalendar::DOW_MONDAY,对应数值2)
$firstDayOfWeek = $calendar->getFirstDayOfWeek();
// 获取当前日期的星期常量值(周一对应数值2)
$currentDayOfWeek = $calendar->get(IntlCalendar::FIELD_DAY_OF_WEEK);

// 计算相对于周首日的数值:周首日=1,依次递推
$relativeDay = ($currentDayOfWeek - $firstDayOfWeek + 7) % 7 + 1;

echo $relativeDay; // 输出1,符合你的预期

额外:其他星期格式符的区别

如果你的需求是固定规则的星期数值,可以选择对应格式符:

  • 固定ISO标准(周一=1,周日=7):使用'u'格式符(需确保ICU版本支持)
    echo $formatter->formatObject($date, 'u'); // 输出1
    
  • 以周日为1的计数(周日=1,周一=2…周六=7):使用'c'格式符
    echo $formatter->formatObject($date, 'c'); // 输出2
    

内容的提问来源于stack exchange,提问作者Martin Winkel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:14:52