Sometimes we have to work with dates and times. I use dates less than times because with times you can measure code execution time which is sometimes essential (for my website scraping book’s performance measurement is the core part I guess).
So let’s jump right ahead into the date-time modules and see what we can achieve with the usage of that.
Ticks
Time units in computer science are mostly starting from the so called epoch: 00:00, 01. January 1970.
The popular time module of Python counts the time since this epoch in ticks.
>>> import time
>>> ticks = time.time()
>>> print('Number of ticks since the epoch: ', ticks)
Number of ticks since the epoch: 1441253634.967577
The result of the example will differently vary on your computer because time ticks away…
The good thing with the ticks is that you can subtract them. With this you can measure code execution.
>>> import time
>>> start = time.time()
>>> print("Just a simple print...")
Just a simple print...
>>> print('Time elapsed: {}'.format(time.time()-start))
Time elapsed: 6.1041178703308105
The result above is in seconds what is nice. So it is a good option to use time.time() for runtime measurement.
Time tuples
Python’s dates are represented with time tuples: 9 numbers in a tuple. The problem with time-tuples is that you have to enter all the values to have a valid tuple. This can lead to errors.
Formatting time
To format the time you have to use some built-in methods. I will use time.asctime() which requires a time-tuple to provide. If no tuple is provided then the actual system time is used.
>> import time
>>> time.asctime()
'Thu Sep 3 06:39:18 2015'
>>> time.asctime((2016, 7, 9, 0,0,0,0,0,0))
'Mon Jul 9 00:00:00 2016'
The problem with the second example above is that the 9th July 2016 will be a Saturday not a Monday. However we have had to provide the “Day of Week” field where I out of laziness added 0 for Monday. I think you have arrived to the same conclusion: there should be another way around…
Datetime
The datetime module comes handy in the previous case because it can handle dates without requiring all the tuple parameters asctime required. The built-in function isoformat returns a string representing the ISO format of the date.
>>> import datetime
>>> datetime.datetime(2016,7,9).isoformat()
'2016-07-09T00:00:00'
Seems a bit awkward with the ‘T’ denoting the delimiter between date and time at first but this is just a default convenience method. If you use the str function you get the ‘T’ removed so it is more nicely in your displaying. If you use print then str is called implicitly.
>>> import datetime
>>> str(datetime.datetime(2016,7,9))
'2016-07-09 00:00:00'
>>> print(datetime.datetime(2016,7,9))
2016-07-09 00:00:00
Now this is good but can we separate date and time? Of course, it is Python, you can do everything with this language (naturally some problems require more coding effort).
>>> import datetime
>>> appointment = datetime.datetime(2016,7,9, 16)
>>> appointment
datetime.datetime(2016, 7, 9, 16, 0)
>>> appointment.isoformat()
'2016-07-09T16:00:00'
>>> print(appointment)
2016-07-09 16:00:00
>>> appointment.date()
datetime.date(2016, 7, 9)
>>> appointment.time()
datetime.time(16, 0)
>>> print(appointment.date())
2016-07-09
>>> print(appointment.time())
16:00:00
Advanced datetime Formatting
We have learned about string formatting and I gave you some methods how to format strings. We have seen in this section already that datetime object format nicely when printing them. So in this case we can combine our knowledge and have formatted dates within formatted strings.
Because datetime objects are objects and they are some special kind which often requires formatting, they have the built-in function strftime which requires a format string as parameter and returns the datetime object according to this format. Naturally this format string can contain some more text to include around the datetime object.
>>> import datetime
>>> appointment = datetime.datetime(2016,7,9, 16)
>>> appointment.strftime('Appointment is at %H:%M on the %d, %B %Y')
'Appointment is at 16:00 on the 09, July 2016'
As you can see, strftime uses some placeholders you already know from string formatting, however there are quite some formatters to list them here. If you want to see them all, take a look at the docs.
If you try to use the % string formatting along with datetime objects you will soon see that it does not work out. That’s because for the % formatting you need more parameters and the format-string placeholders are overlapping so you would encounter an error.
You can use the format function on strings with a datetime as parameter, however in this case you will get the representation of the str function — which is not very appropriate in most of the cases.
>>> import datetime
>>> appointment = datetime.datetime(2016,7,9, 16)
>>> 'Appointment is at {}'.format(appointment)
'Appointment is at 2016-07-09 16:00:00'
>>> 'Appointment is at %H:%M on the %d, %B %Y'%(appointment)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: unsupported format character 'H' (0x48) at index 19
That’s why I suggest you to use strftime to get a formatted string with a datetime object. If you have multiple datetime objects to represent in a single string use string concatenation.
Calendars
The calendar module supplies functions related to calendars. For example you can ask if a year is a leap-year or just print the whole calendar for a month or even a year. So I would say the calendar module is loaded with utility functions.
Let’s go straight into the examples and have a calendar printed to our console.
>>> import calendar
>>> calendar.month(2016,7)
' July 2016\nMo Tu We Th Fr Sa Su\n 1 2 3\n 4 5 6 7 8 9 10\n11 12 13 14 15 16 17\n18 19 20 21 22 23 24\n25 26 27 28 29 30 31\n'
>>> print(calendar.month(2016,7))
July 2016
Mo Tu We Th Fr Sa Su
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
As you can see the calendar module takes Monday as the first day of the week, however you can change it easily. To any day of the week you want to.
>>> import calendar
>>> calendar.setfirstweekday(4)
>>> print(calendar.calendar(2016,1))
January 2016
Fr Sa Su Mo Tu We Th
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
As you can see (I hope the formatting of the code block stays the same as I see it now) the weekdays start from 0 (Monday) to 6 (Sunday).
And when you change the first week you change it for the whole module. This means from now on (until the interpreter is re-started) the first day of week will be Thursday. Even a re-import of the calendar module does not help to resolve this problem. So if you change the first day of week for some purpose do not forget to change it back or you can end up with some surprises.
Printing calendars made easy
Well, you can print a calendar on-the-fly too without requiring intermediate objects. The calendar module has the built-in functions prmonth and prcal which prints the month or the calendar directly to the console. The arguments are the same than for month and calendar functions.