32

I have a timestamp in epoch time with nanoseconds - e.g. 1360287003083988472 nanoseconds since 1970-01-01.

The Python datetime objects and conversion methods only support up to millisecond precision.

Is there an easy way to convert this epoch time into human-readable time?

FObersteiner
  • 22,500
  • 8
  • 42
  • 72
victorhooi
  • 16,775
  • 22
  • 90
  • 113
  • 2
    @abarnert I don't think so. This question deals with converting a number to a human-readable string, whereas that one is trying to convert from a string to a `datetime` object. – ethguo Mar 27 '13 at 01:18
  • @ethg242: That question is sort of all over the place, but it comes down to the same thing: `datetime` doesn't handle nanoseconds, so you have to do the math/stringops yourself. Maybe it's fine to have one question about `strptime` and another about `strftime`. – abarnert Mar 27 '13 at 05:25
  • 1
    this is one turned out better than the duplicate – n611x007 Jun 13 '13 at 15:55
  • 1
    @abarnert Have you actually look at the answers on the other question? Lol. For some reason, naxa is right, the answers on this one turned out better, no idea why. – victorhooi Jun 14 '13 at 04:45
  • @victorhooi: Yes, sometimes dups do turn out better than the original. That means you shouldn't ignore a question just because it might be a dup (notice that one of the two answers here is mine), but it doesn't mean we shouldn't mark dups. – abarnert Jun 14 '13 at 18:55
  • Python's `datetime.datetime()` has microsecond support for the fractions and thus microsecond instead of millisecond precision. – Anthon Aug 20 '16 at 09:45

3 Answers3

47

First, convert it to a datetime object with second precision (floored, not rounded):

>>> from datetime import datetime
>>> dt = datetime.fromtimestamp(1360287003083988472 // 1000000000)
>>> dt
datetime.datetime(2013, 2, 7, 17, 30, 3)

Then to make it human-readable, use the strftime() method on the object you get back:

>>> s = dt.strftime('%Y-%m-%d %H:%M:%S')
>>> s
'2013-02-07 17:30:03'

Finally, add back in the nanosecond precision:

>>> s += '.' + str(int(1360287003083988472 % 1000000000)).zfill(9)
>>> s
'2013-02-07 17:30:03.083988472'
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
  • 1
    My problem here is that by using `1360287003083988472 // 1000000000`, you're at risk of loosing valuable information. One can get a human-readable format by using `datetime.fromtimestamp(1360287003083988472 / 1000000000)` instead. – r02 Feb 25 '21 at 12:32
  • @r02. Converting a uint64 to float can lose a lot of valuable information too. One has 64 bits of precision, the other effectively 53. – Mad Physicist Aug 16 '22 at 22:20
17

Actually, Python's datetime methods handle microsecond precision, not millisecond:

>>> nanos = 1360287003083988472
>>> secs = nanos / 1e9
>>> dt = datetime.datetime.fromtimestamp(secs)
>>> dt.strftime('%Y-%m-%dT%H:%M:%S.%f')
'2013-02-07T17:30:03.083988'

But if you actually need nanoseconds, that still doesn't help. Your best bet is to write your own wrapper:

def format_my_nanos(nanos):
    dt = datetime.datetime.fromtimestamp(nanos / 1e9)
    return '{}{:03.0f}'.format(dt.strftime('%Y-%m-%dT%H:%M:%S.%f'), nanos % 1e3)

This gives me:

'2013-02-07T17:30:03.083988472'

Of course you could have done the same thing even if Python didn't do sub-second precision at all…

def format_my_nanos(nanos):
    dt = datetime.datetime.fromtimestamp(nanos / 1e9)
    return '{}.{:09.0f}'.format(dt.strftime('%Y-%m-%dT%H:%M:%S'), nanos % 1e9)
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Unix epoch time is UTC so `datetime.utcfromtimestamp(secs)` will get the correct timezone, fromtimestamp will use the system timezone https://stackoverflow.com/a/72225603/603653 – Lucas Walter Dec 08 '22 at 14:12
3

It should be noted that ubiquitous libraries numpy and pandas can handle Unix time in nanoseconds without further preparation:

import numpy as np
import pandas as pd

unix_ns = 1360287003083988472

np.datetime64(unix_ns, 'ns') # need to specify unit here
# Out[4]: numpy.datetime64('2013-02-08T01:30:03.083988472')

pd.Timestamp(unix_ns) # pd.Timestamp defaults to ns
# Out[5]: Timestamp('2013-02-08 01:30:03.083988472')

# alternatively (also e.g. for list input):
pd.to_datetime(unix_ns)
# Out[6]: Timestamp('2013-02-08 01:30:03.083988472')

numpy / pandas datetime resembles UTC if you do not set a time zone. In vanilla Python datetime, it's local time.

FObersteiner
  • 22,500
  • 8
  • 42
  • 72