使用IntlDateFormatter时年末日期大写Y显示下一年的原因
PHP IntlDateFormatter年末日期年份异常问题解析
问题背景
需求为每月末以塞尔维亚语拉丁字母格式输出月份全称与完整年份(如“Januar 2024”),但在PHP7.4与PHP8.2环境(默认时区Europe/Berlin)下,处理2024年12月30日、31日时,输出结果为decembar 2025(月份正确但年份变为下一年),仅12月29日及之前日期能输出正确的decembar 2024。
测试代码示例:
$period = new DateTimeImmutable('2024-12-31'); $format = new IntlDateFormatter('sr-Latn', IntlDateFormatter::NONE, IntlDateFormatter::NONE, NULL, IntlDateFormatter::GREGORIAN, "MMMM Y"); $label = datefmt_format($format, $period); echo $label;
异常原因解析
核心问题出在格式字符串中Y与y格式符的本质区别:
Y:代表基于周的年份(遵循ISO 8601标准),规则是一年的第一周必须包含该年的1月4日(或该年的第一个周四)。2024年12月30日、31日在ISO周历中属于2025年的第1周,因此使用Y时会输出2025。y:代表公历日历年份,即日期所属的自然年份,不受周历规则影响。
而月份MMMM始终基于公历日历月份计算,因此即使周年份跳转到2025,月份仍显示12月,最终出现decembar 2025的矛盾结果。
时区Europe/Berlin的作用是确保日期的时间戳对应到本地时间,从而正确计算ISO周所属的年份,这也是仅特定日期出现异常的原因——这两天的本地时间恰好落在下一年的周范围内。
解决方案
将格式字符串中的"MMMM Y"修改为"MMMM y",即可输出正确的日历年份:
$format = new IntlDateFormatter('sr-Latn', IntlDateFormatter::NONE, IntlDateFormatter::NONE, NULL, IntlDateFormatter::GREGORIAN, "MMMM y");
内容的提问来源于stack exchange,提问作者Igor Vidic
相关产品推荐
相关产品推荐

