Время ISO (ISO 8601) в Python

340

У меня есть файл. В Python я хотел бы взять его время создания и преобразовать его в строку времени ISO (ISO 8601) , сохранив тот факт, что он был создан в восточном часовом поясе (ET) .

Как мне взять ctime файла и преобразовать его в строку времени ISO, которая указывает восточный часовой пояс (и при необходимости учитывает переход на летнее время)?

Иосиф Туриан
источник
11
@ Ник - Полезная ссылка, но не дубликат - он спрашивает о конвертации в другую сторону.
Ярин
1
@ Джозеф - я только что спросил это в отношении RFC 3999 - должно сработать для этого - Создать метку времени RFC 3339 в Python
Ярин

Ответы:

560

Локально по ISO 8601:

import datetime
datetime.datetime.now().isoformat()
>>> 2020-03-20T14:28:23.382748

UTC по ISO 8601:

import datetime
datetime.datetime.utcnow().isoformat()
>>> 2020-03-20T01:30:08.180856

Локально по ISO 8601 без микросекунды:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:30:43

UTC по ISO 8601 с информацией о часовом поясе (Python 3):

import datetime
datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()
>>> 2020-03-20T01:31:12.467113+00:00

UTC по ISO 8601 с информацией о местном часовом поясе без микросекунды (Python 3):

import datetime
datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:31:43+13:00

Локально по ISO 8601 с информацией о часовом поясе (Python 3):

import datetime
datetime.datetime.now().astimezone().isoformat()
>>> 2020-03-20T14:32:16.458361+13:00

Обратите внимание, что при использовании astimezone()UTC время есть ошибка . Это дает неверный результат:

datetime.datetime.utcnow().astimezone().isoformat() #Incorrect result

Для Python 2 посмотрите и используйте pytz .

estani
источник
17
.isoformat()может принимать параметр разделителя, (если вы хотите что-то отличное от 'T'):.isoformat(' ')
ThorSummoner
5
@ThorSummoner приятно знать! Но позаботьтесь о том, чтобы замена разделителя больше не соответствовала ISO-8601 ... что не имеет особого смысла (кроме того, есть лучшие способы печати дат, но это не было вопросом здесь). RFC
Эстани
4
Пространство разрешено как часть стандарта ISO-8601. It is permitted to omit the 'T' character by mutual agreement.
Райчи
4
@raychi Всегда разрешается менять стандарт по взаимному согласию (что во многих случаях нарушает стандарт, но кого это волнует, если это взаимное согласие, верно?). Мой 2с: только не оставляй как есть.
октября
14
Этот ответ неверен, поскольку datetime.datetime.now (). Isoformat () возвращает локальную строку ISO 8601, не помечая ее как локальную. Вам нужно иметь datetime.timezone, представляющий местный часовой пояс, чтобы изоформаты работали правильно.
Сэм Хартман
66

Вот что я использую для преобразования в формат даты и времени XSD:

from datetime import datetime
datetime.now().replace(microsecond=0).isoformat()
# You get your ISO string

Я сталкивался с этим вопросом, когда искал формат даты и времени XSD ( xs:dateTime). Мне нужно было удалить микросекунды с isoformat.

radtek
источник
4
Что такое "XSD" (в этом контексте)?
Питер Мортенсен
1
Я думаю, что он имеет в виду xs:dateтаблицы стилей XSD / XML.
Свентечие
1
Это значитxs:dateTime
радтек
56

ISO 8601 Представление времени

Международный стандарт ISO 8601 описывает строковое представление для даты и времени. Два простых примера этого формата

2010-12-16 17:22:15
20101216T172215

(оба обозначают 16 декабря 2010 г.), но формат также позволяет установить время разрешения менее одной секунды и указать часовые пояса. Этот формат, конечно, не специфичен для Python, но он хорош для хранения даты и времени в переносимом формате. Подробности об этом формате можно найти в записи Маркуса Куна .

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

Один из способов получить текущее время в этом представлении - использовать strftime из модуля времени в стандартной библиотеке Python:

