Using Python datetime to Work With Dates and Times

Datetime module, extensions and more...

Each time, I try to solve a problem that I have encountered or wondered about by thinking about the programming languages that I am familiar with, such as R, Python, JS, and the different libraries these languages have. The main reason for this comparison is that I want to practice by keeping my memory sharp and being open to different solution methods. I will post a few more articles on this subject.

In this article, I will explain how we can use the datetime module that the Python programming language offers as a built-in in this article and give some examples.

AA

With the lubridate package, which is a part of the tidyverse collection developed for the R programming language, we can operate comprehensive date and time operations and manage data types easily1.

On the JavaScript/NodeJS side, there is the datetime module that I can remember2. On the Python side, the well-known module is offered with the name datetime by default as well. Besides, I did a little research about alternative packages that could be used, and in the last part of the article, mentioned them.

Datetime Module

Python does not have any date-time data types. However, with the datetime module, we can use the strings as date-time.

While working on an example, I had the opportunity to examine both the datetime module documentation and perform sample operations on the presented methods for date operations. In this article, I would like to share the short notes I took and give a few simple examples3 4.

The date operation in the relevant example was as follows:

currentTime = datetime.datetime.today().strftime('%Y-%m-%d') # '2021-07-31'
previousTime = (datetime.datetime.today() - datetime.timedelta(days=7)).strftime('%Y-%m-%d') # '2021-07-24'

We can include the datetime module in our works with import datetime or we only call the relevant class for specified operations such as date, time, and datetime.

from datetime import datetime # datetime.now()
# import datetime # datetime.datetime.now()

# dir(datetime.datetime)
# ['__add__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__radd__', '__reduce__', '__reduce_ex__', '__repr__', '__rsub__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', 'astimezone', 'combine', 'ctime', 'date', 'day', 'dst', 'fold', 'fromisoformat', 'fromordinal', 'fromtimestamp', 'hour', 'isocalendar', 'isoformat', 'isoweekday', 'max', 'microsecond', 'min', 'minute', 'month', 'now', 'replace', 'resolution', 'second', 'strftime', 'strptime', 'time', 'timestamp', 'timetuple', 'timetz', 'today', 'toordinal', 'tzinfo', 'tzname', 'utcfromtimestamp', 'utcnow', 'utcoffset', 'utctimetuple', 'weekday', 'year']

While the date class enables operations related to dates, time contains time-related operations. datetime includes date and time classes.

NOW and TODAY

The now() and today() methods give us the current year, month, day, hour, minute, second, and microsecond information. It is also possible to call this time information separately.

datetime.datetime.today() # datetime.datetime(2021, 7, 31, 19, 31, 46, 197762)

datetime.datetime.now().year # 2021
datetime.datetime.now().month # 7
datetime.datetime.now().day # 31
datetime.datetime.now().hour # 19
datetime.datetime.now().minute # 31
datetime.datetime.now().second # 46
datetime.datetime.now().microsecond # 197762

STRFTIME and STRPTIME

The strftime() method allows us to manage the date and time formats via directives, and as a result of this process, the date object is converted to a character string.

datetime.datetime.now().strftime(format='%Y') # 2021
datetime.datetime.now().strftime(format='%m/%d/%y') # 07/31/21
datetime.datetime.now().strftime(format='%x') # 07/31/21
datetime.datetime.now().strftime(format='%d.%m.%Y') # 31.07.2021

The strptime() method, on the other hand, allows us to convert a string of characters to a date object using date and time formats.

datetime.datetime.strptime('31 July 2014 12:34:44', '%d %B %Y %H:%M:%S') # datetime.datetime(2014, 7, 31, 12, 34, 44)
datetime.datetime.strptime('07/31/21', '%m/%d/%y') # datetime.datetime(2021, 7, 31, 0, 0)
datetime.datetime.strptime('07/31/21', '%x') # datetime.datetime(2021, 7, 31, 0, 0)

In another example, let's convert date-time data with different separators into date types. At this stage, I will also include the re package, which allows us to perform regex operations, in the example.

import re
dates = [datetime.datetime.strptime(re.sub('[^0-9]', '/', d), '%m/%d/%Y') for d in ['11-23-2021', '05/06/1991', '10 10 2000']]
print(dates)

Some of The Most Used Directives

The table below shows some of the frequently used directives5 6.

