Печать правильного времени с использованием часовых поясов, Python
Хорошо, у нас сегодня не хороший день.
Когда вы присоединяете правильный объект tzinfo к экземпляру datetime, а затем запускаете его strftime (), он по-прежнему выходит в UTC, по-видимому, игнорируя красивый объект tzinfo, который я к нему прикрепил.
# python 2.5.4 now = datetime.now () print now.strftime ("% a% b% d% X") # % X является "подходящим временным представителем языкового стандарта" pst = now.replace (tzinfo = Pacific) print pst.strftime ("% a% b% d% X")
Мы получаем:
Пн 18 янв 17:30:16 Пн 18 янв 17:30:16
Я обнаружил, что если я добавлю%z, я могу добавить разницу, которую он должен был вычислить:
Пн 18 января 17:32:38 Пн 18 января 17:32:38 -0800
Он просто указывает на "-8", как бы говоря, "ты делаешь это сам, фу".
Но я хочу, чтобы strftime () просто дал мне строку с ПРЕДВАРИТЕЛЬНЫМ МЕСТНЫМ ВРЕМЕНЕМ.
Как я могу заставить strftime () выполнять для меня математику вычитания часов, когда я выполняю strftime ()?
Полный код, который я использую ниже.
from datetime import tzinfo, timedelta, datetime
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
# A UTC class.
class UTC(tzinfo):
"""UTC"""
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
# A class building tzinfo objects for fixed-offset time zones.
# Note that FixedOffset(0, "UTC") is a different way to build a
# UTC tzinfo object.
class FixedOffset(tzinfo):
"""Fixed offset in minutes east from UTC."""
def __init__(self, offset, name):
self.__offset = timedelta(minutes = offset)
self.__name = name
def utcoffset(self, dt):
return self.__offset
def tzname(self, dt):
return self.__name
def dst(self, dt):
return ZERO
# A class capturing the platform's idea of local time.
import time as _time
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, -1)
stamp = _time.mktime(tt)
tt = _time.localtime(stamp)
return tt.tm_isdst > 0
Local = LocalTimezone()
# A complete implementation of current DST rules for major US time zones.
def first_sunday_on_or_after(dt):
days_to_go = 6 - dt.weekday()
if days_to_go:
dt += timedelta(days_to_go)
return dt
# In the US, DST starts at 2am (standard time) on the first Sunday in April.
DSTSTART = datetime(1, 4, 1, 2)
# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct.
# which is the first Sunday on or after Oct 25.
DSTEND = datetime(1, 10, 25, 1)
class USTimeZone(tzinfo):
def __init__(self, hours, reprname, stdname, dstname):
self.stdoffset = timedelta(hours=hours)
self.reprname = reprname
self.stdname = stdname
self.dstname = dstname
def __repr__(self):
return self.reprname
def tzname(self, dt):
if self.dst(dt):
return self.dstname
else:
return self.stdname
def utcoffset(self, dt):
return self.stdoffset + self.dst(dt)
def dst(self, dt):
if dt is None or dt.tzinfo is None:
# An exception may be sensible here, in one or both cases.
# It depends on how you want to treat them. The default
# fromutc() implementation (called by the default astimezone()
# implementation) passes a datetime with dt.tzinfo is self.
return ZERO
assert dt.tzinfo is self
# Find first Sunday in April & the last in October.
start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year))
end = first_sunday_on_or_after(DSTEND.replace(year=dt.year))
# Can't compare naive to aware objects, so strip the timezone from
# dt first.
if start <= dt.replace(tzinfo=None) < end:
return HOUR
else:
return ZERO
Eastern = USTimeZone(-5, "Eastern", "EST", "EDT")
#Central = USTimeZone(-6, "Central", "CST", "CDT")
#Mountain = USTimeZone(-7, "Mountain", "MST", "MDT")
Pacific = USTimeZone(-8, "Pacific", "PST", "PDT")
now = datetime.now()
print now.strftime( "%a %b %d %X %z" )
pst = now.replace( tzinfo=Pacific )
print pst.strftime( "%a %b %d %X %z" )
3 ответа
.replace
не вычисляет: он просто заменяет одно или несколько полей в новом возвращаемом объекте, копируя все остальные из объекта, к которому он обращен.
Если я правильно понимаю вашу ситуацию, вы начинаете с объекта datetime, который, как вы знаете (с помощью других средств), является UTC, но сам не знает об этом (имеет атрибут tzinfo: None
, что означает "я совершенно не знаю, в каком часовом поясе я нахожусь).
Итак, во- первых, вы создаете информацию о часовом поясе из вашего входного объекта, который является часовым поясом, чтобы сообщить ему, что он находится в часовом поясе UTC (все остальные поля просто копируются):
aware = naive.replace(tzinfo=utc)
Затем вы можете запросить вычисления для часовых поясов и, как следствие, распечатать:
print aware.astimezone(Pacific).strftime('%a %b %d %X %z')
С dt.replace(tzinfo=tz)
вы на самом деле не конвертируете значение времени, вы просто говорите: "Эй, нет, подождите, на самом деле это время было в PDT, а не в UTC". Вы, вероятно, захотите использовать datetime.astimezone(tz)
вместо.
Я думаю, что у Вима была правильная идея, просто задом наперед. Если вы хотите узнать, какое ваше время будет в UTC, используйте:
print pst.astimezone(UTC).strftime( "%a %b %d %X" )
Вам нужно будет найти определение для класса часового пояса UTC. Я понимаю, почему Python не хотел предоставлять реализацию по умолчанию для каждой возможной tzinfo, но UTC следовало включить в базовый пакет.