Making matplotlib's date2num and num2date perfect inverses


Question

I'm trying to write a pair of functions, plottm and unixtm, which convert back and forth between normal unix time (seconds since 1970-01-01) and Matplotlib's date representation (days since the last day of -1BC or something, a float).

If plottm and unixtm were proper inverses then this code would print the same date/time twice:

import time, datetime
import matplotlib.dates as dt

# Convert a unix time u to plot time p, and vice versa
def plottm(u): return dt.date2num(datetime.datetime.fromtimestamp(u))
def unixtm(p): return time.mktime(dt.num2date(p).timetuple())

u = 1270000000
print datetime.datetime.fromtimestamp(u), "-->", \
      datetime.datetime.fromtimestamp(unixtm(plottm(u)))

Alas, it's off by an hour (which only happens for some timestamps, otherwise I'd insert an offset and be done with it).

Probably related: Problems with Localtime

UPDATE: Related question that isn't specific to Matplotlib: Convert a unixtime to a datetime object and back again (pair of time conversion functions that are inverses)

1
2
5/23/2017 11:56:10 AM

Based on @dreeves answer, a solution adapted to work with timezone aware datetimes:

import matplotlib.dates as dt

from calendar import timegm
from datetime import datetime

from pytz import utc


# Convert a unix time u to plot time p, and vice versa
def plottm(u):
    return dt.date2num(datetime.fromtimestamp(u, utc))

def unixtm(p):
    return timegm(dt.num2date(p, utc).utctimetuple())


u = 1270000000
print datetime.fromtimestamp(u, utc), "-->", \
      datetime.fromtimestamp(unixtm(plottm(u)), utc)

output (tested for several timezones):

2010-03-31 01:46:40+00:00 --> 2010-03-31 01:46:40+00:00
3
11/6/2012 11:47:05 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon