DateInterval::createFromDateString() 不支持 ISO 8601 格式字符串(如 'P7D'),仅接受自然语言式相对时间描述(如 '1 day');解析 ISO 8601 必须使用 new DateInterval('P...') 构造函数。

DateInterval::createFromDateString 不支持 ISO 8601 字符串
直接传 P7D、PT1H 或 P1Y2M3DT4H5M6S 给 DateInterval::createFromDateString() 会失败,抛出 DateMalformedStringException(PHP 8.3+)或返回 false(旧版)。这个方法只认自然语言式相对时间描述,比如 "1 day"、"2 weeks"、"3 months",不解析 ISO 8601 格式。
常见错误现象:
- 代码:
DateInterval::createFromDateString('P7D')→ 报错DateMalformedStringException - 代码:
DateInterval::createFromDateString('1 day')→ 正常返回DateInterval实例
原因很简单:createFromDateString() 底层复用的是 strtotime() 的解析器,它只处理“人类可读”的相对表达,不是 ISO 解析器。
ISO 8601 格式必须用 DateInterval::__construct()
要构造 ISO 8601 格式的 DateInterval,唯一正确方式是调用构造函数:new DateInterval($isoString)。
立即学习“PHP免费学习笔记(深入)”;
必须满足:
- 字符串必须以
P开头(日期部分),含T表示时间部分(如需) - 单位字母大小写敏感:大写
Y、M、D、W、H、M、S,且M在P后是“月”,在T后是“分钟” - 不能省略前缀:例如
"1D"错误,必须是"P1D";"1H"错误,必须是"PT1H"
合法示例:
new DateInterval('P1D'); // 1天
new DateInterval('P2W'); // 2周(等价于 P14D)
new DateInterval('PT30M'); // 30分钟
new DateInterval('P1Y2MT4H'); // 1年2月4小时(注意:M 在 T 前是月,T 后是分钟)
PHP 8.3 下的兼容性陷阱:from_string 属性不可见
用 DateInterval::createFromDateString() 创建的实例,在 PHP 8.2+ 中只暴露 from_string 和 date_string 两个属性,其余字段(如 y、m、d 等)为私有且不可访问 —— 即便你 var_dump() 也看不到具体数值。
而用 new DateInterval('P1D') 构造的实例,所有标准属性(y、m、d、h、i、s)都可读取,且值准确反映 ISO 字符串含义。
这意味着:
- 如果你依赖
$interval->d获取天数,必须用构造函数,不能用createFromDateString() -
createFromDateString('1 day')返回的实例,var_dump($i)只显示from_string => "1 day",不保证内部字段已计算或可读
别混淆:DateTime 解析 ISO8601 ≠ DateInterval 解析 ISO8601
DateTime 类能直接解析 "2026-07-14T12:44:00+00:00" 这类完整时间戳,但 DateInterval 的职责完全不同:它只表示“一段长度”,不是“一个时间点”。
容易踩的坑:
- 误以为
DateInterval::createFromDateString("2026-07-14")能工作 —— 它不是日期,是无效相对描述,会报错 - 把 ISO8601 时间戳(如
"2026-07-14T12:44:00Z")传给DateInterval构造函数 —— 会触发警告并返回空间隔,因为这不是持续时间格式 - 混用
DateTime::createFromFormat()和DateInterval—— 前者用于解析时间点,后者用于定义偏移量,二者协作时应分开构造再调用add()/sub()
真正需要 ISO8601 持续时间时,路径只有一条:new DateInterval('P...')。其他入口全是误导。



















