datetime versus aware
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
dt is naïve, check
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 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).
is_dst will of course generate incorrect
time (and UTC timestamp) only on DST overlap or holes. And, when
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 !!
.replace() replaces blindly the
taking into account the target time and will choose a bad DST object.
.localize() uses the target time and your
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.
time.mktime we can create an
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
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).
~ Answered on 2011-03-31 12:33:18