Skip to content

Datetime

Foreword

Notes. Python 2 & 3. Consult the Hitchicker’s Guide to Python.


The datatime library

When building an application incorporating a time triggers, events, records log entries, and much more, we need to deal with dates and times; and time zones. Whether it is a simple script that starts every morning to scrape web data, build a report, and send emails or a comprehensive web framework script that records data entries.

now or any date-time

The datatime library has handy built-in functions: date, time, datetime, timedelta, and tzinfo. The following script demonstrates some of the functionalities.

import datetime

print "The datatime library: "
print dir(datetime)
print "=" * 25

print "The current datetime: "
print datetime.datetime.now()

print "...in a variable: "
test_start = datetime.datetime.now()
print test_start
print "=" * 25

print "Replace the attributes: new formatting."
test_start = test_start.replace(hour=7, minute=39, second = 0, microsecond=0)
print test_start
print "=" * 25

Results.

import datetime

The datatime library: 
['MAXYEAR', 'MINYEAR', '__doc__', '__name__', '__package__', 'date', 'datetime', 'datetime_CAPI', 'time', 'timedelta', 'tzinfo']
=========================

The current datetime: 
2016-04-08 10:03:06.120000
...in a variable: 
2016-04-08 10:03:06.120000
=========================

Replace the attributes: new formatting.
2016-04-08 07:39:00
=========================

Date-time difference

Create a date-time and compute the time difference.

import datetime

print "Start: "
print test_start
print "=" * 25

duration = datetime.datetime.now() - test_start
print "duration = datetime.datetime.now() - test_start: "
print "duration = ", duration
print "day = ", duration.days
print "microseconds = ", duration.microseconds
print "seconds = ", duration.seconds
print "hours (round(seconds/3600)) = ", round(duration.seconds/3600)

Results.

Start: 
2016-04-08 07:39:00
=========================

duration = datetime.datetime.now() - test_start: 
duration =  2:24:06.120000
day =  0
microseconds =  120000
seconds =  8646
hours (round(seconds/3600)) =  2.0
minutes (round(seconds/60)) =  144.0
=========================

Measure duration with timedelta

Create a delta.

print "datetime.datetime.now():"
print datetime.datetime.now()

print "datetime.datetime.now() + datetime.timedelta(days=3): "
print datetime.datetime.now() + datetime.timedelta(days=3)
print "...........................................(days=-5): "
print datetime.datetime.now() + datetime.timedelta(days=-5)
print "...........................................(days=-1): "
print datetime.datetime.now() + datetime.timedelta(days=-1)
print "=" * 25
print ""

print "datetime.datetime.now() + datetime.timedelta(hours=1): "
print datetime.datetime.now() + datetime.timedelta(hours=1)
print "datetime.datetime.now() + datetime.timedelta(0, 3600): "
print datetime.datetime.now() + datetime.timedelta(0, 3600)
print "=" * 25
print ""

work = 9
print "work = ", work

print "datetime.datetime.now() + datetime.timedelta(hours=work):"
print datetime.datetime.now() + datetime.timedelta(hours=work)
print "=" * 25
print ""

Results.

datetime.datetime.now():
2016-04-08 10:06:25.895000
datetime.datetime.now() + datetime.timedelta(days=3): 
2016-04-11 10:06:25.895000
...........................................(days=-5): 
2016-04-03 10:06:25.895000
...........................................(days=-1): 
2016-04-07 10:06:25.895000
=========================

datetime.datetime.now() + datetime.timedelta(hours=1): 
2016-04-08 11:06:25.895000
datetime.datetime.now() + datetime.timedelta(0, 3600): 
2016-04-08 11:06:25.895000
=========================

work =  9
datetime.datetime.now() + datetime.timedelta(hours=work):
2016-04-08 19:06:25.895000
=========================

Use timedelta.

print "Simplify: "
now = datetime.datetime.now()
print "now: "
print now
print "now.date: "
print now.date()
print "now.time: "
print now.time()
print "=" * 25
print ""

print "1 hour: "
hour = datetime.timedelta(hours=1)
print hour
print "=" * 25
print ""

print "Add 1 day: "
tomorrow = datetime.datetime.now().replace(hour=9, minute=0) + datetime.timedelta(days=1)
print tomorrow

print "Add 1 day (2): "
workday = datetime.timedelta(hours=8)
print tomorrow + workday
print "=" * 25
print ""