Direktif Anlamı Örnek
%X Locally formatted time 21:30:00 (en_US)
%x Locally formatted date 08/16/1988 (en_US)
%Y 4 digit year 2021, 1990, vb.
%y 2 digit year 21,90, vb.
%m Numerically the month 01, 10, 12
%B Locally formated month July, Temmuz, vb.
%b Locally formated, shortened month Jul, Tem, vb.
%A Locally formated name of the day Monday, Pazartesi, vb.
%a Locally adapted, shortened name of the day Mon, Pzt, vb.
%w Numerical day of the week 0 (Sunday), 3, 6, vb.
%d Numerical day of the month 01, 22, 31, vb.
%H 24-hour time 00, 11, 23, vb.
%I 12-hour time 01, 10, 24, vb.
%p Locally formated day period AM, ÖÖ, PM, ÖS
%M Minute 00,33,59
%S Second 00, 33, 59
%Z Time zone UTC, EST, GMT, vb.
%z Time zone in numeric format +0000, -0400, vb.

Local definitions may vary depending on the system. You can execute the locale -a command on the command line to see the selectable definitions. It will return an output like this command.

C
C.UTF-8
en_US.utf8
tr_TR
POSIX

It is also possible to display local information with the Python module locale7.

import locale
print(locale.getlocale()) # ('en_US', 'UTF-8')

We can use the setlocale() method to select options listed with locale -a.

locale.setlocale(locale.LC_ALL, 'en_US')
datetime.datetime.now().strftime(format='%b') # Aug
datetime.datetime.now().strftime(format='%x') # 07/31/2021

locale.setlocale(locale.LC_ALL, 'tr_TR')
datetime.datetime.now().strftime(format='%b') # Ağu
datetime.datetime.now().strftime(format='%x') # 31/07/2021

CTIME

The ctime() method returns a legible character string of the specified date and time.

datetime.datetime.today().ctime() # Sat Jul 31 21:21:24 2021
datetime.datetime(2021, 7, 1).ctime() # Thu Jul  1 00:00:00 2021
(datetime.datetime.today() - datetime.timedelta(days=217)).ctime() # Sat Dec 26 21:24:04 2020
datetime.datetime.ctime(datetime.datetime.now()) # Sun Aug  1 07:21:55 2021

TIMESTAMP and FROMTIMESTAMP

In file/directory operations, we display values such as the creation and modified dates in timestamp format.

os.stat('Image.png').st_mtime #1627801430.7354434

The timestamp() method allows us to convert date and time values into timestamp format.

datetime.datetime.today().timestamp() # 1627802786.984535
(datetime.datetime.today() - datetime.timedelta(days=217)).timestamp() # 1609054148.42208
datetime.datetime.fromtimestamp(datetime.datetime.timestamp(datetime.datetime.now())) # datetime.datetime(2021, 8, 1, 7, 33, 7, 576549)

The fromtimestamp() method enables the time stamp to be converted to a human readable format.

datetime.datetime.fromtimestamp(1627802786.984535) # datetime.datetime(2021, 8, 1, 7, 26, 26, 984535)

Other Methods

Let's briefly mention other issues that we use for time operations.

ISOFORMAT and FROMISOFORMAT

The isoformat() method allows us to get the date-time value in ISO format.

datetime.datetime.utcfromtimestamp(1627804283.441646).isoformat() # 2021-08-01T07:51:23.441646

The fromisoformat() method converts the historical expression in ISO format into a datetime object.

datetime.fromisoformat('2021-08-01T00:05:23') # datetime.datetime(2021, 8, 1, 0, 5, 23)

TIMEDELTA

The Timedelta object represents a period, the difference between two dates or times, so comparisons and mathematical operations can be performed8.

datetime.datetime.today() - datetime.timedelta(days=7) # datetime.datetime(2021, 7, 25, 8, 2, 45, 800333)
datetime.datetime.today() + datetime.timedelta(days=-127) # datetime.datetime(2021, 3, 27, 8, 16, 3, 744547)
(datetime.datetime.today() - datetime.timedelta(days=50, hours=8, seconds=27, microseconds=10, minutes=5)).isoformat() # 2021-06-11T23:59:19.479398

REPLACE

datetime.datetime(2002, 12, 31).replace(day=15) # datetime.datetime(2002, 12, 15, 0, 0)
datetime.datetime(2021, 5, 10).replace(year=1995, month=11, day=15).isocalendar() # (1995, 46, 3)

OTHER MODULES

PANDAS

In addition to the default datetime module, it is possible to perform operations with datetime and timedelta objects offered in Pandas9 10.

import pandas as pd
pd.to_datetime("1th of Aug, 2021") # Timestamp('2021-08-01 00:00:00')

