305

I have to create an "Expires" value 5 minutes in the future, but I have to supply it in UNIX Timestamp format. I have this so far, but it seems like a hack.

def expires():
    '''return a UNIX style timestamp representing 5 minutes from now'''
    epoch = datetime.datetime(1970, 1, 1)
    seconds_in_a_day = 60 * 60 * 24
    five_minutes = datetime.timedelta(seconds=5*60)
    five_minutes_from_now = datetime.datetime.now() + five_minutes
    since_epoch = five_minutes_from_now - epoch
    return since_epoch.days * seconds_in_a_day + since_epoch.seconds

Is there a module or function that does the timestamp conversion for me?

Doug Harris
  • 3,169
  • 5
  • 29
  • 31
Daniel Rhoden
  • 6,117
  • 6
  • 26
  • 28
  • 7
    I recommend changing the subject of this question. The question is good, but it is not about converting datetime to Unix timestamp. It is about how to get a Unix timestamp 5 minutes in the future. – D. A. May 21 '13 at 18:10
  • I disagree, @D.A. The question essentially says "I need to do X and Y. Here's what I have now. What's a better way to do Y?" Maybe there are better ways to do X, but the title and the body clearly ask about Y. – Rob Kennedy Jun 22 '13 at 12:40
  • 6
    I agree with you completely on the question, and I think it a good one with a good answer. The problem is "Python datetime to Unix timestamp" doesn't reflect either the question or answer. I found this post searching for a way to do the conversion, and I lost time because of the misleading subject line. I suggest: "Python, 5 minutes in the future as UNIX Timestamp" – D. A. Jul 31 '13 at 21:57
  • 3
    @JimmyKane - A pretty comprehensive answer on how to get a timestamp from a date time can be found here: http://stackoverflow.com/questions/8777753/converting-datetime-date-to-utc-timestamp-in-python/8778548#8778548 – Tim Tisdall Feb 26 '14 at 16:19
  • @TimTisdall yes since the title is changed it makes no sense – Jimmy Kane Feb 27 '14 at 20:12

12 Answers12

355

Another way is to use calendar.timegm:

future = datetime.datetime.utcnow() + datetime.timedelta(minutes=5)
return calendar.timegm(future.timetuple())

It's also more portable than %s flag to strftime (which doesn't work on Windows).

