Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 420
pat Avatar asked Feb 21 '11 14:02

pat


People also ask

How do I create a UTC timestamp in Python?

You can use the datetime module to convert a datetime to a UTC timestamp in Python. If you already have the datetime object in UTC, you can the timestamp() to get a UTC timestamp. This function returns the time since epoch for that datetime object.

How do you find the timestamp in UTC?

Use the getTime() method to get a UTC timestamp, e.g. new Date(). getTime() . The method returns the number of milliseconds since the Unix Epoch and always uses UTC for time representation. Calling the method from any time zone returns the same UTC timestamp.

How do you convert datetime to UTC?

To convert the time in a non-local time zone to UTC, use the TimeZoneInfo. ConvertTimeToUtc(DateTime, TimeZoneInfo) method. To convert a time whose offset from UTC is known, use the ToUniversalTime method. If the date and time instance value is an ambiguous time, this method assumes that it is a standard time.

How do I convert UTC datetime to local datetime in Python?

This datetime object will have no timezone associated with it. Therefore assign the UTC timezone to this datetime object using replace(tzinfo=pytz. UTC) function. Convert the timezone of the datetime object to local timezone by calling the astimezone() function on datetime object.


1 Answers

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 ?

  • If you were using UTC (you are out of trouble):

    import calendar  def dt2ts(dt):     """Converts a datetime object to UTC timestamp      naive datetime will be considered UTC.      """      return calendar.timegm(dt.utctimetuple()) 
  • If you were NOT using UTC, welcome to hell.

    You have to make your datetime non-naïve prior to using the former function, by giving them back their intended timezone.

    You'll need the name of the timezone and the information about if DST was in effect when producing the target naïve datetime (the last info about DST is required for cornercases):

    import pytz     ## pip install pytz  mytz = pytz.timezone('Europe/Amsterdam')             ## Set your timezone  dt = mytz.normalize(mytz.localize(dt, is_dst=True))  ## Set is_dst accordingly 

    Consequences of not providing is_dst:

    Not using is_dst will generate incorrect time (and UTC timestamp) if target datetime was produced while a backward DST was put in place (for instance changing DST time by removing one hour).

    Providing incorrect is_dst will of course generate incorrect time (and UTC timestamp) only on DST overlap or holes. And, when providing also incorrect time, occuring in "holes" (time that never existed due to forward shifting DST), is_dst will give an interpretation of how to consider this bogus time, and this is the only case where .normalize(..) will actually do something here, as it'll then translate it as an actual valid time (changing the datetime AND the DST object if required). Note that .normalize() is not required for having a correct UTC timestamp at the end, but is probably recommended if you dislike the idea of having bogus times in your variables, especially if you re-use this variable elsewhere.

    and AVOID USING THE FOLLOWING: (cf: Datetime Timezone conversion using pytz)

    dt = dt.replace(tzinfo=timezone('Europe/Amsterdam'))  ## BAD !! 

    Why? because .replace() replaces blindly the tzinfo without taking into account the target time and will choose a bad DST object. Whereas .localize() uses the target time and your is_dst hint to select the right DST object.

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

like image 167
vaab Avatar answered Nov 13 '22 04:11

vaab