11
t='20180515102500'
d=datetime.strptime(t, "%Y%m%d%H%M%S")
millis_since_epoch = int(time.mktime(d.timetuple())) * 1000
print(millis_since_epoch)

gives me: 1526379900000 on repl.it(python 3.6.1) and on my local: 1526397900000 (python 2.7.14)

Why? What is the recommended way to convert datetime object to epoch?

user3483203
  • 50,081
  • 9
  • 65
  • 94
user1179299
  • 326
  • 1
  • 4
  • 16
  • 3
    You're using naive datetimes. Presumably `repl.it` is running in a time zone 5 hours away from your local timezone, so its results are 5 hours off. If you don't want to use "whatever local time on this machine is", you have to decide what you _do_ want instead. UTC? Timestamps with offsets or timezones in them? – abarnert May 15 '18 at 18:04
  • 1
    Anyway, the recommended way to convert a datetime object to an offset from epoch is to just call `timestamp()` on it (and then multiply by 1000 if you want millis instead of seconds), or to subtract the epoch (as a `datetime`) and use the `timedelta` result. But neither is going to solve your problem; you'll end up with the same result. – abarnert May 15 '18 at 18:05
  • As a side note, why are you converting the `float` to `int`, and then multiplying by 1000? Did you actually want to make extra sure you don't have sub-second precision even though you're counting in millis? – abarnert May 15 '18 at 18:30

4 Answers4

11

Your problem is that you're using naive datetime (and struct_tm and so on) objects. So you're asking how far 15 May 2018 10:25:00 in "whatever the local timezone on this machine is" is from the Unix epoch. If you run it on two machines with timezones 5 hours apart, you will get results that are 5*3600*1000 milliseconds apart.

The recommended way to do it is either:

d.timestamp() # returns difference from epoch as float seconds

… or:

d - datetime.fromtimestamp(0) # returns difference as timedelta

(It should be obvious how to convert either of those to float millis, or whatever else you need.)

But neither of those will make any difference here, since you're still using naive datetime objects. (At least you aren't mixing in other types from the time module and throwing away precision, but you're not solving your problem.)


The solution to your problem depends on what you're trying to do. Are these UTC timestamps? Are they timestamps in some known timezone that you know out-of-band?

If everything is UTC, the best thing to do is to explicitly create UTC objects, but the simplest thing to do (especially if you need your code to run in 2.7) is:

d - datetime.utcfromtimestamp(0)

This gives you a naive datetime representing 0 UTC seconds since the epoch, and subtracts it from your naive datetime representing X UTC seconds since the epoch, so you get a timedelta representing X seconds (specifically, 17666 days, 37500 seconds), without regard to what timezone the system is using.

Or, the smallest change to your existing code is to use utctimetuple instead of timetuple, which does the same thing in a more convoluted way.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thanks, I "assumed" datetime in python to be like java's LocalDateTime which is without timezone. Yeah, those are UTC timestamps. – user1179299 May 15 '18 at 18:17
  • @user1179299 Python has a single class for naive-local, timezone-imbued, and UTC datetimes. The way you're using it, they're naive-local. But if you were expecting it to act like Java's `LocalDateTime`, why are you surprised that it's acting like Java's `LocalDateTime`? – abarnert May 15 '18 at 18:22
  • LocalDateTime is always without timezone on the other hand python's DateTime can support different flavors. I assumed them to be same. – user1179299 May 15 '18 at 19:07
7

in python 3.6:

datetime.timestamp()

for example:

import datetime

timestamp = datetime.datetime.now().timestamp()
Shelef
  • 598
  • 2
  • 8
  • 16
5

Try this:

t='20180515102500'
d=datetime.datetime.strptime(t, "%Y%m%d%H%M%S")
print(d)
epoch = datetime.datetime.utcfromtimestamp(0)


def unix_time_millis(dt):
  return (dt - epoch).total_seconds() * 1000

unix_time_millis(d)

Let me know if that helps!

IAmGroot
  • 81
  • 4
0
t = datetime.strptime(gr_dt_string, "%Y-%m-%dT%H:%M:%S")
if six.PY2:
    gr_mili = int((t - datetime.fromtimestamp(0)).total_seconds()) * 1000
else:
    gr_mili = int(t.timestamp() * 1000)
Neetin
  • 9
  • 1