print "Appointment: "
appointment = datetime.timedelta(minutes=45)
# year, month, day, hour, minute
start =  datetime.datetime(2016, 8, 17, 12, 45)
end = start + appointment
print end
print "=" * 25
print ""

Results.

Simplify: 
now: 
2016-04-08 10:16:11.476000
now.date: 
2016-04-08
now.time: 
10:16:11.476000
=========================

1 hour: 
1:00:00
=========================

Add 1 day: 
2016-04-09 09:00:11.476000
Add 1 day (2): 
2016-04-09 17:00:11.476000
=========================

Appointment: 
2016-08-17 13:30:00
=========================

now vs. today

The difference between now and today is…

import datetime

now = datetime.datetime.now()
today = datetime.datetime.today()
print now
print today
print "=" * 25
print ""

Results.

2016-04-08 10:34:28.444000
2016-04-08 10:34:28.444000
=========================

now can take a timezone. We deal with timezones further down. Today

import datetime

today = datetime.datetime.combine(datetime.date.today(), datetime.time())
print today # today at midnight
print today.month
print today.hour
print today.year
print today.weekday() # 0 = Monday, 1, 2, 3, 4
print "=" * 25
print ""

Results.

2016-04-08 00:00:00
4
0
2016
5
=========================

Formatting date-time

Format date and time.

import datetime

now = datetime.datetime.now()
print now

# how to better present
# strftime (strings-from-time) or turn datetime digits into strings

print "formatting datetime:"
print now.strftime('%B %d')
print now.strftime('%m/%m/%y')

Results.

2016-04-08 11:08:26.757000
formatting datetime:
April 08
04/04/16

strptime (strings-parse-time) turns strings into datetime digits. Look for help online for date and time types.

import datetime

print "Formatting datetime: "
print now.strftime('%B %d')
print now.strftime('%m/%m/%y')
print "=" * 25
print ""

print "bithday: "
birthday = datetime.datetime.strptime('2016-04-21', '%Y-%m-%d')
print birthday
print "=" * 25
print ""

print "bithday_party: "
birthday_party = datetime.datetime.strptime('2016-04-22 12:00', '%Y-%m-%d %H:%M')
print birthday_party
print "=" * 25
print ""

Results.

Formatting datetime: 
April 08
04/04/16
=========================

bithday: 
2016-04-21 00:00:00
=========================

bithday_party: 
2016-04-22 12:00:00
=========================

A little printing app

Build an application that prints out a date in a sentence.

import datetime

answer_format = '%m/%d'
link_format = '%b_%d'
link = 'https://en.wikipedia.org/wiki/{}'

while True:
    answer = raw_input("What date would you like? Please use the MM/DD format. Enter 'q' to quit.")
    answer2 = str(answer)
    if answer2.upper() == 'Q':
        break

    try:
        date = datetime.datetime.strptime(answer, answer_format)
        output = link.format(date.strftime(link_format))
        print(output)
        file = open('output.txt', 'w')
        file.write(output)
        file.close()
    except:
        print("That's not a valid date. Please try again.")
        break

Run it; it creates an output file. Open output.txt. Copy the link and paste it into a web browser.

Build a Quiz application

Build the skeleton

Build an application (questions.py) that add and multiply numbers.

import datetime

class Question:
    answer = None
    text = None


class Add(Question):
    def __init__(self, num1, num2):
        self.text = '{} + {}'.format(num1, num2)
        self.answer = num1 + num2


class Multiply(Question):
    def __init__(self, num1, num2):
        self.text = '{} x {}'.format(num1, num2)
        self.answer = num1 * num2


print "Add: "
add1 = Add(5, 7)
print add1.text
print add1.answer
print "Multiply: "
multiply1 = Multiply(2, 2)
print multiply1.text
print multiply1.answer

Results.

Add: 
5 + 7
12
Multiply: 
2 x 2
4

Import the questions.py module in another script: quiz.py. Build the skeleton.

import datetime
import random

from questions import Add, Multiply # import the other module


class Quiz:
    questions = []
    answers = []

    def __init__(self):
        # generate 10 random questions with numbers from 1 to 10
        # add these questions into self.questions
        pass

    def take_quiz(self):
        # log the start time
        # ask all of the questions
        # log if they got the question right
        # log the end time
        # show a summary
        pass

    def ask(self, question):
        # log the start time
        # capture the answer
        # check the answer
        # log the end time
        # if the answer's right, send back True
        # otherwise, send back False
        # send back the elapses time, too
        pass


    def total_correct(self):
        # return the total # of correct answers
        pass


    def summary(self):
        # print how many you got right and the total of questions: 5/10
        # print the total time for the quiz: 30 seconds!
        pass

