ISO 8601是什么?如何在Python中使用ISO时间?

646
我有一个文件。在Python中,我想要获取它的创建时间,并将其转换为ISO时间(ISO 8601)字符串,同时保留它在东部时间区域(ET)创建的事实。
如何获取文件的ctime并将其转换为指示东部时间区域的ISO时间字符串(如果需要考虑夏令时)?

12
有用的链接,但不是重复问题,他正在询问如何进行反向转换。 - Yarin
1
@Joseph- 我刚刚问了关于RFC 3999的问题- 这应该适用于它 - 在Python中生成RFC 3339时间戳 - Yarin
15个回答

1112
本地时间转换为ISO 8601格式:
import datetime
datetime.datetime.now().isoformat()
>>> 2020-03-20T14:28:23.382748

UTC转ISO 8601:
import datetime
datetime.datetime.utcnow().isoformat()
>>> 2020-03-20T01:30:08.180856

本地时间转换为没有微秒的 ISO 8601:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:30:43

UTC转ISO 8601带有时区信息(Python 3):
import datetime
datetime.datetime.now(tz=datetime.timezone.utc).isoformat()
>>> 2020-03-20T01:31:12.467113+00:00

UTC转换为ISO 8601格式,包含本地时区信息但不包含微秒(Python 3):
import datetime
datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:31:43+13:00

本地时间转换为带有时区信息的ISO 8601格式(Python 3):
import datetime
datetime.datetime.now().astimezone().isoformat()
>>> 2020-03-20T14:32:16.458361+13:00

注意,在使用astimezone()将UTC时间转换为本地时间时存在一个错误。这会导致结果不正确。
datetime.datetime.utcnow().astimezone().isoformat() #Incorrect result

对于Python 2,请参考并使用pytz

50
.isoformat()可以接受一个分隔符参数,以便您可以使用除了默认的'T'之外的其他内容作为分隔符。例如:.isoformat(' ')表示使用空格作为分隔符。 - ThorSummoner
10
@ThorSummoner 好的,知道了!但是要注意更改分隔符将不符合ISO-8601标准...这没有太多意义(此外,有更好的方法来打印日期,但这不是这里的问题)。 RFC - estani
20
ISO-8601标准允许包含空格。可以通过双方协商省略“T”字符。 - raychi
9
@raychi,如果通过双方协议更改标准始终是可以的(在许多情况下会破坏标准,但如果是双方同意,谁会在意呢?)。我的个人建议是:不要改变标准,让它保持原样。 - estani
24
这个答案是错误的,因为datetime.datetime.now().isoformat()返回一个本地的ISO 8601字符串,但没有标注它是本地的。你需要使用代表本地时区的datetime.timezone来确保isoformat正确工作。 - Sam Hartman
显示剩余11条评论

117

ISO 8601允许紧凑的表示方式,除了T之外没有分隔符,因此我喜欢使用这个一行代码来获取快速时间戳字符串:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%S.%fZ")
'20180905T140903.591680Z'

如果您不需要微秒级别的精度,可以省略.%f部分:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
'20180905T140903Z'

对于本地时间:

>>> datetime.datetime.now().strftime("%Y%m%dT%H%M%S")
'20180905T140903'

总的来说,我建议您保留标点符号。 RFC 3339 推荐使用这种风格,因为如果每个人都使用标点符号,就不会出现多个 ISO 8601 字符串按其标点符号在组中排序的风险。因此,符合规范的字符串的一行代码应为:

>>> datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
'2018-09-05T14:09:03Z'

5
有没有办法将毫秒数限制在3位数字以内?即,我的另一个JavaScript应用程序使用new Date().toISOString()会生成类似于2019-02-23T04:02:04.051Z的日期时间格式。 - Mzq
1
警告:结尾处的‘Z’是不正确的。输出包括‘Z’符号的时区的正确方法是使用‘%z’或‘%Z’,这使得它变成‘datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S%z")’。我已经花了2个小时来查找我的代码中的错误…… - Dr_Zaszuś
3
@Dr_Zaszuś 这不正确。%z 会为你的本地时间生成时区偏移量,这不适用于时间戳,尤其是当你查看多个系统时。字面上的 Z 是 ISO 8601 中代表 UTC 的简写形式。 - Jim Hunziker
1
@Miranda 类似于 JavaScript 的输出 datetime.datetime.now(datetime.timezone.utc).isoformat()[:23]+"Z" - seizu
@Dr_Zaszuś 你也可以使用 utcnow() 替代 now() - DollarAkshay

79

这是我用来将日期时间转换为XSD日期时间格式的方法:

from datetime import datetime
datetime.now().replace(microsecond=0).isoformat()
# You get your ISO string

我在寻找XSD日期时间格式(xs:dateTime)时遇到了这个问题。我需要从isoformat中删除微秒。


5
在这个上下文中,“XSD”是指什么? - Peter Mortensen
2
我相信他指的是 XSD / XML 样式表中的 xs:date - sventechie
1
它的意思是 xs:dateTime - radtek

66

ISO 8601时间表示

国际标准ISO 8601描述了日期和时间的字符串表示形式。这种格式的两个简单示例为:

2010-12-16 17:22:15
20101216T172215

ISO 8601日期格式可以用来表示时间(均为2010年12月16日),但该格式也允许指定亚秒分辨率时间和时区。当然,这种格式并非仅适用于Python,但它非常适合以可移植的方式存储日期和时间。有关此格式的详细信息可以在马库斯·昆恩(Markus Kuhn)条目中找到。

我建议使用此格式来存储文件中的时间。

从Python标准库的time模块中使用strftime获取当前时间的方法如下:

>>> from time import strftime
>>> strftime("%Y-%m-%d %H:%M:%S")
'2010-03-03 21:16:45'

