2010-01-18 2 views
9

Extendsпечати правильное время с помощью часовых поясов, Python

Ok, мы не имеющие хороший день сегодня.

Когда вы прикрепляете правильный объект tzinfo к экземпляру datetime, а затем вы strftime(), он STILL появляется в UTC, по-видимому игнорируя красивый объект tzinfo, который я привязал к нему.

 
    # python 2.5.4 
    now = datetime.now() 
    print now.strftime("%a %b %d %X") # %X is "locale's appropriate time rep" 

    pst = now.replace(tzinfo=Pacific) 
    print pst.strftime("%a %b %d %X") 

Получаем:

 
Mon Jan 18 17:30:16 
Mon Jan 18 17:30:16 

Я нашел, если я добавлю% г, я могу добавить разницу его предполагается вычислили:

 
Mon Jan 18 17:32:38 
Mon Jan 18 17:32:38 -0800 

он просто сбруя на -8 там, как бы говоря: «вы делаете это сами, foo».

Но я хочу, чтобы 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") 
+0

, чтобы получить текущее время в данном часовом поясе: 'теперь = DateTime.Now (Pacific)' ' – jfs

ответ

13

.replace не вычисляет: это просто заменяет одно или несколько полей в новом возвращенном объекте, копируя все остальные из объекта, на который он вызван.

Если я правильно понимаю вашу ситуацию правильно, вы начинаете с объектом даты и времени, которые вы знаете (с помощью других средств) является UTC, но не знает, что само по себе (это имеет атрибут tzinfo из None, что означает «я м полностью невежественны относительно того, что часовой пояса я в).

Итак, первого, вы делаете часовой пояс-Aware от вашего входного временной зоны наивного объекта, для того, чтобы проинформировать его о том, что это в часовом поясе UTC (все других поля просто скопируйте):

aware = naive.replace(tzinfo=utc) 

Тогда, вы можете запросить расчеты относительно часовых поясов, и печати в результате:

print aware.astimezone(Pacific).strftime('%a %b %d %X %z') 
5

С dt.replace(tzinfo=tz) вы на самом деле не преобразование значения времени, вы просто сказать: "Эй, нет, подождите, на этот раз был на самом деле в PDT, а не в UTC. Вместо этого вы, скорее всего, захотите использовать datetime.astimezone(tz).

+0

dt.replace (tzinfo = tz) 'может дать вам известный объект datetime, а' datetime.astimezone (tz) 'даст вам то, что у вас было раньше (известно ли это или наивно). – Shule

2

Я думаю, Wim had the right idea, только в обратном направлении. Если вы хотите знать, что ваше время будет в формате UTC, используйте:

print pst.astimezone(UTC).strftime("%a %b %d %X") 

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