【问题标题】:In Python, how to print FULL ISO 8601 timestamp, including current timezone在 Python 中,如何打印 FULL ISO 8601 时间戳,包括当前时区
【发布时间】:2014-07-04 13:08:51
【问题描述】:

我需要以 ISO 8601 格式打印完整的本地日期/时间,包括本地时区信息,例如:

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

如果我有正确的 tzinfo 对象,我可以使用 datetime.isoformat() 来打印它 - 但我该如何获得它?

注意,我被困在 Python 2.5 上,这可能会降低一些选项的可用性。

【问题讨论】:

  • 能否请您修改标题以明确您的问题实际上是什么 - 就目前而言,这似乎与 yesterday's effort 重复。
  • 不知道标题怎么不清楚?昨天的问题被错误地标记为重复 - 链接的问题没有回答我的问题 - 这是如何使用当前、本地、时区打印当前、本地、时间。
  • 因为,正如您在问题文本中实际指出的那样,您的问题不是打印时间戳,而是获取本地 tzinfo 对象。仅在 我关闭它之后,才将这一说明添加到上一个问题中。
  • 好吧,现在有点元,但问题标题肯定应该是询问如何解决我想要解决的问题(以便对未来寻找相同问题的人有用) ,而不是部分解决方案的技术细节?

标签: python datetime python-2.5


【解决方案1】:

python 标准库不提供 tzinfo 实现。您需要对其进行子类化。 datetime module 中提供了示例。

接受的答案提供了错误的结果。例如,在我的时区 +02 中,结果是 +01:59。这是因为在计算差值之前,需要在 localnow 和 utcnow 上进行微秒替换为 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 module 的否定 altzone:

from datetime import datetime
import time

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

【讨论】:

  • 请注意,'altzone' 的文档表明它只应在 'daylight' 非零时使用。这表明不同的变量包含非 DST 偏移量。因为当然可以。 ://
【解决方案2】:

已接受的@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

【讨论】:

    【解决方案3】:

    我已经找到了自己的方法来做到这一点,希望这对其他想要在输出文件中打印有用的时间戳的人有用。

    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)
    

    这感觉有点 hacky,但似乎是获取具有正确 UTC 偏移量的本地时间的唯一可靠方法。欢迎提供更好的答案!

    【讨论】:

    • 这个答案不正确。结果返回 utc +/-xy:59 因为毫秒在 localnow 和 utcnow 包括在内。然后减法会导致此舍入问题
    猜你喜欢
    • 2014-08-24
    • 2019-02-02
    • 2023-04-11
    • 2013-03-11
    • 1970-01-01
    • 2013-12-06
    • 2016-11-30
    • 1970-01-01
    相关资源
    最近更新 更多