Convert a string representing the date or epoch time to datetime and change timezone in Python

Page content

Motivation

Because I always google the way to convert a string representing the date to datetime and change timezone on the Internet, this is note to self article.

There are three types to process date and time in Python. `datetime`, `date`, and `time`. I mainly use `datetime` in this article.

Environment

• python 3.6
• pytz
• jupyter notebook

Convert epoch time to datetime

Now convert numeric data types of `eopch time` to `datetime`.

The `epoch time` is also called as `Unix time` and this counts starts at the Unix Epoch on January 1st, 1970 at UTC. Therefore, the unix time is merely the number of seconds between a particular date and the Unix Epoch.

Just one thing to be careful of this conversion is to check whether the numeric types of epoch time is in second or millisecond. It is often the case that I judge it by digits or actual calculation by fuction.

Using the `fromtimestamp` function in `datetime` module makes the code simpler as well.

Covert epoch second

Sample code with `fromtimestamp` function is as bellow.

``````1import datetime
2
3e = 1524349374
4dt = datetime.datetime.fromtimestamp(e)
5
6print(dt)
7>> 2018-04-22 07:22:54``````

Covert epoch millisecond expressed in decimal

The `fromtimestamp` function can convert without problems even if a value is milliseconds format below the decimal point.

``````1import datetime
2
3mills = 1524349374.099776
4dt2 = datetime.datetime.fromtimestamp(mills)
5
6print(dt2)
7>> 2018-04-22 07:22:54.099776``````

Convert epoch millisecond expressed in integer

In milliseconds expressed as an integer (epoch millisecond notation), divide a value after checking how many digits represent milliseconds.

``````1import datetime
2
3mills = 1524349374099
4dt3 = datetime.datetime.fromtimestamp(mills / 1000)
5
6print(dt3)
7>> 2018-04-22 07:22:54.099000``````

Convert string to datetime

Convert date string with timezone

It is easy to convert date string with timezone to datetime by using `strptime` function. %z means that UTC offset in the form `+HHMM` or `-HHMM` and `%f` means microsecond as a decimal number which zero-padded on the left.

``````1import datetime
2
3utc_date_str = '2018-04-01 20:10:56.123+0900'
4dt = datetime.datetime.strptime(utc_date_str, '%Y-%m-%d %H:%M:%S.%f%z')
5
6print(dt)
7>> 2018-04-01 20:10:56.123000+09:00``````

Convert date string without timezone

Converting a date string without timezone to datetime is troublesome because checking what timezone the string represents is neccesarry. After checking the specification of data, using string joining is a quick solution.

`````` 1import datetime
2
3utc_date_str = '2018-04-01 20:10:56'
4# as JST
5dt = datetime.datetime.strptime(utc_date_str + '+0900', '%Y-%m-%d %H:%M:%S%z')
6
7print(dt)
8print(dt.tzinfo)
9>> 2018-04-01 20:10:56+09:00
10>> UTC+09:00``````

Here's another way to use `parse` function in `dateutil` library. The way to giving `tzinfos` object to argument, compared to the previous `fromtimestamp` example, improves readability of the code.

``````1import datetime
2from dateutil.parser import parse
3from dateutil.tz import gettz
4
5tzinfos = {'JST' : gettz('Asia/Tokyo')}
6date_str = '2018-04-01 20:10:56'
7str_to_dt = parse(date_str + ' JST', tzinfos=tzinfos)
8print(str_to_dt)``````

Points to keep in mind when dealing with date and time

naive and aware

In dealing with date and time in Python, keep in mind two kind of data naive and aware.

The official Python document says as below,

• aware

An aware object has sufficient knowledge of applicable algorithmic and political time adjustments, such as time zone and daylight saving time information, to locate itself relative to other aware objects. An aware object is used to represent a specific moment in time that is not open to interpretation

• naive

A naive object does not contain enough information to unambiguously locate itself relative to other date/time objects. Whether a naive object represents Coordinated Universal Time (UTC), local time, or time in some other timezone is purely up to the program, just like it is up to the program whether a particular number represents metres, miles, or mass. Naive objects are easy to understand and to work with, at the cost of ignoring some aspects of reality.

In short, the `aware` object should be used in dealing with time data with timezone.

However, relationship between types and `aware`/`naive` objects is complicated because objects created from types are not unique.

typesobject
datenaive
timenaive or aware
datetimenaive or aware

Whether the `time` and` datetime` types are `aware` or` naive` can be checked below.

objectcondition to become awarecondition to become naive
time`t.tzinfo` of object `t` is not None, and `t.tzinfo.utcoffset(None)` returns not NoneOther than aware
datetime`t.tzinfo` of object `t` is not None, and `t.tzinfo.utcoffset(t)` returns not None`d.tzinfo` is None. Or `d.tzinfo` is not None and `d.tzinfo.utcoffset(d)` returns None

Pay attention to processing with timezone on application execution environment

If executing the timezone conversion code without paying attention to aware and naive, the response of code will be changed depending on runtime environment.

`````` 1import datetime
2from pytz import timezone
3import pytz
4
5date_str = '2018-04-01 20:10:56'
6# str_to_dt is `naive`
7str_to_dt = datetime.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
8print("Str to dt")
9print(str_to_dt)                      # 2018-04-01 20:10:56
10print(str_to_dt.timestamp())          # 1522581056.0
11print(str_to_dt.tzname())             # None
12
13# calculating with naive object, returns wrong time
14utc = timezone('UTC')
15utc_dt = str_to_dt.astimezone(utc)
16print("UTC dt")
17print(utc_dt)                         # 2018-04-01 11:10:56+00:00
18print(utc_dt.timestamp())             # 1522581056.0
19print(utc_dt.tzname())                # UTC
20print(utc_dt.tzinfo.utcoffset(utc_dt))# 0:00:00
21
22jst = timezone('Asia/Tokyo');
23jst_dt = str_to_dt.astimezone(jst);
24print("JST dt")
25print(jst_dt)                         # 2018-04-01 20:10:56+09:00
26print(jst_dt.timestamp())             # 1522581056.0
27print(jst_dt.tzname())                # JST
28print(jst_dt.tzinfo.utcoffset(jst_dt))# 9:00:00``````

In the example code above it shows conversion of string without timezone to datetime as variable named `str_to_dt`. And when changing timezone with `astimezone` function, relative calculation is performed from the timezone on the runtime environment to the target timezone.

For that reason, when using multiple regions of the public cloud,
behavior may be different depending on where the program is deployed.

Conclusion

It is available to

• Convert epochtime (second and millsecond) to datetime with `fromtimestamp` function
• Convert string to datetime with `strptime` function
• Change timezone with `dateutil` library

And in dealing with date and time in Python, keep in mind two kind of data naive and aware.