Search code examples
pythontimezonedstpytzlocaltime

How to find next day's Unix timestamp for same hour, including DST, in Python?


In Python, I can find the Unix time stamp of a local time, knowing the time zone, like this (using pytz):

>>> import datetime as DT
>>> import pytz
>>> mtl = pytz.timezone('America/Montreal')
>>> naive_time3 = DT.datetime.strptime('2013/11/03', '%Y/%m/%d')
>>> naive_time3
datetime.datetime(2013, 11, 3, 0, 0)
>>> localized_time3 = mtl.localize(naive_time3)
>>> localized_time3
datetime.datetime(2013, 11, 3, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>)
>>> localized_time3.timestamp()
1383451200.0

So far, so good. naive_time is not aware of the time zone, whereas localized_time knows its midnight on 2013/11/03 in Montréal, so the (UTC) Unix time stamp is good. This time zone is also my local time zone and this time stamp seems right:

$ date -d @1383451200
Sun Nov  3 00:00:00 EDT 2013

Now, clocks were adjusted one hour backward November 3rd at 2:00 here in Montréal, so we gained an extra hour that day. This means that there were, here, 25 hours between 2013/11/03 and 2013/11/04. This shows it:

>>> naive_time4 = DT.datetime.strptime('2013/11/04', '%Y/%m/%d')
>>> localized_time4 = mtl.localize(naive_time4)
>>> localized_time4
datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EST-1 day, 19:00:00 STD>)
>>> (localized_time4.timestamp() - localized_time3.timestamp()) / 3600
25.0

Now, I'm looking for an easy way to get the localized_time4 object from localized_time3, knowing I want to get the next localized day at the same hour (here, midnight). I tried timedelta, but I believe it's not aware of time zones or DST:

>>> localized_time4td = localized_time3 + DT.timedelta(1)
>>> localized_time4td
datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>)
>>> (localized_time4td.timestamp() - localized_time3.timestamp()) / 3600
24.0

My purpose is to get informations about log entries that are stored with their Unix timestamp for each local day. Of course, if I use localized_time3.timestamp() and add 24 * 3600 here (which will be the same as localized_time4td.timestamp()), I will miss all log entries that happened between localized_time4td.timestamp() and localized_time4td.timestamp() + 3600.

In other words, the function or method I'm looking for should know when to add 25 hours, 24 hours or 23 hours sometimes to a Unix time stamp, depending on when DST shifts happen.


Solution

  • Without using a new package:

    def add_day(x):
        d = x.date()+DT.timedelta(1)
        return mtl.localize(x.replace(year=d.year, month=d.month, day=d.day, tzinfo=None))
    

    Full script:

    import datetime as DT
    import pytz
    import calendar
    mtl = pytz.timezone('America/Montreal')
    naive_time3 = DT.datetime.strptime('2013/11/03', '%Y/%m/%d')
    print repr(naive_time3)
    #datetime.datetime(2013, 11, 3, 0, 0)
    localized_time3 = mtl.localize(naive_time3)
    print repr(localized_time3)
    #datetime.datetime(2013, 11, 3, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>)
    print calendar.timegm(localized_time3.utctimetuple())
    #1383451200.0
    def add_day(x):
        d = x.date()+DT.timedelta(1)
        return mtl.localize(x.replace(year=d.year, month=d.month, day=d.day, tzinfo=None))
    print repr(add_day(localized_time3))
    #datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EST-1 day, 19:00:00 STD>)
    

    (calendar is for Python2.)