>>> from time import strftime
>>> strftime("%Y-%m-%d %H:%M:%S")
'2010-03-03 21:16:45'

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

>>> from datetime import datetime
>>> datetime.strptime("2010-06-04 21:08:12", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2010, 6, 4, 21, 8, 12)

Наиболее надежным является модуль Egenix mxDateTime:

>>> from mx.DateTime.ISO import ParseDateTimeUTC
>>> from datetime import datetime
>>> x = ParseDateTimeUTC("2010-06-04 21:08:12")
>>> datetime.fromtimestamp(x)
datetime.datetime(2010, 3, 6, 21, 8, 12)

Ссылки

Воислав Саука
источник
2
В каком смысле это «более крепкий»?
Стефан
Дата:2018-05-25
loxaxs
Объединенная дата и время в UTC:2018-05-25T12:16:14+00:00
loxaxs
2
Объединенная дата и время в UTC:2018-05-25T12:16:14Z
loxaxs
Объединенная дата и время в UTC:20180525T121614Z
loxaxs
49

Я нашел datetime.isoformat в документации . Кажется, делать то, что вы хотите:

datetime.isoformat([sep])

Return a string representing the date and time in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.mmmmmm or, if microsecond is 0, YYYY-MM-DDTHH:MM:SS

If utcoffset() does not return None, a 6-character string is appended, giving the UTC offset in (signed) hours and minutes: YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or, if microsecond is 0 YYYY-MM-DDTHH:MM:SS+HH:MM

The optional argument sep (default 'T') is a one-character separator, placed between the date and time portions of the result. For example,
>>>

>>> from datetime import tzinfo, timedelta, datetime
>>> class TZ(tzinfo):
...     def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'
user2120810
источник
30

ISO 8601 допускает компактное представление без разделителей, кроме T, поэтому я хотел бы использовать этот однострочный для получения быстрой строки метки времени:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%S.%fZ")
'20180905T140903.591680Z'

Если вам не нужны микросекунды, просто пропустите .%fчасть:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
'20180905T140903Z'

По местному времени:

>>> datetime.datetime.now().strftime("%Y%m%dT%H%M%S")
'20180905T140903'

Редактировать:

После прочтения этого вопроса я рекомендую оставить пунктуацию в. RFC 3339 рекомендует этот стиль, потому что, если все используют пунктуацию, нет риска, что несколько строк ISO 8601 будут отсортированы в группах по пунктуации. Таким образом, одна строка для соответствующей строки будет:

>>> datetime.datetime.now().strftime("%Y-%m-%dT%H:%M%SZ")
'2018-09-05T14:09:03Z'
Джим Хунзикер
источник
3
Есть ли способ ограничить цифры миллисекунд до 3? т.е. мое другое приложение javascript будет работать 2019-02-23T04:02:04.051Zсnew Date().toISOString()
Миранда
19

Формат времени ISO 8601 не хранит название часового пояса, сохраняется только соответствующее смещение UTC.

Чтобы преобразовать файл ctime в строку времени ISO 8601, сохранив смещение UTC в Python 3:

>>> import os
>>> from datetime import datetime, timezone
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, timezone.utc)
>>> dt.astimezone().isoformat()
'2015-11-27T00:29:06.839600-05:00'

Код предполагает, что ваш местный часовой пояс - это восточный часовой пояс (ET) и что ваша система предоставляет правильное смещение UTC для данной временной метки POSIX ( ts), т. Е. У Python есть доступ к базе данных исторических часовых поясов в вашей системе, или часовой пояс имел такие же правила на данную дату.

Если вам нужно портативное решение; используйте pytzмодуль, который обеспечивает доступ к базе данных tz :

>>> import os
>>> from datetime import datetime
>>> import pytz  # pip install pytz
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, pytz.timezone('America/New_York'))
>>> dt.isoformat()
'2015-11-27T00:29:06.839600-05:00'

Результат такой же в этом случае.

Если вам нужно название часового пояса / сокращение / идентификатор зоны, сохраните его отдельно.

