【问题标题】:What is the right ISO8601 format?什么是正确的 ISO8601 格式?
【发布时间】:2016-07-07 18:32:18
【问题描述】:

为什么

echo date('c');

不等于

$datetime = new DateTime();
echo $datetime->format(DateTime::ISO8601); 

结果:

2016-07-07T21:18:22+03:00
2016-07-07T21:18:22+0300

两者都必须以 ISO8601 格式给出当前时间。在Wikipedia 中,正确的格式是2016-07-07T21:18:22+03:00,但有些银行在API 中使用2016-07-07T21:18:22+0300 格式。为什么?

【问题讨论】:

  • 两者都有效 - en.wikipedia.org/wiki/ISO_8601#Time_zone_designators - <time>Z, <time>±hh:mm, <time>±hhmm, <time>±hh 根据链接页面都有效;另见Marcus Kuhn's summary
  • @MarkBaker,您不能将基本格式的区域指示符与扩展格式的日期和时间混合在一起。 ISO 8601:2004 非常明确:[...] 表达式要么完全采用基本格式,在这种情况下,使用所需表达式所需的最小分隔符数量,要么完全采用扩展格式 [.. .]

标签: php date datetime iso8601


【解决方案1】:

2016-07-07T21:18:22+03:00

是正确的 ISO 8601:2004 表示。

2016-07-07T21:18:22+0300

不正确,当日期和时间为扩展格式时,区域指示符可能不是基本格式。

ISO 8601:2004 4.3 日期和时间

[...] 表达式应完全采用基本格式,在 在这种情况下,所需的最小分隔符数量 表达式被使用,或完全以扩展格式使用,在这种情况下 应使用额外的分隔符[...]

更新 1

ISO 8601 指定了三种不同的日期表示:日历、序号和星期日期。 Theese 可以被格式化为基本格式(分隔符的最少数量)或扩展格式(包括附加分隔符的基本格式的扩展)。 ISO 8601 要求生成的表达式要么始终采用基本格式,要么始终采用扩展格式。

本地时间的日历日期和时间与 UTC 不同的组合:

2016-07-07T21:18:22+03:00 (extended format)
20160707T211822+0300 (basic format)

本地时间的序数日期和时间与 UTC 不同的组合:

2016-189T21:18:22+03:00 (extended format)
2016189T211822+0300 (basic format)

本地时间的星期日期和时间与UTC的差异:

2016-W27-4T21:18:22+03:00 (extended format)
2016W274T211822+0300 (basic format)

以上所有表示均表示本地时间的相同日期和时间,与 UTC(和即时)不同。如果 API 记录它接受 ISO 8601 日期、时间和区域指示符(也称为完整表示),则它应该接受上述所有表示以符合 ISO 8601。

更新 2

我遇到的大多数错误都源于使用strftime() 以本地时间输出 ISO 8601 日期和时间,与扩展格式的 UTC 不同。由于z 转换说明符的限制,标准strftime() 只能输出基本格式的兼容表示:

本地时间的日历日期和时间与 UTC 不同的组合:

Format:          Example:
%Y%m%dT%H%M%S%z  20160707T211822+0300

本地时间的序数日期和时间与 UTC 不同的组合:

Basic format:    Example:
%Y%jT%H%M%S%z    2016189T211822+0300

本地时间的星期日期和时间与UTC的差异:

Basic format:    Example:
%GW%V%uT%H%M%S%z 2016W274T211822+0300

GNU strftime 实现支持百分比和z 转换说明符之间的: 标志,以指定区域指示符应以扩展格式格式化:

本地时间的日历日期和时间与 UTC 不同的组合:

Format:                Example:
%Y-%m-%dT%H:%M:%S%:z   2016-07-07T21:18:22+03:00

本地时间的序数日期和时间与 UTC 不同的组合:

Format:                Example:
%Y-%jT%H:%M:%S%:z      2016-189T21:18:22+03:00

本地时间的星期日期和时间与UTC的差异:

Format:                Example:
%G-W%V-%uT%H:%M:%S%:z  2016-W27-4T21:18:22+03:00

【讨论】:

  • 那么第二个应该是什么才能使它正确?
  • 好的。感谢更新。所以我想必然的问题是为什么 PHP 输出的格式不正确? (而且根据 OP,一些银行系统?)是否已向他们报告?
  • @Simba PHP 记录了 DateTime::ISO8601 不符合 ISO 8601,文档指出应该使用 DateTime::ATOM
  • 谢谢陈森。 DateTime::ISO8601 是出于向后兼容性的原因。我的爱沙尼亚瑞典银行使用这种格式,尽管在文档中使用 ISO8601 格式。
【解决方案2】:

即使使用 DateTime::ATOM,当给出毫秒数时,PHP 仍然不能正确解释 ISO8601。

$d=DateTime::createFromFormat(DateTime::ATOM,"2018-01-10T01:00:00.000Z"); 
// null

或使用碳:

echo Carbon\Carbon::createFromFormat(Carbon\Carbon::ATOM,"2018-01-10T01:00:00.000Z","UTC");
// InvalidArgumentException with message 'The timezone could not be found in the database'

最好的办法是让 Carbon 或 datetime 自己解决:

$d = new Carbon\Carbon("2018-01-10T01:00:00.000Z");
// -> 2018-01-10 01:00:00
$d = new Carbon\Carbon("2018-01-10T01:00:00Z");
// -> 2018-01-10 01:00:00

【讨论】:

    猜你喜欢
    • 2014-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多