代码之家  ›  专栏  ›  技术社区  ›  Tom Gruff

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

  •  36
  • Tom Gruff  · 技术社区  · 16 年前

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

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

    我情不自禁地觉得我错过了什么,有什么想法吗?

    4 回复  |  直到 7 年前
        1
  •  54
  •   user3850    12 年前

    如果你这样做的话,我想你可以省去一些方法调用:

    >>> 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() 国家:

    应该使用此方法来构造本地时间,而不是 而不是将TZINFO参数传递给日期时间构造函数。

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

    >>> 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年之前的日期没有任何保证。

        2
  •  24
  •   Community Mohan Dere    8 年前

    @hop's answer 从夏令时(DST)过渡到2012年4月1日的当天是否错误。修复它 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)
    
        3
  •  0
  •   Ignacio Vazquez-Abrams    16 年前

    设置TZ环境变量可以修改TimeZone python的日期和时间函数使用的内容。

    >>> 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)
    
        4
  •  0
  •   Jonathan Leffler    16 年前

    每个时区都有一个数字,例如US/Central=-6。这被定义为以小时为单位的从UTC的偏移量。因为0000是午夜,所以您可以使用此偏移量在任何时区中查找午夜UTC时的时间。我相信你可以用

     time.timezone

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

    时区

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

    因此,如果时间是正数(例如,如果芝加哥是午夜(时区值为+6),则为6000=6am UTC),则只需使用小时数。

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