Печать даты и времени в формате ISO без миллисекунд

Я пытаюсь сериализовать дату и время в API, но мне не нужны миллисекунды. Я хочу здесь: https://en.wikipedia.org/wiki/ISO_8601 - "2015-09-14T17:51:31+00:00"

tz = pytz.timezone('Asia/Taipei')
dt = datetime.datetime.now()
loc_dt = tz.localize(dt)

Попробуйте А:

loc_dt.isoformat()
>> '2015-09-17T10:46:15.767000+08:00'

Попробуйте Б:

loc_dt.strftime("%Y-%m-%dT%H:%M:%S%z")
>> '2015-09-17T10:46:15+0800'

Последний почти идеален, за исключением того, что в части часового пояса отсутствует двоеточие. Как я могу решить эту проблему без манипуляций со строками (удаление миллисекунд или добавление двоеточия)?


person Csaba Toth    schedule 17.09.2015    source источник
comment
Я бы предпочел решение со строкой формата, потому что это то, что я могу легко добавить в сериализатор. Однако я не вижу ничего полезного на странице строки формата strftime.   -  person Csaba Toth    schedule 17.09.2015
comment
ISO8601 допускает вторые фрагменты. Попробуйте удалить фрагмент перед форматированием строки   -  person Panagiotis Kanavos    schedule 18.09.2015
comment
несвязанный: ваш код может дать сбой во время переходов DST, вместо этого используйте loc_dt = datetime.now(tz).   -  person jfs    schedule 18.09.2015
comment
@ J.F.Sebastian Что происходит, почему это не получается? Иногда я локализую не datetime.now(), а существующий объект datetime.   -  person Csaba Toth    schedule 19.09.2015
comment
@CsabaToth: он может вернуть неправильное время для неоднозначного местного времени. Если вы хотите устранить неоднозначность существующего местного времени, вам нужна дополнительная информация, например, Анализ упорядоченных временных меток по местному времени (в формате UTC) при соблюдении перехода на летнее время Время   -  person jfs    schedule 19.09.2015


Ответы (1)


Вы можете заменить микросекунды на 0 и использовать изоформат:

import pytz
from datetime import datetime
tz = pytz.timezone('Asia/Taipei')
dt = datetime.now()
loc_dt = tz.localize(dt).replace(microsecond=0)
print loc_dt.isoformat()
2015-09-17T19:12:33+08:00

Если вы хотите сохранить loc_dt как есть, выполните замену при выводе:

loc_dt = tz.localize(dt)
print loc_dt.replace(microsecond=0).isoformat()

Как прокомментировано, вам лучше передать tz в datetime.now:

 dt = datetime.now(tz)

Причины обсуждаются в pep-0495, вы также можете добавить assert, чтобы отловить любые ошибки при замене:

 ssert loc_dt.resolution >= timedelta(microsecond=0)
person Padraic Cunningham    schedule 17.09.2015
comment
Вау, это странно с точки зрения парсера. Если по какой-либо причине микросекунда равна 0, она полностью опускается при выводе? Если минуты или секунды равны нулю, они не опускаются. - person Csaba Toth; 18.09.2015
comment
да, если вы замените миллисекунды на 0, тогда ваша дата и время станет datetime.datetime(2015, 9, 17, 12, 33, 46, tzinfo=<DstTzInfo 'Asia/Taipei' CST+8:00:00 STD>), поэтому вызов isoformat просто работает с тем, что есть - person Padraic Cunningham; 18.09.2015
comment
Анализ: stackoverflow.com/questions/127803/ Невероятно!!! - person Csaba Toth; 18.09.2015
comment
tz.localize(datetime.now()) может выйти из строя; вместо этого используйте datetime.now(tz). - person jfs; 18.09.2015
comment
добавьте assert datetime.resolution == timedelta(microseconds=1), иначе ваш код может дать сбой. - person jfs; 18.09.2015
comment
@ J.F.Sebastian, что делает datetime.resolution == timedelta(microseconds=1)? - person Padraic Cunningham; 18.09.2015
comment
@CsabaToth, dateutil, кажется, делает многое из того, что должно делать datetime, но dateutil также требует некоторых догадок, не уверен, что есть какая-либо полностью надежная библиотека. - person Padraic Cunningham; 18.09.2015
comment
@PadraicCunningham: проверяет, что datetime.resolution равно 1 микросекунде . Это всегда верно для всех текущих реализаций Python. На самом деле, assert loc_dt.resolution >= timedelta(microsecond=0) может быть здесь лучше: цель состоит в том, чтобы избежать тихого сбоя, если, например, loc_dt.resolution - это наносекунда. Примечание: ошибка assert здесь указывает на наличие ошибки, т. е. отсутствие пользовательского ввода (даже недействительного) может сделать утверждение ложным. - person jfs; 19.09.2015
comment
@ J.F.Sebastian Как .replace(microsecond=0).isoformat() может выйти из строя? Я определенно не хочу явно указывать фреймворку разрешение в микросекундах. Другой: не могли бы вы уточнить, как/почему tz.localize(datetime.now()) может выйти из строя? - person Csaba Toth; 19.09.2015
comment
@CsabaToth: (1) представьте, что вы хотели урезать результат до минуты: '2015-09-17T10:46:00+0800' и вы использовали для этого .replace(second=0).isoformat(); результат будет неправильным: '2015-09-17T10:46:00.767000+08:00 (обратите внимание: миллисекунды там). Если loc_dt.resolution является наносекундой, то .replace(microsecond=0) может оставить ненулевые наносекунды. (2) на tz.localize(datetime.now()) -- рассмотрим случаи, когда местное время неоднозначно, например, при переходе на летнее время. Читайте о том, почему tz.localize() имеет параметр is_dst. datetime.now(tz) работает. - person jfs; 19.09.2015
comment
@ J.F.Sebastian Я вижу: во время перехода на летнее время? МОЙ БОГ! - person Csaba Toth; 19.09.2015
comment
Хорошее решение для разбора для всех, кто использует Django: stackoverflow.com/questions/20194496/ - person Csaba Toth; 19.09.2015
comment
@ J.F.Sebastian, как .replace(second=0).isoformat() вписывается в удаление миллисекунд? - person Padraic Cunningham; 19.09.2015
comment
@PadraicCunningham: это не так. Обратите внимание на слова «представьте», «минута» и соответствующую метку времени, где секунды равны 00. - person jfs; 19.09.2015
comment
@ J.F.Sebastian, так как же `loc_dt.replace(microsecond=0).isoformat()` может не работать с использованием приведенного выше кода, при каких обстоятельствах loc_dt.resolution может быть наносекундой и приводить к ненулевым наносекундам? - person Padraic Cunningham; 19.09.2015
comment
@PadraicCunningham: (1) assert предполагает, что это никогда не происходит, если нет ошибки (2) Ошибка заключается в том, что loc_dt является некоторым подклассом datetime, таким как pandas.Timestamp или другим подобным типом, который может иметь loc_dt.resolution == nanosecond (там это интерфейсы с наносекундным разрешением, и люди хотят совершать круговые поездки без потери информации или удобства) (3) Нужно ли мне объяснять, почему .replace(microsecond=0) может быть недостаточно, если loc_dt.resolution < microsecond? - person jfs; 19.09.2015
comment
@ J.F.Sebastian, я понимаю, почему это может потерпеть неудачу, я спрашивал, был ли случай, напрямую связанный с датой и временем, когда он мог когда-либо потерпеть неудачу, на что я полагаю, что простой ответ - нет? - person Padraic Cunningham; 19.09.2015