301

I have a bunch of datetime objects and I want to calculate the number of seconds since a fixed time in the past for each one (for example since January 1, 1970).

import datetime
t = datetime.datetime(2009, 10, 21, 0, 0)

This seems to be only differentiating between dates that have different days:

t.toordinal()

How does one convert a datetime object to seconds?

starball
  • 20,030
  • 7
  • 43
  • 238
Nathan Lippi
  • 4,967
  • 5
  • 25
  • 29
  • 1
    related: [Converting `datetime.date` to UTC timestamp in Python](http://stackoverflow.com/a/8778548/4279) – jfs Jul 10 '15 at 20:23
  • 2
    I'd probably convert both to S since epoch and go from there: `int(t.timestamp())` – nerdwaller Nov 13 '15 at 20:41
  • for the opposite operation go here: [convert-seconds-since-epoch-to-a-datetime-object](https://stackoverflow.com/questions/3694487/in-python-how-do-you-convert-seconds-since-epoch-to-a-datetime-object) – Trevor Boyd Smith Dec 06 '18 at 19:00

13 Answers13

296

For the special date of January 1, 1970 there are multiple options.

For any other starting date you need to get the difference between the two dates in seconds. Subtracting two dates gives a timedelta object, which as of Python 2.7 has a total_seconds() function.

>>> (t-datetime.datetime(1970,1,1)).total_seconds()
1256083200.0

The starting date is usually specified in UTC, so for proper results the datetime you feed into this formula should be in UTC as well. If your datetime isn't in UTC already, you'll need to convert it before you use it, or attach a tzinfo class that has the proper offset.

As noted in the comments, if you have a tzinfo attached to your datetime then you'll need one on the starting date as well or the subtraction will fail; for the example above I would add tzinfo=pytz.utc if using Python 2 or tzinfo=timezone.utc if using Python 3.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • I prefer this method because it only requires a single import. – jathanism Oct 21 '11 at 17:30
  • Thanks for the help! (Chosen because it is the most general solution) – Nathan Lippi Oct 21 '11 at 18:38
  • 1
    Python now warns me: "TypeError: can't subtract offset-naive and offset-aware datetimes" What's the best solution to fix that? – Aaron Ash Apr 13 '13 at 00:47
  • 2
    @Charybdis, try `datetime.datetime(1970,1,1,tzinfo=pytz.utc)`. – Mark Ransom Apr 13 '13 at 01:00
  • 13
    Consider using: ``datetime.datetime.utcfromtimestamp(0)`` I've used this to get the 'epoch' easily. Note that epoch is not always the same on all systems. – D. A. Nov 05 '13 at 20:04
  • 3
    Be very careful with timezones here. I'm at UTC+2, which means that the output of `time.time()` and `datetime.now() - datetime(1970, 1, 1)` differ by 7200 seconds. Rather use `(t - datetime.datetime.fromtimestamp(0)).total_seconds()`. Do *not* use `utcfromtimestamp(0)` if you want to convert a datetime in your local timezone. – Carl Jul 09 '15 at 09:18
  • 2
    @D.A.: [Python does not support non-POSIX epochs](http://bugs.python.org/issue22356). All systems where python works use the same Epoch: 1970-01-01 00:00:00 UTC – jfs Jul 10 '15 at 20:24
  • @Carl: it is *also* wrong if utc_offset_at_1970 is different from utc_offset_now (as it is in many timezones). [Convert local time to utc time](http://stackoverflow.com/q/79797/4279) first then [use this answer to get POSIX timestamp](http://stackoverflow.com/a/8778548/4279). – jfs Jul 10 '15 at 20:27
  • @MarkRansom: the formula produces POSIX timestamp iff `t` is a UTC time. – jfs Jul 10 '15 at 20:31
  • @J.F.Sebastian good point, I should have mentioned that in the answer. The question used a naive datetime object so you can't make any assumptions about its time zone. – Mark Ransom Jul 10 '15 at 21:03
  • @J.F.Sebastian I finally got around to adding the UTC qualifiers to this answer, thanks for the jab in the other question. – Mark Ransom Aug 24 '15 at 23:22
  • @MarkRansom: drop *"usually specified in UTC"*. It is not a matter of preference. POSIX epoch that is also used on Windows is always: 1970-01-01 UTC. `t` must be in utc for the formula to make sense. – jfs Aug 25 '15 at 08:47
  • @J.F.Sebastian my answer is applicable to more than just the POSIX epoch, so it stays the way it is. – Mark Ransom Aug 25 '15 at 11:50
  • This is working nicely for me, but what about if you want to check whether the next day starts and you have datetime seconds? For instance, say you start your day in the midnight – Devilhorn Dec 15 '20 at 21:22
  • @Devilhorn you can use the modulo of the number of seconds in a day to find out what time of day it is. Of course that will be in UTC so you might want to add or subtract the offset for your time zone. – Mark Ransom Dec 15 '20 at 22:31
214

Starting from Python 3.3 this becomes super easy with the datetime.timestamp() method. This of course will only be useful if you need the number of seconds from 1970-01-01 UTC.

from datetime import datetime
dt = datetime.today()  # Get timezone naive now
seconds = dt.timestamp()

The return value will be a float representing even fractions of a second. If the datetime is timezone naive (as in the example above), it will be assumed that the datetime object represents the local time, i.e. It will be the number of seconds from current time at your location to 1970-01-01 UTC.

Andrzej Pronobis
  • 33,828
  • 17
  • 76
  • 92
137

To get the Unix time (seconds since January 1, 1970):

>>> import datetime, time
>>> t = datetime.datetime(2011, 10, 21, 0, 0)
>>> time.mktime(t.timetuple())
1319148000.0
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 24
    be careful when using time.mktime for it's express of local time and it's platform-dependent – Shih-Wen Su Jan 09 '13 at 19:10
  • 8
    Be careful indeed. It bit me to my ass big time – Arg Aug 09 '13 at 07:29
  • it assumes that `t` is a local time. UTC offset for the local timezone may have been different in the past and if `mktime()` (C library) has no access to a historical timezone data on a given platform than it may fail (`pytz` is a portable way to access the tz database). Also, local time may be ambiguous e.g., during DST transitions -- you need additional info to disambiguate [e.g., if you know that consecutive date/time values should be increasing in a log file](http://stackoverflow.com/a/26221183/4279) – jfs Jul 10 '15 at 21:00
  • 1
    Be careful when using this with times that have fractions of a second. `time.mktime(datetime.datetime(2019, 8, 3, 4, 5, 6, 912000).timetuple())` results in `1564819506.0`, silently dropping the milliseconds, but `datetime.datetime(2019, 8, 3, 4, 5, 6, 912000).timestamp()` (Andrzej Pronobis' answer) results in `1564819506.912`, the expected result. – Alex Nov 05 '19 at 23:40
33

Maybe off-the-topic: to get UNIX/POSIX time from datetime and convert it back:

>>> import datetime, time
>>> dt = datetime.datetime(2011, 10, 21, 0, 0)
>>> s = time.mktime(dt.timetuple())
>>> s
1319148000.0

# and back
>>> datetime.datetime.fromtimestamp(s)
datetime.datetime(2011, 10, 21, 0, 0)

Note that different timezones have impact on results, e.g. my current TZ/DST returns:

>>>  time.mktime(datetime.datetime(1970, 1, 1, 0, 0).timetuple())
-3600 # -1h

therefore one should consider normalizing to UTC by using UTC versions of the functions.

Note that previous result can be used to calculate UTC offset of your current timezone. In this example this is +1h, i.e. UTC+0100.

References:

Robert Lujo
  • 15,383
  • 5
  • 56
  • 73
  • [`mktime()` may fail](http://stackoverflow.com/questions/7852855/how-to-convert-a-python-datetime-object-to-seconds#comment50683496_7852891). In general, you need `pytz` to convert local time to utc, to get POSIX timestamp. – jfs Jul 10 '15 at 21:07
  • calendar.timegm() seems to be the utc version of time.mktime() – frankster Aug 05 '15 at 10:56
  • Also beware: mktime is up to 10x slower than other approaches. Since it's not unlikely you're doing this in a hot path, it matters. – Remko Oct 15 '21 at 14:01
28

int (t.strftime("%s")) also works

dan3
  • 2,528
  • 22
  • 20
  • 2
    Works for me in Python 2.7, with `import datetime; t = datetime.datetime(2011, 10, 21, 0, 0)` (as specified by OP). But really, I doubt %s is a recently-added time format. – dan3 Apr 05 '14 at 10:30
  • 1
    @dan3: wrong. `%s` is not supported (it may work on some platforms iff `t` is a naive datetime object representing local time and if the local C library has access to the tz database otherwise the result may be wrong). Don't use it. – jfs Jul 10 '15 at 20:35
  • `%s` is not documented anywhere. I sow it in real code and was wondering what is this and look in the documentation and there is no such thing as `%s`. There is only with big S just for the seconds. – VStoykov Oct 05 '16 at 10:36
16

from the python docs:

timedelta.total_seconds()

Return the total number of seconds contained in the duration. Equivalent to

(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6

computed with true division enabled.

Note that for very large time intervals (greater than 270 years on most platforms) this method will lose microsecond accuracy.

This functionality is new in version 2.7.

Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162
Michael
  • 1,786
  • 5
  • 23
  • 42
  • 1
    there is a small problem with the calculation it must be 10**6 instead of 10*6 ... td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 – sdu Nov 27 '12 at 10:22
  • @sdu great catch - the double asterisk is in my answer but stackoverflow consumes it, attempts to rectify only embolden the text. – Michael Jan 18 '13 at 19:01
4

Comparing the 4 most common ways to do this, for accuracy:

Method 1: Manual Calculation

from datetime import datetime
total1 = int(datetimeobj.strftime('%S'))
total1 += int(datetimeobj.strftime('%M')) * 60
total1 += int(datetimeobj.strftime('%H')) * 60 * 60
total1 += (int(datetimeobj.strftime('%j')) - 1) * 60 * 60 * 24
total1 += (int(datetimeobj.strftime('%Y')) - 1970) * 60 * 60 * 24 * 365
print ("Method #1: Manual")
print ("Before: %s" % datetimeobj)
print ("Seconds: %s " % total1)
print ("After: %s" % datetime.fromtimestamp(total1))

Output:

Method #1: Manual
Before: 1970-10-01 12:00:00 
Seconds: 23630400 
After: 1970-10-01 16:00:00

Accuracy test: FAIL (time zone shift)

Method 2: Time Module

import time
from datetime import datetime
total2 = int(time.mktime(datetimeobj.timetuple()))
print ("Method #2: Time Module")
print ("Before: %s" % datetimeobj)
print ("Seconds: %s " % total2)
print ("After: %s" % datetime.fromtimestamp(total2))

Output:

Method #2: Time Module
Before: 1970-10-01 12:00:00 
Seconds: 23616000 
After: 1970-10-01 12:00:00

Accuracy test: PASS

Method 3: Calendar Module

import calendar
from datetime import datetime
total3 = calendar.timegm(datetimeobj.timetuple())
print ("Method #3: Calendar Module")
print ("Before: %s" % datetimeobj)
print ("Seconds: %s " % total3)
print ("After: %s" % datetime.fromtimestamp(total3))

Output:

Method #3: Calendar Module
Before: 1970-10-01 12:00:00
Seconds: 23616000
After: 1970-10-01 16:00:00

Accuracy test: FAIL (time zone shift)

Method 4: Datetime Timestamp

from datetime import datetime
total4 = datetimeobj.timestamp()
print ("Method #4: datetime timestamp")
print ("Before: %s" % datetimeobj)
print ("Seconds: %s " % total4)
print ("After: %s" % datetime.fromtimestamp(total4))

Output:

Method #2: Time Module
Before: 1970-10-01 12:00:00 
Seconds: 23616000 
After: 1970-10-01 12:00:00

Accuracy test: PASS

Conclusion

  • All 4 methods convert datetime to epoch (total seconds)
  • Both the Manual method and Calendar module method are time zone aware.
  • Both datetime.timestamp() and time.mktime() methods are time zone unaware.
  • Simplest method: datetime.timestamp()
leenremm
  • 1,083
  • 13
  • 19
3

I do not see this in all of the answers, although I guess it is the default need:

t_start = datetime.now()
sleep(2)
t_end = datetime.now()
duration = t_end - t_start
print(round(duration.total_seconds()))

If you do not use .total_seconds(), it throws: TypeError: type datetime.timedelta doesn't define __round__ method.

Example:

>>> duration
datetime.timedelta(seconds=53, microseconds=621861)
>>> round(duration.total_seconds())
54
>>> duration.seconds
53

Taking duration.seconds takes only the seconds, leaving aside the microseconds, the same as if you ran math.floor(duration.total_seconds()).

questionto42
  • 7,175
  • 4
  • 57
  • 90
2

To convert a datetime object that represents time in UTC to POSIX timestamp:

from datetime import timezone

seconds_since_epoch = utc_time.replace(tzinfo=timezone.utc).timestamp()

To convert a datetime object that represents time in the local timezone to POSIX timestamp:

import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone()
seconds_since_epoch = local_timezone.localize(local_time, is_dst=None).timestamp()

See How do I convert local time to UTC in Python? If the tz database is available on a given platform; a stdlib-only solution may work.

Follow the links if you need solutions for <3.3 Python versions.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
1

I tried the standard library's calendar.timegm and it works quite well:

# convert a datetime to milliseconds since Epoch
def datetime_to_utc_milliseconds(aDateTime):
    return int(calendar.timegm(aDateTime.timetuple())*1000)

Ref: https://docs.python.org/2/library/calendar.html#calendar.timegm

0

Python provides operation on datetime to compute the difference between two date. In your case that would be:

t - datetime.datetime(1970,1,1)

The value returned is a timedelta object from which you can use the member function total_seconds to get the value in seconds.

(t - datetime.datetime(1970,1,1)).total_seconds()
Michael Doubez
  • 5,937
  • 25
  • 39
Yash Chitroda
  • 645
  • 4
  • 8
  • 27
0
import datetime
import math


def getSeconds(inputDate):
    time = datetime.date.today().strftime('%m/%d/%Y')
    date_time = datetime.datetime.strptime(time, '%m/%d/%Y')
    msg = inputDate
    props = msg.split(".")
    a_timedelta = datetime.timedelta
    if(len(props)==3):
        a_timedelta = date_time - datetime.datetime(int(props[0]),int(props[1]),int(props[2]))
    else:
        print("Invalid date format")
        return
    seconds = math.trunc(a_timedelta.total_seconds())
    print(seconds)
    return seconds

Example getSeconds("2022.1.1")

Faisal Amin
  • 91
  • 1
  • 5
-3

The standard way to find the processing time in ms of a block of code in python 3.x is the following:

import datetime

t_start = datetime.datetime.now()

# Here is the python3 code, you want 
# to check the processing time of

t_end = datetime.datetime.now()
print("Time taken : ", (t_end - t_start).total_seconds()*1000, " ms")
Cribber
  • 2,513
  • 2
  • 21
  • 60