如何在Python中打印完整的ISO 8601时间戳,包含当前时区

6 投票
3 回答
3410 浏览
提问于 2025-04-18 12:07

我想要打印出完整的本地日期和时间,格式要符合ISO 8601标准,还要包含本地时区的信息,比如:

2007-04-05T12:30:00.0000-02:00

我可以使用 datetime.isoformat() 来打印这些信息,但我该如何获取正确的时区信息对象呢?

需要注意的是,我现在使用的是Python 2.5,这可能会限制一些可用的选项。

3 个回答

1

接受的 @xorsyst 的回答现在给我的结果是错的(2018-03-21 在欧洲/华沙时区):

2018-03-21 19:02:10+00:59

(应该是:2018-03-21 19:02:10+01:00)

@kwoldt 给的答案更好,但需要一个合适的偏移参数。他的例子结果也不对:

>>> print(isoformat_offset(datetime.now(), offset=-time.altzone, short=False))
2018-03-21T19:06:54.024151+02:00

(应该是:2018-03-21T19:06:54.024151+01:00)

我找到了一种对我有效的解决方案:

import datetime
import time

def local_datetime_isoformat():
    ts = time.time()
    local_dt = datetime.datetime.fromtimestamp(ts)
    struct_tm = time.localtime(ts)
    offset = time.altzone if struct_tm.tm_isdst else time.timezone
    local_iso = local_dt.isoformat(' ')
    if offset:
        sign = '+' if offset < 0 else '-'
        offset_hours = abs(offset) // 3600
        offset_minutes = (abs(offset) % 3600) // 60
        local_iso += '{0}{1:0<2}:{2:0<2}'.format(sign, offset_hours, offset_minutes)
    else:
        local_iso += 'Z'
    return local_iso

>>> print local_datetime_isoformat()
2018-03-21 19:04:03.631014+01:00
1

Python的标准库里没有提供tzinfo的实现,你需要自己去创建一个。你可以在datetime模块里找到一些示例。

有些人给出的答案结果是错误的。例如,在我的时区+02下,结果却是+01:59。这是因为在计算时间差之前,需要把本地时间和UTC时间的微秒部分都替换成0。

这里有一个我为Python 2.5写的版本:

# coding=utf-8


def isoformat_offset(dt, offset, dt_sep='T', hm_sep=True, short=True):
    """Return a string representing the date and time in ISO 8601 format,
    YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM. If microseconds is 0 .mmmmmm is omitted.
    The optional argument dt_sep (default 'T') is a one-character separator,
    placed between the date and time portions of the result.
    The optional argument hm_Sep (default True) indicates if a : separator
    should be placed between the hours and minutes portions of the time zone
    designator.
    The optional argument short (default True) defines if the minute portion of
    the time zone designator should be omitted in the case of zero minutes.

        >>> from datetime import datetime
        >>> cur = datetime(2017, 4, 26, 17, 14, 23, 123456)
        >>> off = 2 * 3600 # +02:00
        >>> isoformat_offset(cur, off)
        '2017-04-26T17:14:23.123456+02'
        >>> isoformat_offset(cur, off, ' ')
        '2017-04-26 17:14:23.123456+02'
        >>> isoformat_offset(cur, off, hm_sep=False)
        '2017-04-26T17:14:23.123456+02'
        >>> isoformat_offset(cur, off, short=False)
        '2017-04-26T17:14:23.123456+02:00'
        >>> isoformat_offset(cur, off, hm_sep=False, short=False)
        '2017-04-26T17:14:23.123456+0200'
        >>> cur = cur.replace(microsecond=0)
        >>> isoformat_offset(cur, off)
        '2017-04-26T17:14:23+02'
        >>> off = -2 * 3600 # -02:00
        >>> isoformat_offset(cur, off)
        '2017-04-26T17:14:23-02'
        >>> off = 2 * 3600 + 30 * 60 # +02:30
        >>> isoformat_offset(cur, off)
        '2017-04-26T17:14:23+02:30'
        >>> isoformat_offset(cur, off, hm_sep=False)
        '2017-04-26T17:14:23+0230'
    """
    offset_hours = offset // 3600
    offset_mins = (offset - offset_hours * 3600) // 60
    frmt = '%s%+03d'
    args = [dt.isoformat(dt_sep), offset_hours]
    if (short is True and offset_mins > 0) or (short is False and offset_mins == 0):
        if hm_sep is True:
            frmt += ':'
        frmt += '%02d'
        args.append(offset_mins)
    return frmt % tuple(args)

if __name__ == '__main__':
    import doctest
    doctest.testmod()

要获取这个函数所需的本地时区的秒数,可以使用来自time模块的负值altzone:

from datetime import datetime
import time

now = datetime.now()
offset = -time.altzone
print(isoformat_offset(now, offset))
0

我找到了自己的一种方法,希望这对想在输出文件中打印有用的时间戳的人有帮助。

import datetime

# get current local time and utc time
localnow = datetime.datetime.now()
utcnow = datetime.datetime.utcnow()

# compute the time difference in seconds
tzd = localnow - utcnow
secs = tzd.days * 24 * 3600 + tzd.seconds

# get a positive or negative prefix
prefix = '+'
if secs < 0:
    prefix = '-'
    secs = abs(secs)

# print the local time with the difference, correctly formatted
suffix = "%s%02d:%02d" % (prefix, secs/3600, secs/60%60)
now = localnow.replace(microsecond=0)
print "%s%s" % (now.isoformat(' '), suffix)

这感觉有点不太正规,但似乎是获取带有正确UTC时区偏移的本地时间的唯一可靠方法。如果有更好的方法,欢迎分享!

撰写回答