>>> dt.astimezone().strftime('%Y-%m-%d %H:%M:%S%z (%Z)')
'2015-11-27 00:29:06-0500 (EST)'

Примечание: нет, :смещение UTC и ESTсокращение часового пояса не является частью формата времени ISO 8601. Это не уникально.

Разные библиотеки / разные версии одной и той же библиотеки могут использовать разные правила часового пояса для одной и той же даты / часового пояса. Если это будущая дата, то правила могут быть еще неизвестны. Другими словами, одно и то же время UTC может соответствовать разному местному времени, в зависимости от того, какие правила вы используете - сохранение времени в формате ISO 8601 сохраняет время UTC и местное время, которое соответствует текущим правилам часового пояса, используемым на вашей платформе. , Возможно, вам придется пересчитать местное время на другой платформе, если она имеет другие правила.

JFS
источник
14

Вам нужно будет использовать, os.statчтобы получить время создания файла и комбинацию time.strftimeи time.timezoneдля форматирования:

>>> import time
>>> import os
>>> t = os.stat('C:/Path/To/File.txt').st_ctime
>>> t = time.localtime(t)
>>> formatted = time.strftime('%Y-%m-%d %H:%M:%S', t)
>>> tz = str.format('{0:+06.2f}', float(time.timezone) / 3600)
>>> final = formatted + tz
>>> 
>>> final
'2008-11-24 14:46:08-02.00'
Макс Шавабке
источник
Учитывает ли часовой пояс летнее время? Кажется, что tz будет одинаковым независимо от летнего времени или нет.
Джозеф Туриан
2
Это будет любое смещение, действующее в данный момент. Если DST активен, он будет иметь другое смещение, чем когда DST не активен.
Макс Шавабке
4

Поправьте меня, если я ошибаюсь (я не ошибаюсь), но смещение от UTC меняется с переходом на летнее время. Так что вы должны использовать

tz = str.format('{0:+06.2f}', float(time.altzone) / 3600)

Я также считаю, что знак должен быть другим:

tz = str.format('{0:+06.2f}', -float(time.altzone) / 3600)

Я могу ошибаться, но я так не думаю.

Ярек Пшигодзки
источник
2

Я согласен с Яреком и, кроме того, отмечаю, что символ разделителя смещения ISO является двоеточием, поэтому я думаю, что окончательный ответ должен быть:

isodate.datetime_isoformat(datetime.datetime.now()) + str.format('{0:+06.2f}', -float(time.timezone) / 3600).replace('.', ':')
mattbornski
источник
2

Добавление небольшого варианта к отличному ответу Эстани

Локально по ISO 8601 с TimeZone и без микросекундной информации (Python 3):

import datetime, time

utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
utc_offset = datetime.timedelta(seconds=-utc_offset_sec)
datetime.datetime.now().replace(microsecond=0, tzinfo=datetime.timezone(offset=utc_offset)).isoformat()

Пример вывода:

'2019-11-06T12:12:06-08:00'

Проверено, что этот вывод может быть проанализирован как Javascript, так Dateи C # DateTime/DateTimeOffset

Sharpiro
источник
1

Я разработал эту функцию:

def iso_8601_format(dt):
    """YYYY-MM-DDThh:mm:ssTZD (1997-07-16T19:20:30-03:00)"""

    if dt is None:
        return ""

    fmt_datetime = dt.strftime('%Y-%m-%dT%H:%M:%S')
    tz = dt.utcoffset()
    if tz is None:
        fmt_timezone = "+00:00"
    else:
        fmt_timezone = str.format('{0:+06.2f}', float(tz.total_seconds() / 3600))

    return fmt_datetime + fmt_timezone
Андре Авилла
источник
-6
import datetime, time    
def convert_enddate_to_seconds(self, ts):
    """Takes ISO 8601 format(string) and converts into epoch time."""
     dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+\
                datetime.timedelta(hours=int(ts[-5:-3]),
                minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
    seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
    return seconds 

>>> import datetime, time
>>> ts = '2012-09-30T15:31:50.262-08:00'
>>> dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
>>> seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
>>> seconds
1348990310.26
Ронак
источник