df = pd.DataFrame(['2021-10-05', '2019-05-06', '2015-03-11'], columns=['Dates'])
[(pd.Timestamp(dt) + pd.Timedelta('-15 day')).day_name() for dt in df['Dates']] # ['Monday', 'Sunday', 'Tuesday']

pd.Timedelta("1 days 2 hours") # Timedelta('1 days 02:00:00')
pd.Timedelta(pd.offsets.Day(2)) # Timedelta('2 days 00:00:00')

pd.Series(pd.date_range("2012-1-1", periods=3, freq="D"))
'''
0   2012-01-01
1   2012-01-02
2   2012-01-03
dtype: datetime64[ns]
'''

pd.date_range("2018-01-01", periods=3, freq="H")
'''
DatetimeIndex(['2018-01-01 00:00:00', '2018-01-01 01:00:00', '2018-01-01 02:00:00'],
dtype='datetime64[ns]', freq='H')
'''

DATEUTIL

dateutil can be considered a more practical and improved version of datetime11.

from datetime import *; from dateutil.relativedelta import *
import calendar

NOW = datetime.now()
TODAY = date.today()
print(NOW) # 2021-08-01 08:43:27.891459
print(TODAY) # 2021-08-01

NOW+relativedelta(months=+1) # datetime.datetime(2021, 9, 1, 8, 45, 51, 522361)

ARROW

Arrow developed for Python is comparable to the lubridate package developed for the R programming language12. Especially its time zones methods are so handy.

import arrow

arrow.utcnow() # <Arrow [2021-08-01T08:49:17.631022+00:00]>
arrow.utcnow().shift(hours=-1) # <Arrow [2021-08-01T07:50:21.604033+00:00]>
arrow.utcnow().to('GMT+3') # <Arrow [2021-08-01T11:53:15.176165+03:00]>
arrow.utcnow().to('GMT-3').shift(hours=-1) # <Arrow [2021-08-01T10:54:03.573688+03:00]>
arrow.utcnow().to('EST').shift(hours=2).humanize() # in 2 hours

SIMPLEDATE

The Simpledate package offers several facilitating methods, especially converting between formats, such as timezone and formats13.

!pip install pytz tzlocal simple-date

import simpledate

simpledate.SimpleDate(tz='America/New_York') # SimpleDate('2021-08-01 05:19:47.150963 EDT', tz='America/New_York')
simpledate.SimpleDate(tz=120, format='%Y-%m-%d %z') # SimpleDate('2021-08-01 +0200', tz='pytz.FixedOffset(120)')
simpledate.SimpleDate('2013-01-01', tz='EST', country='US') # SimpleDate('2013-01-01')
simpledate.SimpleDate('6/12/2013', format='%m/%d/%Y') # SimpleDate('06/12/2013', tz='Etc/UTC')

[simpledate.best_guess_utc(date) for date in ['1/6/2013 BST', '1/6/2013 EST', 'Tue, 18 Jun 2013 12:19:09 -0400']]
'''
[datetime.datetime(2013, 5, 31, 23, 0, tzinfo=<UTC>),
 datetime.datetime(2013, 1, 6, 5, 0, tzinfo=<UTC>),
 datetime.datetime(2013, 6, 18, 16, 19, 9, tzinfo=<UTC>)]
'''

pd.date_range("2018-01-01", periods=3, freq="H")
'''
DatetimeIndex(['2018-01-01 00:00:00', '2018-01-01 01:00:00', '2018-01-01 02:00:00'],
dtype='datetime64[ns]', freq='H')
'''

pd.date_range(start='1/1/2018', end='1/08/2018')
'''
DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
               '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'],
              dtype='datetime64[ns]', freq='D')
'''

pd.date_range(start='1/1/2018', periods=5, freq='M')
'''
DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30',
               '2018-05-31'],
              dtype='datetime64[ns]', freq='M')
'''

df = pd.DataFrame({'Dates': ['2021-10-05', '2021-10-06', '2021-10-04','2021-11-15', '2021-11-21', '2021-11-09'], 'Counts': [20,23,41,55,32,24]})
df['Dates'] = pd.to_datetime(df['Dates'])
df.resample('M', on='Dates')['Counts'].mean()

'''
Dates
2021-10-31    28.0
2021-11-30    37.0
Freq: M, Name: Counts, dtype: float64
'''

df['Counts'].groupby(df['Dates'].dt.month).mean()
'''
Dates
10    28.0
11    37.0
Name: Counts, dtype: float64
'''

That's all for now, my notes on the datetime package. I will continue to add new notes and examples in the future.