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

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

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

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

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


person xorsyst    schedule 04.07.2014    source источник
comment
Не могли бы вы изменить заголовок, чтобы было ясно, в чем на самом деле заключается ваш вопрос - в его нынешнем виде это выглядит как дубликат вчерашнего усилия< /а>.   -  person jonrsharpe    schedule 04.07.2014
comment
Я не уверен, как заголовок неясен? Вчерашний вопрос был неправильно помечен как дубликат - связанный с ним вопрос НЕ отвечает на мой вопрос - как распечатать текущее местное время с текущим, местным часовым поясом.   -  person xorsyst    schedule 04.07.2014
comment
Потому что, как вы на самом деле указываете в тексте вопроса, ваша проблема не в печати метки времени, а в получении локального объекта tzinfo. Это уточнение было добавлено к предыдущему вопросу только после того, как я его закрыл.   -  person jonrsharpe    schedule 04.07.2014
comment
Ну, теперь это становится немного мета, но, конечно, заголовок вопроса должен спрашивать, как решить проблему, которую я хочу решить (чтобы быть полезной для будущих людей, ищущих ту же проблему), а не технические детали части решения?   -  person xorsyst    schedule 04.07.2014


Ответы (3)


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

Принятый ответ дает неверные результаты. Например, в моем часовом поясе +02 результат +01:59. Это связано с тем, что замена микросекунд на 0 должна быть выполнена для localnow и utcnow до расчета разницы.

Вот моя версия для 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()

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

from datetime import datetime
import time

now = datetime.now()
offset = -time.altzone
print(isoformat_offset(now, offset))
person kwoldt    schedule 26.04.2017
comment
Обратите внимание, что документы для «altzone» указывают, что его следует использовать только тогда, когда «дневной свет» не равен нулю. Это говорит о том, что другая переменная содержит смещение, отличное от DST. Потому что, конечно, это так. :/ - person tekHedd; 10.08.2019

Принятый ответ @xorsyst теперь дает мне неверные результаты (21 марта 2018 г. в Европе / Варшавской зоне):

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

(должно быть: 21.03.2018 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
person Marcin Raczyński    schedule 20.03.2018

Я разработал свой собственный способ сделать это, надеюсь, это будет полезно для всех, кто хочет печатать полезные временные метки в выходных файлах.

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. Приветствуются лучшие ответы!

person xorsyst    schedule 14.07.2014
comment
этот ответ неверный. результат возвращает utc +/-xy:59, потому что миллисекунды указаны в localnow и включены utcnow. затем вычитание вызывает эту проблему округления - person Dominik; 26.04.2017