2010-01-18 9 views
23

Jak ustawić strefę czasową instancji datetime, która właśnie wyszła z magazynu danych?atrybut "tzinfo" obiektów 'datetime.datetime' nie jest zapisywalny

Po pierwszym uruchomieniu jest w UTC. Chcę to zmienić na EST.

Próbuję, na przykład:

class Book(db.Model): 
    creationTime = db.DateTimeProperty() 

Kiedy książka jest pobierany, chcę natychmiast ustawić jego tzinfo:

book.creationTime.tzinfo = EST 

Gdzie I use this example dla mojego obiektu EST

Jednak otrzymuję:

 
attribute 'tzinfo' of 'datetime.datetime' objects is not writable 

Widziałem wiele odpowiedzi, które zalecają pytz i python-dateutil, ale naprawdę chcę odpowiedzi na to pytanie.

Odpowiedz

38

datetime „s obiekty są niezmienne, więc nie można zmienić żadnego z ich atrybutami - zrobisz nowy Przedmiotem niektóre atrybuty takie same, a niektóre inne, i przypisać go do tego, co trzeba, aby go przypisać.

to jest w Twoim przypadku, zamiast

book.creationTime.tzinfo = EST 

trzeba kodować

book.creationTime = book.creationTime.replace(tzinfo=EST) 
+0

uwaga: nie konwertuje z strefy czasowej UTC do EST (* "po raz pierwszy pojawia się w UTC. Chcę ją zmienić na EST." *). Czas pozostaje taki sam. Aby przekonwertować, można użyć 'book.creationTime.astimezone (EST)'. – jfs

0

To, czego chcesz, znajduje się w tym miejscu w numerze docs.

from datetime import tzinfo, timedelta, datetime 

ZERO = timedelta(0) 
HOUR = timedelta(hours=1) 
DSTSTART = datetime(1, 4, 1, 2) 
DSTEND = datetime(1, 10, 25, 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 

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 

now = datetime.now() 
print now 
print now.tzinfo 

Eastern = USTimeZone(-5, 'Eastern', 'EST', 'EDT') 
now_tz_aware = now.replace(tzinfo=Eastern) 
print now_tz_aware 

wyjściowa:

2010-01-18 17:08:02.741482 
None 
2010-01-18 17:08:02.741482-05:00 
+2

to ledwie bardzo pouczające. Mógłbyś wytłumaczyć tyle samo, mówiąc, że użyjesz datetime.replace (tzinfo = ...) - ale nie wyjaśniłeś, jak powinien on dostać Tzinfo, którego chce, po prostu nałożyłeś na strefę czasową EST/EDT. – Auspex

5

Jeśli otrzymujesz datetime, który jest w EST, ale nie ma jej zestaw pól tzinfo użyć dt.replace(tzinfo=tz) przypisać tzinfo bez zmiany czasu. (Twoja baza danych powinna to dla ciebie zrobić.)

Jeśli otrzymujesz datetime w UDT, a chcesz to w EST, potrzebujesz astimezone. http://docs.python.org/library/datetime.html#datetime.datetime.astimezone

W przeważającej większości przypadków baza danych powinna przechowywać i zwracać dane w UDT, i nie powinieneś używać zastępowania (z wyjątkiem przypuszczalnego przypisania Tzinfo).

+1

Przez "UDT" masz na myśli "UTC", zgadza się? – Will

Powiązane problemy