簡體   English   中英

將時區感知日期字符串轉換為UTC並返回Python

[英]Converting timezone-aware date string to UTC and back in Python

我正在將國家氣象服務警報提要解析為Web應用程序。 我想在達到到期時清除警報。 我還想以他們所屬的地理區域的本地時間格式顯示到期時間。

警報覆蓋整個美國,所以我認為最好的方法是存儲和比較UTC時間戳的時間。 到期時間以字符串形式到達Feed中: 2011-09-09T22:12:00-04:00

我正在使用Labix dateutils包以時區感知的方式解析字符串:

>>> from dateutil.parser import parse
>>> d = parse("2011-09-18T15:52:00-04:00")
>>> d
datetime.datetime(2011, 9, 18, 15, 52, tzinfo=tzoffset(None, -14400))

我還能夠在幾小時內捕獲UTC偏移量:

>>> offset_hours = (d.utcoffset().days * 86400 + d.utcoffset().seconds) / 3600
>>> offset_hours
-4

使用datetime.utctimetuple()time.mktime()方法,我能夠將解析的日期轉換為UTC時間戳:

>>> import time
>>> expiration_utc_ts = time.mktime(d.utctimetuple())
>>> expiration_utc_ts
1316393520.0

在這一點上,我感覺非常好,我能夠將原始字符串轉換為表示UTC中的到期時間的時間戳。 我能夠將當前時間作為UTC時間戳與到期時間進行比較,並確定是否需要清除它:

>>> now_utc_ts = time.mktime(time.gmtime())
>>> now_utc_ts
1316398744.0
>>> now_utc_ts >= expiration_tc_ts
True

我遇到的困難是嘗試將存儲的UTC時間戳轉換回原始的本地化格式。 我有從原始轉換存儲的偏移小時數和我解析的字符串來存儲時區標簽:

>>> print offset_hours
-4
>>> print timezone
EDT

我想將UTC時間戳轉換回本地格式化的時間,但將其轉換回datetime時間似乎不起作用:

>>> import datetime
>>> datetime.datetime.fromtimestamp(expiration_utc_ts) + datetime.timedelta(hours=offset_hours)
datetime.datetime(2011, 9, 18, 16, 52) # The hour is 16 but it should be 15

看起來它已經過了一個小時。 我不確定錯誤的引入位置? 我把另一個測試放在一起,得到了類似的結果

>>> # Running this at 21:29pm EDT
>>> utc_now = datetime.datetime.utcnow()
>>> utc_now_ts = time.mktime(right_now.utctimetuple())
>>> datetime.datetime.fromtimestamp(utc_now_ts)
datetime.datetime(2011, 9, 18, 22, 29, 47) # Off by 1 hour

有人能幫助我找到我的錯誤嗎? 我不確定這是否是夏令時問題? 我遇到了一些讓我相信它可能試圖將我的日期和時間本地化的東西但是在這一點上我很難過。 我希望以時區無關的方式進行所有這些計算/比較。

問題是夏令時被應用了兩次。

一個簡單的例子:

>>> time_tuple = datetime(2011,3,13,2,1,1).utctimetuple()
time.struct_time(tm_year=2011, tm_mon=3, tm_mday=13, tm_hour=2, tm_min=1, tm_sec=1, tm_wday=6, tm_yday=72, tm_isdst=0)
>>> datetime.fromtimestamp(time.mktime(time_tuple))
datetime.datetime(2011, 3, 13, 3, 1, 1)

我很確定故障在於time.mktime() 正如它在文檔中所說:

這是localtime()的反函數。 它的參數是struct_time或完整的9元組(因為需要dst標志;如果它是未知的,則使用-1作為dst標志),它以本地時間而不是UTC表示時間。 它返回一個浮點數,以便與time()兼容。 如果輸入值不能表示為有效時間,則會引發OverflowError或ValueError(這取決於Python或底層C庫是否捕獲到無效值)。 它可以生成時間的最早日期取決於平台。

當您將時間元組傳遞給time.mktime() ,它需要一個關於時間是否為夏令時的標志。 正如您在上面所看到的, utctimetuple()返回一個標記為0標志的元組,正如它在文檔中所說的那樣:

如果datetime實例d是天真的,則與d.timetuple()相同,不同之處在於無論d.dst()返回什么,tm_isdst都被強制為0。 DST在UTC時間內從未生效。

如果d知道,則通過減去d.utcoffset()將d標准化為UTC時間,並返回標准化時間的time.struct_time。 tm_isdst強制為0.請注意,如果d.year為MINYEAR或MAXYEAR且UTC調整溢出一年邊界,則結果的tm_year成員可能為MINYEAR-1或MAXYEAR + 1。

既然你告訴time.mktime()你的時間不是DST,它的工作是將所有時間轉換成當地時間,並且它是你所在地區的當前夏令時,它會增加一個小時來實現夏令時。 因此結果。


雖然我沒有方便的帖子,但我在幾天前遇到了一種方法,可以在當地時間將時區感知的日期時間轉換為天真的日期時間。 對於您的應用程序而言,這可能比您當前所做的更好(使用優秀的pytz模塊):

import pytz
def convert_to_local_time(dt_aware):
    tz = pytz.timezone('America/Los_Angeles') # Replace this with your time zone string
    dt_my_tz = dt_aware.astimezone(tz)
    dt_naive = dt_my_tz.replace(tzinfo=None)
    return dt_naive

將'America / LosAngeles'替換為您自己的時區字符串,您可以在pytz.all_timezones找到pytz.all_timezones

datetime.fromtimestamp()是從POSIX時間戳獲取本地時間的正確方法。 您的問題中的問題是您使用不正確的time.mktime()將感知日期時間對象轉換為POSIX時間戳。 是正確的方法之一

expiration_utc_ts = (d - datetime(1970, 1, 1, tzinfo=utc)).total_seconds()
local_dt = datetime.fromtimestamp(expiration_utc_ts)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM