[python] Convert UTC datetime string to local datetime

I've never had to convert time to and from UTC. Recently had a request to have my app be timezone aware, and I've been running myself in circles. Lots of information on converting local time to UTC, which I found fairly elementary (maybe I'm doing that wrong as well), but I can not find any information on easily converting the UTC time to the end-users timezone.

In a nutshell, and android app sends me (appengine app) data and within that data is a timestamp. To store that timestamp to utc time I am using:

datetime.utcfromtimestamp(timestamp)

That seems to be working. When my app stores the data, it is being store as 5 hours ahead (I am EST -5)

The data is being stored on appengine's BigTable, and when retrieved it comes out as a string like so:

"2011-01-21 02:37:21"

How do I convert this string to a DateTime in the users correct time zone?

Also, what is the recommended storage for a users timezone information? (How do you typically store tz info ie: "-5:00" or "EST" etc etc ?) I'm sure the answer to my first question might contain a parameter the answers the second.

This question is related to python datetime utc localtime

The answer is


Here's a resilient method that doesn't depend on any external libraries:

from datetime import datetime
import time

def datetime_from_utc_to_local(utc_datetime):
    now_timestamp = time.time()
    offset = datetime.fromtimestamp(now_timestamp) - datetime.utcfromtimestamp(now_timestamp)
    return utc_datetime + offset

This avoids the timing issues in DelboyJay's example. And the lesser timing issues in Erik van Oosten's amendment.

As an interesting footnote, the timezone offset computed above can differ from the following seemingly equivalent expression, probably due to daylight savings rule changes:

offset = datetime.fromtimestamp(0) - datetime.utcfromtimestamp(0) # NO!

Update: This snippet has the weakness of using the UTC offset of the present time, which may differ from the UTC offset of the input datetime. See comments on this answer for another solution.

To get around the different times, grab the epoch time from the time passed in. Here's what I do:

def utc2local (utc):
    epoch = time.mktime(utc.timetuple())
    offset = datetime.fromtimestamp (epoch) - datetime.utcfromtimestamp (epoch)
    return utc + offset

If using Django, you can use the timezone.localtime method:

from django.utils import timezone
date 
# datetime.datetime(2014, 8, 1, 20, 15, 0, 513000, tzinfo=<UTC>)

timezone.localtime(date)
# datetime.datetime(2014, 8, 1, 16, 15, 0, 513000, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)

See the datetime documentation on tzinfo objects. You have to implement the timezones you want to support yourself. The are examples at the bottom of the documentation.

Here's a simple example:

from datetime import datetime,tzinfo,timedelta

class Zone(tzinfo):
    def __init__(self,offset,isdst,name):
        self.offset = offset
        self.isdst = isdst
        self.name = name
    def utcoffset(self, dt):
        return timedelta(hours=self.offset) + self.dst(dt)
    def dst(self, dt):
            return timedelta(hours=1) if self.isdst else timedelta(0)
    def tzname(self,dt):
         return self.name

GMT = Zone(0,False,'GMT')
EST = Zone(-5,False,'EST')

print datetime.utcnow().strftime('%m/%d/%Y %H:%M:%S %Z')
print datetime.now(GMT).strftime('%m/%d/%Y %H:%M:%S %Z')
print datetime.now(EST).strftime('%m/%d/%Y %H:%M:%S %Z')

t = datetime.strptime('2011-01-21 02:37:21','%Y-%m-%d %H:%M:%S')
t = t.replace(tzinfo=GMT)
print t
print t.astimezone(EST)

Output

01/22/2011 21:52:09 
01/22/2011 21:52:09 GMT
01/22/2011 16:52:09 EST
2011-01-21 02:37:21+00:00
2011-01-20 21:37:21-05:00a

This answer should be helpful if you don't want to use any other modules besides datetime.

datetime.utcfromtimestamp(timestamp) returns a naive datetime object (not an aware one). Aware ones are timezone aware, and naive are not. You want an aware one if you want to convert between timezones (e.g. between UTC and local time).

If you aren't the one instantiating the date to start with, but you can still create a naive datetime object in UTC time, you might want to try this Python 3.x code to convert it:

import datetime

d=datetime.datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") #Get your naive datetime object
d=d.replace(tzinfo=datetime.timezone.utc) #Convert it to an aware datetime object in UTC time.
d=d.astimezone() #Convert it to your local timezone (still aware)
print(d.strftime("%d %b %Y (%I:%M:%S:%f %p) %Z")) #Print it with a directive of choice

Be careful not to mistakenly assume that if your timezone is currently MDT that daylight savings doesn't work with the above code since it prints MST. You'll note that if you change the month to August, it'll print MDT.

Another easy way to get an aware datetime object (also in Python 3.x) is to create it with a timezone specified to start with. Here's an example, using UTC:

import datetime, sys

aware_utc_dt_obj=datetime.datetime.now(datetime.timezone.utc) #create an aware datetime object
dt_obj_local=aware_utc_dt_obj.astimezone() #convert it to local time

#The following section is just code for a directive I made that I liked.
if sys.platform=="win32":
    directive="%#d %b %Y (%#I:%M:%S:%f %p) %Z"
else:
    directive="%-d %b %Y (%-I:%M:%S:%f %p) %Z"

print(dt_obj_local.strftime(directive))

If you use Python 2.x, you'll probably have to subclass datetime.tzinfo and use that to help you create an aware datetime object, since datetime.timezone doesn't exist in Python 2.x.


import datetime

def utc_str_to_local_str(utc_str: str, utc_format: str, local_format: str):
    """
    :param utc_str: UTC time string
    :param utc_format: format of UTC time string
    :param local_format: format of local time string
    :return: local time string
    """
    temp1 = datetime.datetime.strptime(utc_str, utc_format)
    temp2 = temp1.replace(tzinfo=datetime.timezone.utc)
    local_time = temp2.astimezone()
    return local_time.strftime(local_format)

utc = '2018-10-17T00:00:00.111Z'
utc_fmt = '%Y-%m-%dT%H:%M:%S.%fZ'
local_fmt = '%Y-%m-%dT%H:%M:%S+08:00'
local_string = utc_str_to_local_str(utc, utc_fmt, local_fmt)
print(local_string)   # 2018-10-17T08:00:00+08:00

for example, my timezone is '+08:00'. input utc = 2018-10-17T00:00:00.111Z, then I will get output = 2018-10-17T08:00:00+08:00


You can use calendar.timegm to convert your time to seconds since Unix epoch and time.localtime to convert back:

import calendar
import time

time_tuple = time.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
t = calendar.timegm(time_tuple)

print time.ctime(t)

Gives Fri Jan 21 05:37:21 2011 (because I'm in UTC+03:00 timezone).


Consolidating the answer from franksands into a convenient method.

import calendar
import datetime

def to_local_datetime(utc_dt):
    """
    convert from utc datetime to a locally aware datetime according to the host timezone

    :param utc_dt: utc datetime
    :return: local timezone datetime
    """
    return datetime.datetime.fromtimestamp(calendar.timegm(utc_dt.timetuple()))

If you want to get the correct result even for the time that corresponds to an ambiguous local time (e.g., during a DST transition) and/or the local utc offset is different at different times in your local time zone then use pytz timezones:

#!/usr/bin/env python
from datetime import datetime
import pytz    # $ pip install pytz
import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone() # get pytz tzinfo
utc_time = datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
local_time = utc_time.replace(tzinfo=pytz.utc).astimezone(local_timezone)

You can use arrow

from datetime import datetime
import arrow

now = datetime.utcnow()

print(arrow.get(now).to('local').format())
# '2018-04-04 15:59:24+02:00'

you can feed arrow.get() with anything. timestamp, iso string etc


I traditionally defer this to the frontend -- send times from the backend as timestamps or some other datetime format in UTC, then let the client figure out the timezone offset and render this data in the proper timezone.

For a webapp, this is pretty easy to do in javascript -- you can figure out the browser's timezone offset pretty easily using builtin methods and then render the data from the backend properly.


Here is a quick and dirty version that uses the local systems settings to work out the time difference. NOTE: This will not work if you need to convert to a timezone that your current system is not running in. I have tested this with UK settings under BST timezone

from datetime import datetime
def ConvertP4DateTimeToLocal(timestampValue):
   assert isinstance(timestampValue, int)

   # get the UTC time from the timestamp integer value.
   d = datetime.utcfromtimestamp( timestampValue )

   # calculate time difference from utcnow and the local system time reported by OS
   offset = datetime.now() - datetime.utcnow()

   # Add offset to UTC time and return it
   return d + offset

From the answer here, you can use the time module to convert from utc to the local time set in your computer:

utc_time = time.strptime("2018-12-13T10:32:00.000", "%Y-%m-%dT%H:%M:%S.%f")
utc_seconds = calendar.timegm(utc_time)
local_time = time.localtime(utc_seconds)

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to datetime

Comparing two joda DateTime instances How to format DateTime in Flutter , How to get current time in flutter? How do I convert 2018-04-10T04:00:00.000Z string to DateTime? How to get current local date and time in Kotlin Converting unix time into date-time via excel Convert python datetime to timestamp in milliseconds SQL Server date format yyyymmdd Laravel Carbon subtract days from current date Check if date is a valid one Why is ZoneOffset.UTC != ZoneId.of("UTC")?

Examples related to utc

Convert LocalDateTime to LocalDateTime in UTC How to set the timezone in Django? Java Convert GMT/UTC to Local time doesn't work as expected Should MySQL have its timezone set to UTC? How to Convert UTC Date To Local time Zone in MySql Select Query How to convert UTC timestamp to device local time in android Convert python datetime to epoch with strftime Convert Java Date to UTC String How do I get a UTC Timestamp in JavaScript? Converting datetime.date to UTC timestamp in Python

Examples related to localtime

How to convert java.sql.timestamp to LocalDate (java8) java.time? How to Convert UTC Date To Local time Zone in MySql Select Query Get the current time in C Convert UTC datetime string to local datetime How to convert local time string to UTC?