pythondatetimetimestamputc

get UTC timestamp in python with datetime


Is there a way to get the UTC timestamp by specifying the date? What I would expect:

datetime(2008, 1, 1, 0, 0, 0, 0)

should result in

 1199145600

Creating a naive datetime object means that there is no time zone information. If I look at the documentation for datetime.utcfromtimestamp, creating a UTC timestamp means leaving out the time zone information. So I would guess, that creating a naive datetime object (like I did) would result in a UTC timestamp. However:

then = datetime(2008, 1, 1, 0, 0, 0, 0)
datetime.utcfromtimestamp(float(then.strftime('%s')))

results in

2007-12-31 23:00:00

Is there still any hidden time zone information in the datetime object? What am I doing wrong?


Solution

  • Naïve datetime versus aware datetime

    Default datetime objects are said to be "naïve": they keep time information without the time zone information. Think about naïve datetime as a relative number (ie: +4) without a clear origin (in fact your origin will be common throughout your system boundary).

    In contrast, think about aware datetime as absolute numbers (ie: 8) with a common origin for the whole world.

    Without timezone information you cannot convert the "naive" datetime towards any non-naive time representation (where does +4 targets if we don't know from where to start ?). This is why you can't have a datetime.datetime.toutctimestamp() method. (cf: http://bugs.python.org/issue1457227)

    To check if your datetime dt is naïve, check dt.tzinfo, if None, then it's naïve:

    datetime.now()        ## DANGER: returns naïve datetime pointing on local time
    datetime(1970, 1, 1)  ## returns naïve datetime pointing on user given time
    

    I have naïve datetimes, what can I do ?

    You must make an assumption depending on your particular context: The question you must ask yourself is: was your datetime on UTC ? or was it local time ?

    OLD incorrect answer (thanks @J.F.Sebastien for bringing this up):

    Hopefully, it is quite easy to guess the timezone (your local origin) when you create your naive datetime object as it is related to the system configuration that you would hopefully NOT change between the naive datetime object creation and the moment when you want to get the UTC timestamp. This trick can be used to give an imperfect question.

    By using time.mktime we can create an utc_mktime:

    def utc_mktime(utc_tuple):
        """Returns number of seconds elapsed since epoch
    
        Note that no timezone are taken into consideration.
    
        utc tuple must be: (year, month, day, hour, minute, second)
    
        """
    
        if len(utc_tuple) == 6:
            utc_tuple += (0, 0, 0)
        return time.mktime(utc_tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0))
    
    def datetime_to_timestamp(dt):
        """Converts a datetime object to UTC timestamp"""
    
        return int(utc_mktime(dt.timetuple()))
    

    You must make sure that your datetime object is created on the same timezone than the one that has created your datetime.

    This last solution is incorrect because it makes the assumption that the UTC offset from now is the same than the UTC offset from EPOCH. Which is not the case for a lot of timezones (in specific moment of the year for the Daylight Saving Time (DST) offsets).