jfs
  • 399,953
  • 195
  • 994
  • 1,670
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
  • Thanks D.Shawley. help(datetime.timedelta) didn't mention that shortcut. It only had days, seconds, and microseconds. – Daniel Rhoden May 05 '10 at 19:05
  • 12
    Note that, combining the previous two comments, the right solution is: `calendar.timegm(future.utctimetuple())`. This ensures that a UTC time is passed into `calendar.timegm`. – shadowmatter Jan 31 '13 at 04:28
  • 1
    Can't upvote @tumbleweed's comment enough. If you're trying to get a UNIX timestamp (and therefore one in UTC), use calendar.timegm. – Bialecki Feb 20 '13 at 20:58
  • @tumbleweed, right. If you use mktime plus gmtime(0) will result in nonzero roundtrip delta for any time zone besides UTC: e.g. ` time.mktime(datetime.fromtimestamp(time.mktime(time.gmtime(0))).timetuple())` gives `21600.0` seconds (6 hours) instead of 0.0 for my unix machine's TZ – hobs Nov 05 '13 at 23:55
  • If you want to get UTC timestamp you should use this: `calendar.timegm(datetime.datetime.utcnow().timetuple())`. Method using `datetime.datetime.now().utctimetuple()` doesn't work for me (Python 3.2). – Wookie88 Dec 28 '13 at 15:21
  • @Wookie88: you could call `time.time()` to get the timestamp as [@Off Rhoden's answer shows](http://stackoverflow.com/a/2776392/4279) – jfs Apr 29 '14 at 10:58
  • @CatPlusPlus: Unfortunately, the [edits that can change the meaning of an answer are forbidden](http://meta.stackexchange.com/help/editing) that is why if an answer is wrong, comments are used instead of fixing the answer directly. In my opinion, even if half of all edits were wrong; it is easy to push the rollback button. – jfs Apr 29 '14 at 11:06
  • @J.F.Sebastian There, I made it wiki, feel free to edit to your heart's content! I really don't care to reresearch a bad answer (how it got to 300 score is beyond me, stupid SO voting) to a crappy SO question from 4 years ago. – Cat Plus Plus Apr 29 '14 at 15:11
  • @shadowmatter: `.utctimetuple()` doesn't work like you think it does. It doesn't convert a naive datetime object in local timezone to UTC time. The result is the same as for `.timetuple()` only `tm_isdst` is forced to zero. – jfs Apr 30 '14 at 03:25
  • You can do future.strftime("%s") – Nidhin Bose J. Aug 11 '14 at 08:39
  • @NidhinBoseJ.: It's like you didn't actually read the answer. It's also a silly solution because you end up with a string. Why do you want a string? Hint: you don't. – Lightness Races in Orbit Aug 11 '14 at 09:15
165

Now in Python >= 3.3 you can just call the timestamp() method to get the timestamp as a float.

import datetime
current_time = datetime.datetime.now(datetime.timezone.utc)
unix_timestamp = current_time.timestamp() # works if Python >= 3.3

unix_timestamp_plus_5_min = unix_timestamp + (5 * 60)  # 5 min * 60 seconds
Tim Tisdall
  • 9,914
  • 3
  • 52
  • 82
  • 5
    +1 for this. It should be displayed much higher, because it's the clean way how to do that in Python 3 – Viktor Stískala May 21 '13 at 20:28
  • 3
    @scott654 I thought having it right at the beginning of the comment made it clear enough, but I added some bold to it too. – Tim Tisdall Oct 01 '13 at 13:16
  • 1
    I'd make the note as a comment in the code block because we all just scan the code in the answers first and only read the rest if the code looks good. Good answer though. – Matthew Purdon Oct 04 '13 at 17:21
  • 2
    [local time may be ambigous](http://pytz.sourceforge.net/#problems-with-localtime). The example (`datetime.now()`) is bad because it encourages the usage of naive datetime objects that represent local time and it might fail during DST transitions (due to the inherent ambiguity). You could use `ts = datetime.now(timezone.utc).timestamp()` instead. – jfs Nov 17 '13 at 18:19
  • @J.F.Sebastian - good point. I didn't want to add to the imports, though, so I changed it to `utcnow()`. I'm used to working on machines where the timezone is set to UTC, but that shouldn't be assumed in this code snippet. – Tim Tisdall Nov 18 '13 at 14:01
  • now the code is incorrect for any local time different from utc. `.timestamp()` uses local time for naive datetime object. timezone.utc is necessary here. Look at [more ways to get timestamp from datetime](http://stackoverflow.com/a/8778548/4279) – jfs Nov 18 '13 at 18:50
  • @J.F.Sebastian - okay, changed to `now(datetime.timezone.utc)` – Tim Tisdall Nov 18 '13 at 19:05
  • +1: looks good. You could use `from datetime import datetime, timezone` for readability – jfs Nov 18 '13 at 20:18
  • This gives an output with a decimal point though which isn't right surely? E.g. `1522933571.0` – geoidesic Apr 05 '18 at 13:07
  • @geoidesic - It's right, it returns the timestamp as a float. Some machines return millisecond precision while others don't, so this method always returns a float to accommodate both. You can put the value into `int()` to truncate it into an integer if needed. – Tim Tisdall Apr 05 '18 at 13:24
146

Just found this, and its even shorter.

import time
def expires():
    '''return a UNIX style timestamp representing 5 minutes from now'''
    return int(time.time()+300)
Daniel Rhoden
  • 6,117
  • 6
  • 26
  • 28
  • 12
    This doesn't answer the question. – Jesse Dhillon Apr 06 '12 at 03:30
  • 24
    @JesseDhillon it answers the question (make a UNIX timestamp 5 mins in future), just not the title. – dbr Jul 07 '12 at 13:56
  • 3
    `time.time()` can be set back. To create an "Expires" value 5 minutes in the future you might need [`time.monotonic()`](http://docs.python.org/dev/library/time.html#time.monotonic) analog depending on your use-case. – jfs Aug 14 '12 at 15:00
  • @j-f-sebastian time.monotonic() does not return a UNIX timestamp, it returns a timestamp with an undefined reference point. – rspeer Jun 03 '13 at 22:34
  • @rspeer: yes, as [the docs say](http://docs.python.org/dev/library/time.html#time.monotonic), only the difference between consecutive calls is valid. Whether `monotonic` can be used depends on your use-case e.g., `subprocess` module does use it to implement `timeout` option. – jfs Jun 15 '13 at 07:31
  • why are you creating a whole new dedicated function for this? – au_stan Oct 11 '14 at 15:22
57

This is what you need:

import time
import datetime
n = datetime.datetime.now()
unix_time = time.mktime(n.timetuple())
Ali
  • 18,665
  • 21
  • 103
  • 138
  • How is this different or adds to the one 'Cat Plus Plus' provided? – David Apr 30 '13 at 19:19
  • 3
    E.G. this is the answer to the question "Python datetime to Unix timestamp" while Cat Plus Plus answered the question "Python datetime that will be in 5 minutes to Unix timestamp". So this one is clean and obvious. – running.t Jun 25 '13 at 17:45
  • @running.t: it reminds me: "every problem has simple, obvious and *wrong* solution". See [possible issues with `mktime(dt.timetuple())`](http://stackoverflow.com/questions/2775864/python-datetime-to-unix-timestamp/13423911#comment15929690_2775982). `datetime.now(timezone.utc).timestamp()` provided by @Tim Tisdall is the solution in Python 3.3+. Otherwise [`(dt - epoch).total_seconds()` could be used](http://stackoverflow.com/a/13423911/4279). – jfs Dec 11 '13 at 03:28
  • @J.F.Sebastian what if I really do want all computation to take place in local time? Is it the case when eg. to parse a naive string that one knows is localtime and decide whether there was DST in effect in that particular time? – n611x007 May 08 '14 at 13:35
  • 1
    @naxa: yes, some local times are ambiguous or non-existent. Also timezone offset may be different for reasons other than DST (you need a tz database such as pytz, to find out the correct offset). Local time means whatever local politician thinks is a good idea to measure time I.e., it may be highly irregular. – jfs May 08 '14 at 13:45
49

You can use datetime.strftime to get the time in Epoch form, using the %s format string:

def expires():
    future = datetime.datetime.now() + datetime.timedelta(seconds=5*60)
    return int(future.strftime("%s"))

Note: This only works under linux, and this method doesn't work with timezones.

shahar
  • 355
  • 2
  • 18
mipadi
  • 398,885
  • 90
  • 523
  • 479
  • 32
    This is a somewhat undocumented behaviour ( http://www.python.org/doc/current/library/datetime.html ). Seems to be working under linux and not working under win32 (generating `ValueError: Invalid format string`). – Antony Hatchkins Dec 25 '10 at 21:23
  • 3
    This method doesn't work with timezones. Changing timezone will give the same result datetime(2013,12,7,tzinfo=timezone("America/Chicago")).strftime("%s") 1386385200 datetime(2013,12,7,tzinfo=timezone("Europe/Riga")).strftime("%s") 1386385200 – Martins Balodis Dec 09 '13 at 13:58
11

Here's a less broken datetime-based solution to convert from datetime object to posix timestamp:

future = datetime.datetime.utcnow() + datetime.timedelta(minutes=5)
return (future - datetime.datetime(1970, 1, 1)).total_seconds()

See more details at Converting datetime.date to UTC timestamp in Python.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
6
def in_unix(input):
  start = datetime.datetime(year=1970,month=1,day=1)
  diff = input - start
  return diff.total_seconds()
rgrinberg
  • 9,638
  • 7
  • 27
  • 44
Sravan
  • 553
  • 8
  • 15
4

The key is to ensure all the dates you are using are in the utc timezone before you start converting. See http://pytz.sourceforge.net/ to learn how to do that properly. By normalizing to utc, you eliminate the ambiguity of daylight savings transitions. Then you can safely use timedelta to calculate distance from the unix epoch, and then convert to seconds or milliseconds.

Note that the resulting unix timestamp is itself in the UTC timezone. If you wish to see the timestamp in a localized timezone, you will need to make another conversion.

Also note that this will only work for dates after 1970.

   import datetime
   import pytz

   UNIX_EPOCH = datetime.datetime(1970, 1, 1, 0, 0, tzinfo = pytz.utc)
   def EPOCH(utc_datetime):
      delta = utc_datetime - UNIX_EPOCH
      seconds = delta.total_seconds()
      ms = seconds * 1000
      return ms
fawce
  • 822
  • 6
  • 10
  • 3
    note: I don't understand "the [unix] timestamp in a localized timezone". The timestamp is the same (elapsed seconds since `1970-01-01 00:00:00+00:00`). To get a naive datetime object in local timezone: `datetime.fromtimestamp(ts)` – jfs Aug 14 '12 at 09:37
4

The following is based on the answers above (plus a correction for the milliseconds) and emulates datetime.timestamp() for Python 3 before 3.3 when timezones are used.

def datetime_timestamp(datetime):
    '''
    Equivalent to datetime.timestamp() for pre-3.3
    '''
    try:
        return datetime.timestamp()
    except AttributeError:
        utc_datetime = datetime.astimezone(utc)
        return timegm(utc_datetime.timetuple()) + utc_datetime.microsecond / 1e6

To strictly answer the question as asked, you'd want:

datetime_timestamp(my_datetime) + 5 * 60

datetime_timestamp is part of simple-date. But if you were using that package you'd probably type:

SimpleDate(my_datetime).timestamp + 5 * 60

which handles many more formats / types for my_datetime.

andrew cooke
  • 45,717
  • 10
  • 93
  • 143
1
def expiration_time():
    import datetime,calendar
    timestamp = calendar.timegm(datetime.datetime.now().timetuple())
    returnValue = datetime.timedelta(minutes=5).total_seconds() + timestamp
    return returnValue
hd1
  • 33,938
  • 5
  • 80
  • 91
1

Note that solutions with timedelta.total_seconds() work on python-2.7+. Use calendar.timegm(future.utctimetuple()) for lower versions of Python.

mighq
  • 1,004
  • 1
  • 13
  • 14
0

How about this method using built-in timestamp function? The snippet is working for different time (not just current time).

import datetime

a = "2017-01-01 14:30:00"
b = datetime.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
c = int(b.timestamp()/60.0)
alarm_time = c + 5

Runtime environment   OS: Ubuntu 16.04   Python 3.6

Cloud Cho
  • 1,594
  • 19
  • 22