2012-04-24 11 views
10

Długo szukam zbyt długo w datach/strefach czasowych w Pythonie i myślałem, że ktoś może mi pomóc.Python pass tzinfo do naiwnej datetime bez pyta

Zasadniczo chcę przeprowadzić konwersję w UTC i uwzględnić zmiany czasu letniego.

Utworzyłem następujące tzinfo klasy z jednego z tutoriali Python (nie 100% dokładne wiem, ale to nie jest konieczne):

from datetime import tzinfo, timedelta, datetime 

ZERO = timedelta(0) 
HOUR = timedelta(hours=1) 

def first_sunday_on_or_after(dt): 
    days_to_go = 6 - dt.weekday() 
    if days_to_go: 
     dt += timedelta(days_to_go) 
    return dt 

DSTSTART_2007 = datetime(1, 3, 8, 2) 
DSTEND_2007 = datetime(1, 11, 1, 1) 
DSTSTART_1987_2006 = datetime(1, 4, 1, 2) 
DSTEND_1987_2006 = datetime(1, 10, 25, 1) 
DSTSTART_1967_1986 = datetime(1, 4, 24, 2) 
DSTEND_1967_1986 = DSTEND_1987_2006 

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 start and end times for US DST. For years before 1967, return 
     # ZERO for no DST. 
     if 2006 < dt.year: 
      dststart, dstend = DSTSTART_2007, DSTEND_2007 
     elif 1986 < dt.year < 2007: 
      dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006 
     elif 1966 < dt.year < 1987: 
      dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986 
     else: 
      return ZERO 

     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 

Z drugiej strony mam dowolny date obiekt w EST i chcę poznać liczbę godzin, które różnią się, biorąc pod uwagę DST.

Próbowałem coś takiego:

>>> Eastern = ustimezone.USTimeZone(-5, "Eastern", "EST", "EDT") 
>>> x = datetime.date.today() # I actually get an arbitrary date but this is for the example 
>>> x_dt = datetime.datetime.combine(x, datetime.time()) 
>>> x_dt_tz = x_dt.astimezone(Eastern) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: astimezone() cannot be applied to a naive datetime 

Widziałem kilka postów, którzy mówią do korzystania z modułu localizepytz, ale niestety nie jestem w stanie wykorzystać dodatkowe moduły, więc niemożliwe, aby użyć pyzt

Czy ktoś wie, w jaki sposób uzyskać ten naiwny datetime do obiektu z timezonem bez używania pytz?

+1

x_dt.replace (tzinfo = Wschodniej) może być? Z czytania: http://groups.google.com/group/google-appengine/browse_thread/thread/17add9b3070aad7e/b995fe7e1f16cd4e –

+1

@skyl perfect, x_dt.replace (tzinfo = Eastern) .utcoffset() zwraca datetime.timedelta (-1 , 72000), co odpowiada -4 godzin! Wydaje się to tak zawiłe z powodu tak prostej rzeczy, ale dzięki za pomoc, powinieneś opublikować ją jako odpowiedź, a ja ją zaakceptuję. –

+0

obsługa DST bez 'pytz' jest jak obsługa wielu języków bez użycia Unicode. Można to zrobić, ale wynik będzie nieprawidłowy w wielu przypadkach. – jfs

Odpowiedz

7

Użyj x_dt.replace(tzinfo=Eastern) (found from this Google Groups thread).

x_dt.replace(tzinfo=Eastern).utcoffset() zwraca datetime.timedelta(-1, 72000) co odpowiada -4 godzin! (od komentarza pytania)

11

Co jest warte, odpowiedź @skyl jest mniej więcej równoważna z tym, co robi pytz.

Oto odpowiednie źródło pytz. To właśnie nazywa replace na obiekcie datetime z tzinfo kwarg:

def localize(self, dt, is_dst=False): 
    '''Convert naive time to local time''' 
    if dt.tzinfo is not None: 
     raise ValueError('Not naive datetime (tzinfo is already set)') 
    return dt.replace(tzinfo=self) 
+2

+1 za znalezienie źródła –

+0

@CharlesMenguy: nie, to nie jest to, co 'pytz' robi dla stref czasowych z DST (*" Chcę wykonać konwersję w UTC i biorąc pod uwagę zmiany czasu letniego. "*). Możesz użyć '.replace()' tylko ze stałymi przesuniętymi strefami czasowymi, takimi jak UTC (ta sama przesunięcie UTC od początku czasów do samego końca). – jfs

Powiązane problemy