Convert datetime to Unix timestamp and convert it back in python

PythonDatetimeTimestamp

Python Problem Overview


I have dt = datetime(2013,9,1,11), and I would like to get a Unix timestamp of this datetime object.

When I do (dt - datetime(1970,1,1)).total_seconds() I got the timestamp 1378033200.

When converting it back using datetime.fromtimestamp I got datetime.datetime(2013, 9, 1, 6, 0).

The hour doesn't match. What did I miss here?

Python Solutions


Solution 1 - Python

solution is

import time
import datetime
d = datetime.date(2015,1,5)

unixtime = time.mktime(d.timetuple())

Solution 2 - Python

If you want to convert a python datetime to seconds since epoch you should do it explicitly:

>>> import datetime
>>> datetime.datetime(2012, 04, 01, 0, 0).strftime('%s')
'1333234800'
>>> (datetime.datetime(2012, 04, 01, 0, 0) - datetime.datetime(1970, 1, 1)).total_seconds()
1333238400.0

In Python 3.3+ you can use timestamp() instead:

>>> import datetime
>>> datetime.datetime(2012, 4, 1, 0, 0).timestamp()
1333234800.0

Solution 3 - Python

What you missed here is timezones.

Presumably you've five hours off UTC, so 2013-09-01T11:00:00 local and 2013-09-01T06:00:00Z are the same time.

You need to read the top of the datetime docs, which explain about timezones and "naive" and "aware" objects.

If your original naive datetime was UTC, the way to recover it is to use utcfromtimestamp instead of fromtimestamp.

On the other hand, if your original naive datetime was local, you shouldn't have subtracted a UTC timestamp from it in the first place; use datetime.fromtimestamp(0) instead.

Or, if you had an aware datetime object, you need to either use a local (aware) epoch on both sides, or explicitly convert to and from UTC.

If you have, or can upgrade to, Python 3.3 or later, you can avoid all of these problems by just using the timestamp method instead of trying to figure out how to do it yourself. And even if you don't, you may want to consider borrowing its source code.

(And if you can wait for Python 3.4, it looks like PEP 341 is likely to make it into the final release, which means all of the stuff J.F. Sebastian and I were talking about in the comments should be doable with just the stdlib, and working the same way on both Unix and Windows.)

Solution 4 - Python

Rather than this expression to create a POSIX timestamp from dt,

(dt - datetime(1970,1,1)).total_seconds()

Use this:

int(dt.strftime("%s"))

I get the right answer in your example using the second method.

EDIT: Some followup... After some comments (see below), I was curious about the lack of support or documentation for %s in strftime. Here's what I found:

In the Python source for datetime and time, the string STRFTIME_FORMAT_CODES tells us:

"Other codes may be available on your platform.
 See documentation for the C library strftime function."

So now if we man strftime (on BSD systems such as Mac OS X), you'll find support for %s:

"%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))."

Anyways, that's why %s works on the systems it does. But there are better solutions to OP's problem (that take timezones into account). See @abarnert's accepted answer here.

Solution 5 - Python

For working with UTC timezones:

time_stamp = calendar.timegm(dt.timetuple())

datetime.utcfromtimestamp(time_stamp)

Solution 6 - Python

You've missed the time zone info (already answered, agreed)

arrow package allows to avoid this torture with datetimes; It is already written, tested, pypi-published, cross-python (2.6 — 3.xx).

All you need: pip install arrow (or add to dependencies)

Solution for your case

dt = datetime(2013,9,1,11)
arrow.get(dt).timestamp
# >>> 1378033200

bc = arrow.get(1378033200).datetime
print(bc)
# >>> datetime.datetime(2013, 9, 1, 11, 0, tzinfo=tzutc())
print(bc.isoformat())
# >>> '2013-09-01T11:00:00+00:00'

Solution 7 - Python

If your datetime object represents UTC time, don't use time.mktime, as it assumes the tuple is in your local timezone. Instead, use calendar.timegm:

>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60

Solution 8 - Python

def dt2ts(dt, utc=False):
    if utc:
        return calendar.timegm(dt.timetuple())
    if dt.tzinfo is None:
        return int(time.mktime(dt.timetuple()))
    utc_dt = dt.astimezone(tz.tzutc()).timetuple()
    return calendar.timegm(utc_dt)

If you want UTC timestamp :time.mktime just for local dt .Use calendar.timegm is safe but dt must the utc zone so change the zone to utc. If dt in UTC just use calendar.timegm.

Solution 9 - Python

Well, when converting TO unix timestamp, python is basically assuming UTC, but while converting back it will give you a date converted to your local timezone.

See this question/answer; https://stackoverflow.com/questions/18812638/get-timezone-used-by-datetime-datetime-fromtimestamp

Solution 10 - Python

def datetime_to_epoch(d1):

    # create 1,1,1970 in same timezone as d1
    d2 = datetime(1970, 1, 1, tzinfo=d1.tzinfo)
    time_delta = d1 - d2
    ts = int(time_delta.total_seconds())
    return ts


def epoch_to_datetime_string(ts, tz_name="UTC"):
    x_timezone = timezone(tz_name)
    d1 = datetime.fromtimestamp(ts, x_timezone)
    x = d1.strftime("%d %B %Y %H:%M:%S")
    return x

Solution 11 - Python

This class will cover your needs, you can pass the variable into ConvertUnixToDatetime & call which function you want it to operate based off.

from datetime import datetime
import time

class ConvertUnixToDatetime:
    def __init__(self, date):
        self.date = date

    # Convert unix to date object
    def convert_unix(self):
        unix = self.date

        # Check if unix is a string or int & proceeds with correct conversion
        if type(unix).__name__ == 'str':
            unix = int(unix[0:10])
        else:
            unix = int(str(unix)[0:10])

        date = datetime.utcfromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S')

        return date

    # Convert date to unix object
    def convert_date(self):
        date = self.date

        # Check if datetime object or raise ValueError
        if type(date).__name__ == 'datetime':
            unixtime = int(time.mktime(date.timetuple()))
        else:
            raise ValueError('You are trying to pass a None Datetime object')
        return type(unixtime).__name__, unixtime


if __name__ == '__main__':

    # Test Date
    date_test = ConvertUnixToDatetime(datetime.today())
    date_test = date_test.convert_date()
    print(date_test)

    # Test Unix
    unix_test = ConvertUnixToDatetime(date_test[1])
    print(unix_test.convert_unix())

Solution 12 - Python

import time
from datetime import datetime
time.mktime(datetime.now().timetuple())

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkunView Question on Stackoverflow
Solution 1 - PythonDmitrySemenovView Answer on Stackoverflow
Solution 2 - PythonFrancisco CostaView Answer on Stackoverflow
Solution 3 - PythonabarnertView Answer on Stackoverflow
Solution 4 - PythonDarren StoneView Answer on Stackoverflow
Solution 5 - PythonEmin TemizView Answer on Stackoverflow
Solution 6 - PythonmaxkoryukovView Answer on Stackoverflow
Solution 7 - PythonMatt KramerView Answer on Stackoverflow
Solution 8 - PythonwyxView Answer on Stackoverflow
Solution 9 - PythonRonald PortierView Answer on Stackoverflow
Solution 10 - Pythonrjha94View Answer on Stackoverflow
Solution 11 - PythoncryptopotluckView Answer on Stackoverflow
Solution 12 - PythonJosé Juan De la CruzView Answer on Stackoverflow