Results (similar).

Add: 
5 + 7
12
Multiply: 
2 x 2
4

Generate questions

Complete some functions and test the script.

import datetime
import random

from questions import Add, Multiply


class Quiz: # ADD
    questions = []
    answers = []

    def __init__(self):
        """
        generate 10 random questions with numbers from 1 to 10
        add these questions into self.questions
        """
        question_types = (Add, Multiply)

        for _ in range(10): # _ we don't care if it's 1, 5 or 12, as long as it is a number
            num1 = random.randint(1, 10)
            num2 = random.randint(1, 10)
            question = random.choice(question_types)(num1, num2)
            # add these questions into self.questions
            self.questions.append(question)

    def take_quiz(self):
        # log the start time
        # ask all of the questions
        # log if they got the question right
        # log the end time
        # show a summary
        pass

    def ask(self, question):
        # log the start time
        # capture the answer
        # check the answer
        # log the end time
        # if the answer's right, send back True
        # otherwise, send back False
        # send back the elapses time, too
        pass


    def total_correct(self): # ADD
        """return the total # of correct answers"""
        total = 0
        for answer in self.answers:
            if answer[0]:
                total += 1
        return total

    def summary(self): # ADD
        """
        print how many you got right and the total of questions: 5/10
        print the total time for the quiz: 30 seconds!
        """
        print("You got {} out of {} right.".format(
                self.total_correct(), len(self.questions)
        ))
        print("It took you {} seconds total.".format(
                (self.end_time-self.start_time).seconds
        ))


quiz1 = Quiz()
print quiz1.answers
print quiz1.questions
print "=" * 25
print quiz1.questions[0].text
print quiz1.questions[0].answer

Results.

Add: 
5 + 7
12
Multiply: 
2 x 2
4
[]
[<questions.Add instance at 0x00000000022B7E88>, <questions.Multiply instance at 0x00000000022FBC88>, <questions.Multiply instance at 0x00000000022FB688>, <questions.Multiply instance at 0x00000000022FBDC8>, <questions.Add instance at 0x00000000022FBE08>, <questions.Multiply instance at 0x00000000022FBE48>, <questions.Multiply instance at 0x00000000022FBE88>, <questions.Add instance at 0x00000000022FBEC8>, <questions.Multiply instance at 0x00000000022FBF08>, <questions.Multiply instance at 0x00000000022FBF48>]
=========================
3 + 1
4

Finalize the application

Complete the script and test it.

import datetime
import random

from questions import Add, Multiply


class Quiz:
    questions = []
    answers = []

    def __init__(self):
        """
        generate 10 random questions with numbers from 1 to 10
        add these questions into self.questions
        """
        question_types = (Add, Multiply)

        for _ in range(10): # _ we don't care if it's 1, 5 or 12, as long as it is a number
            num1 = random.randint(1, 10)
            num2 = random.randint(1, 10)
            question = random.choice(question_types)(num1, num2)
            # add these questions into self.questions
            self.questions.append(question)

    def take_quiz(self): # ADD
        """
        log the start time, ask all of the questions
        log if they got the question right, log the end time
        show a summary
        """
        # log the start time
        self.start_time = datetime.datetime.now()

        # ask all of the questions
        for question in self.questions:
            self.answers.append(self.ask(question))
        else: # if the loop reached the end, so else happends
            self.end_time = datetime.datetime.now()

        # show a summary
        return self.summary()     


    def ask(self, question): # ADD
        """
        log the start time, capture the answer, check the answer
        log the end time, if the answer's right, send back True
        otherwise, send back False, send back the elapses time, too
        """
        correct = False
        # log the start time
        question_start = datetime.datetime.now()

        # capture the answer
        answer = raw_input(question.text + ' = ')

        # check the answer
        if answer == str(question.answer):
            correct = True

        # log the end time
        question_end = datetime.datetime.now()

        # if the answer's right, send back True
        # otherwise, send back False
        # send back the elapses time, too
        return correct, question_end - question_start


    def total_correct(self):
        """return the total # of correct answers"""
        total = 0
        for answer in self.answers:
            if answer[0]:
                total += 1
        return total

    def summary(self):
        """
        print how many you got right and the total of questions: 5/10
        print the total time for the quiz: 30 seconds!
        """
        print("You got {} out of {} right.".format(
                self.total_correct(), len(self.questions)
        ))
        print("It took you {} seconds total.".format(
                (self.end_time-self.start_time).seconds
        ))


