如何获得给定时区的“午夜”的UTC时间?

我现在所能想到的最好的就是这个怪物:

>>> 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(),因为这将使用服务器的时区,而不是用户的时区。

我不禁感到我错过了什么,有什么想法?

我认为你可以削减一些方法调用,如果你这样做:

 >>> from datetime import datetime >>> datetime.now(pytz.timezone("Australia/Melbourne")) \ .replace(hour=0, minute=0, second=0, microsecond=0) \ .astimezone(pytz.utc) 

但是…在代码中存在一个比美学更大的问题:在夏令时或夏令时切换的时候会出现错误的结果。

这是因为datetime构造函数和replace()都不考虑DST更改。

例如:

 >>> 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! 

但是, tz.localize()的文档声明:

这个方法应该用来构造本地时间,而不是将一个tzinfoparameter passing给一个datetime构造函数。

因此,你的问题是这样解决的:

 >>> 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年之前没有保证。

从Daylight Saving Time(DST)例如2012年4月1日过渡到当天, @ hop的答案是错误的。要解决它,可以使用tz.localize()

 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) 

同评论一样:

 #!/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) 

设置TZ环境variables可以修改Python的date和时间函数使用的时区。

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

每个时区都有一个数字,例如US / Central = -6。 这被定义为距UTC的时间偏移量。 由于0000是午夜,所以您可以简单地使用此偏移量来查找在UTC时间午夜时的任何时间段的时间。 要访问,我相信你可以使用

  time.timezone 

根据The Python Docs ,time.timezone实际上给出了这个数字的负值:

time.timezone

UTC(西部大部分地区为负值,美国为正值,英国为零)的本地(非DST)时区的偏移量。

所以,如果这个数字是正数(如果是在芝加哥的午夜(有6个时区的数值),那么它就是6000 =上午6点UTC)。

如果数字是负数,则从24中减去。例如,柏林会给-1,所以24 – 1 => 2300 = 11pm。