Search code examples
pythontimestamppython-datetime

Python datetime.datetime from time.structtime difference


I use feedparser to grab the entries from some RSS feeds. The entries have a published_parsed field which are parsed by feedparser into time.structtime.

I use this function to convert the time.structtime into a datetime.datetime:

def publishParsedToDatetime(structTime): 
    return datetime.datetime.fromtimestamp(time.mktime(structTime))

Input (structtime):

time.struct_time(tm_year=2015, tm_mon=8, tm_mday=1, tm_hour=20, tm_min=28, tm_sec=33, tm_wday=5, tm_yday=213, tm_isdst=0)

Output (datetime):

2015-08-01 21:28:33

I see a problem which could be timezone related, there is 1 hour difference between the structtime and the datetime values.

The structtime value is UTC. But the datetime.datetime value is neither UTC, nor my current timezone (CET, Central European Time, we observe Summertime, so we have UTC + 2hrs at the moment).

How can this be explained?


Solution

  • Actually, as explained in the documentation for datetime.fromtimestamp, it converts to local time by default:

    Return the local date and time corresponding to the POSIX timestamp, such as is returned by time.time(). If optional argument tz is None or not specified, the timestamp is converted to the platform’s local date and time, and the returned datetime object is naive

    The 1 hour difference can then be explained by the field tm_isdst=0 tells it to not use daylight savings (despite your local time zone using it).

    To see this more clearly, we construct two test cases

    import time, datetime
    
    # this is how your time object was constructed before
    tm_isdst = 0
    t = time.mktime((2015, 8, 1, 20, 28, 33, 5, 213, tm_isdst))
    print("Old conversion: {0}".format(datetime.datetime.fromtimestamp(t)))
    
    # this is what happens if you let mktime "divine" a time zone
    tm_isdst = -1
    t = time.mktime((2015, 8, 1, 20, 28, 33, 5, 213, tm_isdst))
    print("New conversion: {0}".format(datetime.datetime.fromtimestamp(t)))
    

    The output of this is as follows:

    Old conversion: 2015-08-01 21:28:33
    New conversion: 2015-08-01 20:28:33
    

    The problem then, you see, is that the structTime object being passed to your publishParsedToDatetime has tm_isdst=0 but the time stamp you wanted to parse was for a DST time zone.

    As you have already noted in another comment, the proper solution to this is probably to always use UTC in your back-end code, and only do time zone handling when showing the time to the user, or when reading user input.