В Python, как напечатать полную метку времени ISO 8601, включая текущий часовой пояс

Мне нужно напечатать ПОЛНУЮ местную дату / время в формате ISO 8601, включая информацию о местном часовом поясе, например:

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

я могу использовать datetime.isoformat() распечатать его, если у меня есть правильный объект tzinfo - но как мне его получить?

Обратите внимание, я застрял в Python 2.5, что может снизить доступность опций.

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)

Это выглядит немного странно, но кажется единственным надежным способом получить местное время с правильным смещением UTC. Лучшие ответы приветствуются!

Стандартная библиотека python не обеспечивает реализацию tzinfo. Вы должны подкласс это. примеры приведены в модуле datetime.

Принятый ответ дает неверные результаты. Например, в моем часовом поясе +02 результат +01:59. Это связано с тем, что перед вычислением разницы необходимо выполнить микросекундную замену на 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()

Чтобы получить местный часовой пояс в секундах по мере необходимости для этой функции, используйте отрицательный altzone из временного модуля:

from datetime import datetime
import time

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

Принято @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
Другие вопросы по тегам