您可以使用datetime类的strptime构造函数:

>>> from datetime import datetime
>>> datetime.strptime("2010-06-04 21:08:12", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2010, 6, 4, 21, 8, 12)

最强大的是Egenix mxDateTime模块:

>>> from mx.DateTime.ISO import ParseDateTimeUTC
>>> from datetime import datetime
>>> x = ParseDateTimeUTC("2010-06-04 21:08:12")
>>> datetime.fromtimestamp(x)
datetime.datetime(2010, 3, 6, 21, 8, 12)

参考资料


2
它更加“健壮”的意义是什么? - Stéphane
日期:2018年5月25日 - loxaxs
合并日期和时间为UTC:2018-05-25T12:16:14+00:00 - loxaxs
2
合并日期和时间为UTC:2018-05-25T12:16:14Z - loxaxs
合并日期和时间为UTC:20180525T121614Z - loxaxs
如何在UTC中创建此组合日期和时间:2018-05-25T12:16:14Z @Ioxaxs - Khan

53
我在文档中找到了datetime.isoformat。它似乎可以实现你想要的功能:
datetime.isoformat([sep])

Return a string representing the date and time in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.mmmmmm or, if microsecond is 0, YYYY-MM-DDTHH:MM:SS

If utcoffset() does not return None, a 6-character string is appended, giving the UTC offset in (signed) hours and minutes: YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or, if microsecond is 0 YYYY-MM-DDTHH:MM:SS+HH:MM

The optional argument sep (default 'T') is a one-character separator, placed between the date and time portions of the result. For example,
>>>

>>> from datetime import tzinfo, timedelta, datetime
>>> class TZ(tzinfo):
...     def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'

31

如果您正在寻找仅限于日期的解决方案,那么它就是:

import datetime

datetime.date.today().isoformat()

我这样做是为了避免导入比datetime更多的类:从datetime中导入datetime; datetime.now().isoformat()[:10](抱歉找不到代码片段) - David Elgstuen
另一种方法:datetime.datetime.now().strftime("%Y-%m-%d) - tommy.carstensen

26

ISO 8601 时间格式不保存时区名称,仅保留相应的 UTC 偏移量。

在 Python 3 中将文件 ctime 转换为 ISO 8601 时间字符串并保留 UTC 偏移量的方法:

>>> import os
>>> from datetime import datetime, timezone
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, timezone.utc)
>>> dt.astimezone().isoformat()
'2015-11-27T00:29:06.839600-05:00'
代码假设您的本地时区为东部标准时间(ET),并且您的系统针对给定的POSIX时间戳(ts)提供了正确的UTC偏移量,即Python可以访问系统上的历史时区数据库或在给定日期时区具有相同的规则。

如果您需要一个可移植的解决方案,请使用pytz模块,该模块提供访问tz数据库的功能:

>>> import os
>>> from datetime import datetime
>>> import pytz  # pip install pytz
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, pytz.timezone('America/New_York'))
>>> dt.isoformat()
'2015-11-27T00:29:06.839600-05:00'

在这种情况下结果是相同的。

如果你需要时区名称/缩写/区域ID,请将其单独存储。

>>> dt.astimezone().strftime('%Y-%m-%d %H:%M:%S%z (%Z)')
'2015-11-27 00:29:06-0500 (EST)'

注意:UTC偏移量中没有冒号,EST时区缩写也不是ISO 8601时间格式的一部分。这不是唯一的。

不同的库/相同库的不同版本可能针对同一日期/时区使用不同的时区规则。如果是未来的日期,则可能还不知道规则。换句话说,相同的UTC时间可能对应于不同的本地时间,具体取决于使用的规则 - 以ISO 8601格式保存时间会保留UTC时间以及与您平台上正在使用的当前时区规则对应的本地时间。如果使用不同的规则,在不同的平台上可能需要重新计算本地时间。


20

您需要使用os.stat来获取文件创建时间,同时结合使用time.strftimetime.timezone进行格式化:

>>> import time
>>> import os
>>> t = os.stat('C:/Path/To/File.txt').st_ctime
>>> t = time.localtime(t)
>>> formatted = time.strftime('%Y-%m-%d %H:%M:%S', t)
>>> tz = str.format('{0:+06.2f}', float(time.timezone) / 3600)
>>> final = formatted + tz
>>> 
>>> final
'2008-11-24 14:46:08-02.00'

时区是否考虑夏令时?似乎无论是否使用夏令时,tz都是相同的。 - Joseph Turian
2
它将是当前生效的任何偏移量。如果夏令时处于活动状态,则其偏移量将与夏令时不活动时不同。 - Max Shawabkeh

17

请保持生活简单:

  1. 使用UTC时间
  2. 微秒级别时间戳
  3. 一行代码实现

f"{datetime.datetime.utcnow().isoformat()[:-3]}Z"

输出结果:

2022-02-25T02:08:40.684Z


6

毫秒级标准 RFC-3339格式

在LoRa应用中,我需要以此格式获取时间,下面是我的解决方案,希望能够帮到你:

from datetime import datetime
from time import strftime


# Get the current time in the format: 2021-03-20T16:51:23.644+01:00
def rfc3339_time_ms():
        datetime_now = datetime.utcnow()
        # Remove the microseconds
        datetime_now_ms = datetime_now.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
        # Add the timezone as "+/-HHMM", and the colon in "+/-HH:MM"
        datetime_now_ms_tz = datetime_now_ms + strftime("%z")
        rfc3339_ms_now = datetime_now_ms_tz[:-2] + ":" + datetime_now_ms_tz[-2:]
        # print(f"Current time in ms in RFC-3339 format: {rfc3339_ms_now}")
        return rfc3339_ms_now

这真的很有帮助,因为它是由Twitter API强制要求的。 - vincent mathew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接