Quiz().take_quiz() # ADD

The results are dynamic. We would get something that look like the following:

Add: 
5 + 7
12
Multiply: 
2 x 2
4
7 x 6 = 54
9 x 10 = 90
4 x 3 = 12
3 + 6 = 9
5 + 6 = 11
10 x 6 = 60
4 x 6 = 24
9 + 9 = 18
2 x 5 = 10
8 + 3 = 11
You got 9 out of 10 rights.
It took you 21 seconds total.

Time zones

Timezones are major challenges for websites and web frameworks. The following is coded in Python 3 since the most common Python frameworks (Flask, Django, Pyramid) at the time this documentation is written work under Python 3. One of the reason is the multi-language ability.

Time zones with datatime only

We build two timezone-aware variables.

import datetime

pacific = datetime.timezone(datetime.timedelta(hours=-8))
eastern = datetime.timezone(datetime.timedelta(hours=-5))

print(pacific)
print(eastern)

Results.

UTC-08:00
UTC-05:00

We build one timezone-naive variable and one timezone-aware variable.

# ...

naive = datetime.datetime(2014, 4, 21, 9)
print(naive)

aware = datetime.datetime(2014, 4, 21, 9, tzinfo=pacific)
print(aware)

Results.

2014-04-21 09:00:00
2014-04-21 09:00:00-08:00

Show these in eastern time.

# ...

print(naive.astimezone(eastern))

Results: cannot be applied to a naive datetime.

# ...

print(aware.astimezone(eastern))

Results.

2014-04-21 12:00:00-05:00

Other interesting time zones.

# ...

aukland = datetime.timezone(datetime.timedelta(hours=13))
print(aukland)
print(aware.astimezone(aukland))
print("=" * 25)

mumbai = datetime.timezone(datetime.timedelta(hours=13, minutes=30))
print(mumbai)
print(aware.astimezone(mumbai))

Results.

UTC+13:00
2014-04-22 06:00:00+13:00
=========================
UTC+05:30
2014-04-21 22:30:00+05:30

Time zones with datatime and pytz

pytz simplify things (a lot!).

import datetime
import pytz

pacific = pytz.timezone('US/Pacific')
eastern = pytz.timezone('US/Eastern')

fmt = '%Y-%m-%d %H:%M:%S %Z%z'
utc = pytz.utc

print("set: ")
start = pacific.localize(datetime.datetime(2014, 4, 21, 9))
print(start.strftime(fmt))
print("=" * 25)

print("convert: ")
start_eastern = start.astimezone(eastern)
print(start_eastern)
print("=" * 25)

print(start)
print("=" * 25)

Results.

set: 
2014-04-21 09:00:00 PDT-0700
=========================
convert: 
2014-04-21 12:00:00-04:00
=========================
2014-04-21 09:00:00-07:00
=========================

More conversions.

# ...

print("set: ")
start_utc = datetime.datetime(2014, 4, 21, 1, tzinfo=utc)
print(start_utc.strftime(fmt))
print("=" * 25)

print("convert: ")
start_pacific = start_utc.astimezone(pacific)
print(start_pacific)
print("=" * 25)

Results.

set: 
2014-04-21 01:00:00 UTC+0000
=========================
convert: 
2014-04-20 18:00:00-07:00
=========================

Set a date-time and convert it.

# ...

print("set aukland and mumbai")
auckland = pytz.timezone('Pacific/Auckland')
mumbai = pytz.timezone('Asia/Calcutta')

print("create a date")
apollo_13_naive = datetime.datetime(1970, 4, 11, 14, 13)
apollo_13_eastern = eastern.localize(apollo_13_naive)

print("print it: ")
print(apollo_13_naive)
print(apollo_13_eastern)
print("=" * 25)

print("convert it, change location: ")
apollo_13_utc = apollo_13_eastern.astimezone(utc)
print(apollo_13_utc.astimezone(pacific).strftime(fmt))
print(apollo_13_utc.astimezone(auckland))
print(apollo_13_utc.astimezone(mumbai))

Results.

set aukland and mumbai
create a date
print it: 
1970-04-11 14:13:00
1970-04-11 14:13:00-05:00
=========================
convert it, change location: 
1970-04-11 11:13:00 PST-0800
1970-04-12 07:13:00+12:00
1970-04-12 00:43:00+05:30

