2010-01-18 34 views
9

ExtendsIn đúng thời gian bằng cách sử dụng múi giờ, Python

Ok, chúng tôi không có một ngày tốt lành hôm nay.

Khi bạn đính kèm đúng đối tượng tzinfo vào một trường hợp datetime, và sau đó bạn strftime() nó, nó STILL xuất hiện trong UTC, dường như bỏ qua đối tượng tzinfo đẹp mà tôi đính kèm với nó.

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

Chúng tôi nhận được:

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

tôi thấy nếu tôi thêm% z, tôi có thể thêm sự khác biệt của nó cho là đã tính toán:

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

Nó chỉ đinh trên -8 ở đó, như thể muốn nói, "bạn làm điều đó cho mình, foo."

Nhưng tôi muốn strftime() chỉ đơn giản là cho tôi một chuỗi VỚI THỜI GIAN ĐỊA ĐIỂM CHÍNH XÁC.

Làm thế nào tôi có thể nhận được strftime() để làm phép tính trừ giờ cho tôi khi tôi strftime() nó?

Mã đầy đủ tôi đang sử dụng ở bên dưới.

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

để có được thời gian hiện tại trong một múi giờ nhất định: 'now = datetime.now (Thái Bình Dương)' – jfs

Trả lời

13

.replace không tính toán: chỉ cần thay thế một hoặc nhiều trường trong đối tượng được trả về mới, trong khi sao chép tất cả các đối tượng khác từ đối tượng được gọi.

Nếu tôi hiểu chính xác tình huống của bạn, bạn bắt đầu với đối tượng ngày giờ mà bạn biết (thông qua các phương tiện khác) là UTC, nhưng không biết chính nó (có thuộc tính tzinfo là None, có nghĩa là "Tôi" Tôi hoàn toàn không biết gì về múi giờ tôi đang dùng)

Vì vậy, trước tiên, bạn hãy nhận biết múi giờ từ đối tượng ngòai múi giờ đầu vào của bạn, để thông báo rằng múi giờ đó ở múi giờ UTC (tất cả các trường khác chỉ cần được sao chép lại):

aware = naive.replace(tzinfo=utc) 

Sau đó, bạn có thể yêu cầu tính toán liên quan đến các múi giờ, và in ấn trong hậu quả:

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

Với dt.replace(tzinfo=tz) bạn không thực sự chuyển đổi giá trị thời gian, bạn chỉ cần nói 'hey không, chờ, lần này đã thực sự trong PDT, không phải trong UTC'. Có thể bạn sẽ muốn sử dụng datetime.astimezone(tz) để thay thế.

+0

'dt.replace (tzinfo = tz) 'có thể cung cấp cho bạn một đối tượng' datetime' nhận thức, trong khi 'datetime.astimezone (tz) 'sẽ cung cấp cho bạn bất kỳ loại nào bạn đã có trước đây (cho dù đó là nhận thức hoặc ngây thơ). – Shule

2

Tôi nghĩ rằng Wim had the right idea, chỉ cần lùi lại. Nếu bạn muốn biết thời gian của bạn sẽ ở dạng UTC, hãy sử dụng:

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

Bạn sẽ phải tìm hiểu định nghĩa cho lớp múi giờ UTC. Tôi hiểu lý do tại sao Python không muốn cung cấp một thực thi mặc định của mọi tzinfo có thể, nhưng UTC nên được bao gồm trong gói cơ sở.

Các vấn đề liên quan