How do I get the UTC time of “midnight” for a given timezone?
我现在能想到的最好的办法就是这个怪物:
1 2 3 4 5 6 7 | >>> datetime.utcnow() \ ... .replace(tzinfo=pytz.UTC) \ ... .astimezone(pytz.timezone("Australia/Melbourne")) \ ... .replace(hour=0,minute=0,second=0,microsecond=0) \ ... .astimezone(pytz.UTC) \ ... .replace(tzinfo=None) datetime.datetime(2008, 12, 16, 13, 0) |
也就是说,用英语获取当前时间(UTC),将其转换为其他时区,将时间设置为午夜,然后转换回UTC。
我不仅仅使用now()或localtime(),因为这将使用服务器的时区,而不是用户的时区。
我情不自禁地觉得我错过了什么,有什么想法吗?
如果你这样做的话,我想你可以省去一些方法调用:
1 2 3 4 | >>> from datetime import datetime >>> datetime.now(pytz.timezone("Australia/Melbourne")) \ .replace(hour=0, minute=0, second=0, microsecond=0) \ .astimezone(pytz.utc) |
但是……在你的代码中有一个比美学更大的问题:在转换为夏令时或从夏令时转换为夏令时的那天,它会给出错误的结果。
原因是,无论是datetime构造函数还是
例如:
1 2 3 4 5 6 7 | >>> now = datetime(2012, 4, 1, 5, 0, 0, 0, tzinfo=pytz.timezone("Australia/Melbourne")) >>> print now 2012-04-01 05:00:00+10:00 >>> print now.replace(hour=0) 2012-04-01 00:00:00+10:00 # wrong! midnight was at 2012-04-01 00:00:00+11:00 >>> print datetime(2012, 3, 1, 0, 0, 0, 0, tzinfo=tz) 2012-03-01 00:00:00+10:00 # wrong again! |
但是,
This method should be used to construct localtimes, rather
than passing a tzinfo argument to a datetime constructor.
因此,您的问题是这样解决的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> import pytz >>> from datetime import datetime, date, time >>> tz = pytz.timezone("Australia/Melbourne") >>> the_date = date(2012, 4, 1) # use date.today() here >>> midnight_without_tzinfo = datetime.combine(the_date, time()) >>> print midnight_without_tzinfo 2012-04-01 00:00:00 >>> midnight_with_tzinfo = tz.localize(midnight_without_tzinfo) >>> print midnight_with_tzinfo 2012-04-01 00:00:00+11:00 >>> print midnight_with_tzinfo.astimezone(pytz.utc) 2012-03-31 13:00:00+00:00 |
不过,对1582年之前的日期没有任何保证。
@从夏令时(DST)过渡到2012年4月1日时,Hop的回答是错误的。要修复它,可以使用cx1〔1〕:
1 2 3 4 | tz = pytz.timezone("Australia/Melbourne") today = datetime.now(tz).date() midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None) utc_dt = midnight.astimezone(pytz.utc) |
与注释相同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/usr/bin/env python from datetime import datetime, time import pytz # pip instal pytz tz = pytz.timezone("Australia/Melbourne") # choose timezone # 1. get correct date for the midnight using given timezone. today = datetime.now(tz).date() # 2. get midnight in the correct timezone (taking into account DST) #NOTE: tzinfo=None and tz.localize() # assert that there is no dst transition at midnight (`is_dst=None`) midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None) # 3. convert to UTC (no need to call `utc.normalize()` due to UTC has no # DST transitions) fmt = '%Y-%m-%d %H:%M:%S %Z%z' print midnight.astimezone(pytz.utc).strftime(fmt) |
使用dateutil.tz比pytz更简单:
1 2 3 4 5 6 7 8 | >>>import datetime >>>import dateutil.tz >>>midnight=(datetime.datetime .now(dateutil.tz.gettz('Australia/Melbourne')) .replace(hour=0, minute=0, second=0, microsecond=0) .astimezone(dateutil.tz.tzutc())) >>>print(midnight) 2019-04-26 14:00:00+00:00 |
TZINFO文档推荐了自Python3.6以来的dateutil.tz。来自dateutil.tz的Tzinfo对象不存在DST等异常的问题,而不需要pytz的本地化功能。使用用户3850中的示例:
1 2 3 4 | >>> now = (datetime.datetime(2012, 4, 1, 5, ... tzinfo = dateutil.tz.gettz('Australia/Melbourne'))) >>> print(now.replace(hour = 0).astimezone(dateutil.tz.tzutc())) 2012-03-31 13:00:00+00:00 |
每个时区都有一个数字,例如US/Central=-6。这被定义为以小时为单位的从UTC的偏移量。因为0000是午夜,所以您可以使用此偏移量在任何时区中查找午夜UTC时的时间。为了达到这个目的,我相信你可以使用
1 | time.timezone |
。
根据python文档,time.timezone实际上给出了这个数字的负值:
time.timezone
The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK).
< /块引用>< /块引用>
因此,如果时间是正数(例如,如果芝加哥是午夜(时区值为+6),则为6000=6am UTC),则只需使用小时数。
如果数字为负数,则从24中减去。例如,柏林会给出-1,所以24-1=>2300=11pm。
设置TZ环境变量可以修改TimeZone python的日期和时间函数使用的内容。
1
2
3
4
5
6
7 >>> time.gmtime()
(2008, 12, 17, 1, 16, 46, 2, 352, 0)
>>> time.localtime()
(2008, 12, 16, 20, 16, 47, 1, 351, 0)
>>> os.environ['TZ']='Australia/Melbourne'
>>> time.localtime()
(2008, 12, 17, 12, 16, 53, 2, 352, 1)