Find out more about pytz

Find out about timezones: print(pytz.all_timezones). Or focus on a country’s timezones. The US.

print(pytz.country_timezones['us'])

Results.

['America/New_York', 'America/Detroit', 'America/Kentucky/Louisville', 'America/Kentucky/Monticello', 'America/Indiana/Indianapolis', 'America/Indiana/Vincennes', 'America/Indiana/Winamac', 'America/Indiana/Marengo', 'America/Indiana/Petersburg', 'America/Indiana/Vevay', 'America/Chicago', 'America/Indiana/Tell_City', 'America/Indiana/Knox', 'America/Menominee', 'America/North_Dakota/Center', 'America/North_Dakota/New_Salem', 'America/North_Dakota/Beulah', 'America/Denver', 'America/Boise', 'America/Phoenix', 'America/Los_Angeles', 'America/Anchorage', 'America/Juneau', 'America/Sitka', 'America/Metlakatla', 'America/Yakutat', 'America/Nome', 'America/Adak', 'Pacific/Honolulu']

Canada.

print(pytz.country_timezones['ca'])

Results.

['America/St_Johns', 'America/Halifax', 'America/Glace_Bay', 'America/Moncton', 'America/Goose_Bay', 'America/Blanc-Sablon', 'America/Toronto', 'America/Nipigon', 'America/Thunder_Bay', 'America/Iqaluit', 'America/Pangnirtung', 'America/Atikokan', 'America/Winnipeg', 'America/Rainy_River', 'America/Resolute', 'America/Rankin_Inlet', 'America/Regina', 'America/Swift_Current', 'America/Edmonton', 'America/Cambridge_Bay', 'America/Yellowknife', 'America/Inuvik', 'America/Creston', 'America/Dawson_Creek', 'America/Fort_Nelson', 'America/Vancouver', 'America/Whitehorse', 'America/Dawson']

Russia.

print(pytz.country_timezones['ru'])

Results.

['Europe/Kaliningrad', 'Europe/Moscow', 'Europe/Simferopol', 'Europe/Volgograd', 'Europe/Kirov', 'Europe/Astrakhan', 'Europe/Saratov', 'Europe/Ulyanovsk', 'Europe/Samara', 'Asia/Yekaterinburg', 'Asia/Omsk', 'Asia/Novosibirsk', 'Asia/Barnaul', 'Asia/Tomsk', 'Asia/Novokuznetsk', 'Asia/Krasnoyarsk', 'Asia/Irkutsk', 'Asia/Chita', 'Asia/Yakutsk', 'Asia/Khandyga', 'Asia/Vladivostok', 'Asia/Ust-Nera', 'Asia/Magadan', 'Asia/Sakhalin', 'Asia/Srednekolymsk', 'Asia/Kamchatka', 'Asia/Anadyr']

Build a script to convert time zones

Build a script that takes a datetime and give it back in 6 other timezones. For any given datetime, an appointment for example, we can know the equivalent elsewhere in the world.

from datetime import datetime

import pytz

OTHER_TIMEZONES = [
    pytz.timezone('US/Eastern'),
    pytz.timezone('Pacific/Auckland'),
    pytz.timezone('Asia/Calcutta'),
    pytz.timezone('UTC'),
    pytz.timezone('Europe/Paris'),
    pytz.timezone('Africa/Khartoum'),
]

fmt = '%Y-%m-%d %H:%M:%S %Z%z'

while True:
    date_input = input("When is your meeting? Please use MM/DD/YYYY HH:MM format. ")
    try:
        local_date = datetime.strptime(date_input, '%m/%d/%Y %H:%M')
    except ValueError:
        print("{} doesn't seem to be a valid date & time.".format(date_input))
    else:
        local_date = pytz.timezone('US/Pacific').localize(local_date)
        utc_date = local_date.astimezone(pytz.utc)

        output = []
        for timezone in OTHER_TIMEZONES:
            output.append(utc_date.astimezone(timezone))
        for appointment in output:
            print(appointment.strftime(fmt))
        break

Results (1 inputs, 6 outputs).

When is your meeting? Please use MM/DD/YYYY HH:MM format. 01/01/2018 13:00
2018-01-01 16:00:00 EST-0500
2018-01-02 10:00:00 NZDT+1300
2018-01-02 02:30:00 IST+0530
2018-01-01 21:00:00 UTC+0000
2018-01-01 22:00:00 CET+0100
2018-01-02 00:00:00 EAT+0300