Создайте временную метку RFC 3339 в Python

Я пытаюсь создать RFC 3339 Временная метка UTC в Python. До сих пор я мог сделать следующее:

>>> d = datetime.datetime.now()
>>> print d.isoformat('T')
2011-12-18T20:46:00.392227

Моя проблема связана с установкой смещения UTC.

Согласно docs, classmethod datetime.now([tz]) принимает необязательный аргумент tz, где tz must be an instance of a class tzinfo subclass и datetime.tzinfo an abstract base class for time zone information objects.

Вот где я теряюсь. Как tzinfo является абстрактным классом и как его реализовать?


( ПРИМЕЧАНИЕ: В PHP это так же просто, как timestamp = date(DATE_RFC3339);, поэтому я не могу понять, почему подход Python настолько запутан...)

Ответ 1

Далее вниз в том же документе, с которым вы связались, в нем объясняется, как его реализовать, приводя некоторые примеры, включая полный код для UTC (представляющий UTC), a FixedOffset класс (представляющий часовой пояс с фиксированным смещением от UTC, в отличие от часового пояса с DST и еще что-то) и несколько других.

Ответ 2

Часовые пояса - это боль, поэтому, вероятно, они решили не включать их в библиотеку datetime.

попробуйте pytz, у него есть tzinfo, который вы ищете: http://pytz.sourceforge.net/

Сначала вы должны создать объект datetime, а затем применить часовой пояс, как показано ниже, а затем ваш вывод .isoformat() будет содержать смещение UTC по желанию:

d = datetime.datetime.utcnow()
d_with_timezone = d.replace(tzinfo=pytz.UTC)
d_with_timezone.isoformat()

'2017-04-13T14: 34: 23,111142 + 00: 00'

Или, просто используйте UTC и бросьте "Z" (для часовой пояс Zulu) в конце, чтобы отметить "часовой пояс" как UTC.

d = datetime.datetime.utcnow() # <-- get time in UTC
print d.isoformat("T") + "Z"

'2017-04-13T14: 34: 23.111142Z

Ответ 3

В Python 3. 3+:

>>> from datetime import datetime, timezone                                
>>> local_time = datetime.now(timezone.utc).astimezone()
>>> local_time.isoformat()
'2015-01-16T16:52:58.547366+01:00'

В старых версиях Python, если вам нужен только осведомленный объект datetime, представляющий текущее время в UTC, вы можете определить простой подкласс tzinfo, как показано в документации, для представления часового пояса UTC:

from datetime import datetime

utc_now = datetime.now(utc)
print(utc_now.isoformat('T'))
# -> 2015-05-19T20:32:12.610841+00:00

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

#!/usr/bin/env python
from datetime import datetime
from tzlocal import get_localzone # $ pip install tzlocal

now = datetime.now(get_localzone())
print(now.isoformat('T'))

Работает как на Python 2, так и на 3.

Ответ 4

Я долго боролся с форматом даты и времени RFC3339, но нашел подходящее решение для преобразования date_string <= > datetime_object в обоих направлениях.

Вам нужны два разных внешних модуля, потому что один из них способен выполнять преобразование только в одном направлении (к сожалению):

сначала установите:

sudo pip install rfc3339
sudo pip install iso8601

затем включите:

import datetime     # for general datetime object handling
import rfc3339      # for date object -> date string
import iso8601      # for date string -> date object

Не нужно помнить, какой модуль для какого направления, я написал две простые вспомогательные функции:

def get_date_object(date_string):
  return iso8601.parse_date(date_string)

def get_date_string(date_object):
  return rfc3339.rfc3339(date_object)

который внутри вашего кода вы можете легко использовать следующим образом:

input_string = '1989-01-01T00:18:07-05:00'
test_date = get_date_object(input_string)
# >>> datetime.datetime(1989, 1, 1, 0, 18, 7, tzinfo=<FixedOffset '-05:00' datetime.timedelta(-1, 68400)>)

test_string = get_date_string(test_date)
# >>> '1989-01-01T00:18:07-05:00'

test_string is input_string # >>> True

Эврика! Теперь вы можете легко (ха-ха) использовать строки даты и строки даты в удобном для использования формате.

Ответ 5

Пакет pytz доступен для Python 2.X и 3.X. Он реализует конкретные подклассы tzinfo среди других сервисов, поэтому вам не нужно.

Чтобы добавить смещение UTC:   import datetime   import pytz

dt = datetime.datetime(2011, 12, 18, 20, 46, 00, 392227)
utc_dt = pytz.UTC.localize(dt)

И теперь это:

print utc_dt.isoformat()

будет печатать:

2011-12-18T20:46:00.392227+00:00

Ответ 6

Еще одна полезная утилита, с которой я только начал работать: dateutil библиотека для обработки часового пояса и синтаксического анализа даты. Рекомендуем вокруг SO, включая этот ответ

Ответ 7

Вы действительно можете использовать встроенный datetime. В виде @ruakh упоминает, есть примеры в страницу, которая показывает, как. Если вы посмотрите раздел tzinfo вы будете см. длинный пример, показывающий множество различных вариантов использования. Здесь код для одного вы ищете, что должно генерировать временную метку RFC 3339 UTC.

from datetime import tzinfo, timedelta, datetime
import time as _time

ZERO = timedelta(0)
STDOFFSET = timedelta(seconds=-_time.timezone)
if _time.daylight:
    DSTOFFSET = timedelta(seconds=-_time.altzone)
else:
    DSTOFFSET = STDOFFSET

DSTDIFF = DSTOFFSET - STDOFFSET


class LocalTimezone(tzinfo):

    def utcoffset(self, dt):
        if self._isdst(dt):
            return DSTOFFSET
        else:
            return STDOFFSET

    def dst(self, dt):
        if self._isdst(dt):
            return DSTDIFF
        else:
            return ZERO

    def tzname(self, dt):
        return _time.tzname[self._isdst(dt)]

    def _isdst(self, dt):
        tt = (dt.year, dt.month, dt.day,
              dt.hour, dt.minute, dt.second,
              dt.weekday(), 0, 0)
        stamp = _time.mktime(tt)
        tt = _time.localtime(stamp)
        return tt.tm_isdst > 0

Local = LocalTimezone()

d = datetime.now(Local)
print d.isoformat('T')

# which returns
# 2014-04-28T15:44:45.758506-07:00

Ответ 8

На современном (3.x) python для получения времени RFC 3339 UTC все, что вам нужно сделать, это использовать datetime и эту единственную строку (сторонние модули не нужны):

import datetime
datetime.datetime.now(datetime.timezone.utc).isoformat()

Результат примерно такой: "2019-06-13T15: 29: 28.972488 + 00: 00"

Эта строка ISO 8601 также совместима с RFC3339.