2010-01-18 13 views
9

Extendsstampa corretta di tempo che utilizzano fusi orari, Python

Ok, non stanno avendo una buona giornata di oggi.

Quando si collega l'oggetto tzinfo corretto a un'istanza datetime, e quindi lo si strftime() esso, ANCORA esce in UTC, apparentemente ignorando il bellissimo oggetto tzinfo ad esso collegato.

 
    # 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") 

otteniamo:

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

ho trovato se aggiungo% z, posso aggiungere la differenza sua presunta di aver calcolato:

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

It pochi chiodini sul -8 lì, come per dire "fai tu stesso, foo".

Ma voglio che strftime() mi dia semplicemente una stringa CON TEMPO LOCALE PRECOMPUTATO.

Come posso ottenere strftime() per fare la matematica di sottrazione dell'ora per me quando lo strftime()?

Il codice completo che sto utilizzando è di seguito.

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

per ottenere l'ora corrente in un determinato fuso orario: 'ora = datetime.now (Pacifico)' ' – jfs

risposta

13

.replace non esegue calcoli: semplicemente sostituisce uno o più campi nel nuovo oggetto restituito, mentre copia tutti gli altri dall'oggetto su cui è chiamato.

Se ho capito bene la tua situazione, si inizia con un oggetto datetime che si sa (con altri mezzi) è UTC, ma non sa che si (si ha un attributo tzinfo di None, che significa "I' m totalmente all'oscuro riguardo a ciò che fuso orario sono in).

Quindi, prima, si effettua un fuso orario-aware dal vostro input oggetto fuso orario naive, al fine di informarlo che è in UTC fuso orario (tutti gli altri campi appena copiata):

aware = naive.replace(tzinfo=utc) 

Poi, è possibile richiedere calcoli per quanto riguarda i fusi orari, e la stampa di conseguenza:

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

Con dt.replace(tzinfo=tz) non sei davvero convertire il valore del tempo, si sta solo dicendo 'Ehi no, aspetta, questa volta era in realtà in PDT, non in UTC'. Probabilmente vorrai usare datetime.astimezone(tz).

+0

dt.replace (tzinfo = tz) 'può darti un oggetto' datetime' consapevole, mentre 'datetime.astimezone (tz) 'ti darà tutto il tipo che avevi prima (che sia consapevole o ingenuo). – Shule

2

Penso che Wim had the right idea, appena indietro. Se volete sapere che cosa il vostro tempo sarebbe in UTC, utilizzare:

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

Dovrete scavare una definizione per una classe UTC fuso orario. Capisco perché Python non abbia voluto fornire un'implementazione predefinita di tutti i possibili tzinfo, ma l'UTC avrebbe dovuto essere incluso nel pacchetto base.