Outils pour utilisateurs

Outils du site


issue163:python

Ceci est une ancienne révision du document !


Way back in January 1969, an American rock band, Chicago (then called Chicago Transit Authority), asked the musical question “Does anybody really know what time it is?” While the meaning of the song doesn’t seem to have much to do with this month's article, the title question of the song does lend itself to our subject this month.

Python has a tremendous built-in series of libraries that deal with date and time. Often, we, as programmers, use the datetime and time libraries without realizing how many features there really are. We will be looking at some of the capabilities of them in this article.

Fire up your Python interpreter in a terminal and let’s get started.

Many times, we simply use the datetime or time libraries to get the current time or date within our programs:

import datetime
import time
print(datetime.datetime.now())

2020-10-23 10:49:11.744798

print(datetime.datetime.today())

2020-10-23 10:50:53.169120

Which is nice and easy. You can easily assign the date and time to a variable and break it out into single values…

tday = datetime.datetime.today()
print(tday.month)

10

print(tday.day)

23

print(tday.year)

2020

You can easily print this information in “human” readable formats using the strftime function…

td = tday.strftime('%m/%d/%Y')
print(td)

10/23/2020

td2 = tday.strftime('%H:%M:%S')
print(td2)

10:51:55

But we all know that; we’ve done it many many times before. Why even bother? Beyond getting time and date into a program, what good is it?

It’s very easy to deal with datetime objects when doing time and date math.

Let’s say that we have issued an invoice today and it is due in 30 days. What date would that be?

tday = datetime.datetime.today()
print(tday)

2020-10-28 03:53:45.551751

due = tday + datetime.timedelta(days=30)
print(due)

2020-11-27 03:53:45.551751

When we deal with databases, we often need to put a time or date into the database as a “timestamp” to show when something happened. That’s super easy.

ts = time.time()
print(ts)

1603875671.3662472

You might be thinking, that doesn’t look like a time, date, or anything like it. But it is. It is a UNIX timestamp. It’s actually the number of seconds since January 1, 1970 UTC. According to https://www.unixtimestamp.com/, one interesting thing: on January 19, 2038, the Unix timestamp will cease working. This is due to a 32-bit overflow. We survived Y2K, but can we survive this?

Anyway, back to the subject at hand.

Accounting

One of the wonderful things about the datetime manipulation capabilities is when you need to do calculations based on two (or more) times or dates. Let’s say that we have an employee who can bill out at a rate of £15 per hour (rounded up to the next hour). Let’s further assume that this employee works on a programming task from 8 am until 11.27 am. How many hours would that be and how much do you bill your customer.

While that looks fairly simple we do have some constraints on how we have to do the calculations. First, we need to convert the start time and end time to values.

We take the start time and end time and convert them to datetime objects.

starttime = “30.10.2020 08:00”
endtime = “30.10.2020 11:27”
print(f'Start time: {starttime} - End Time: {endtime}')

Start time: 30.10.2020 08:00 - End Time: 30.10.2020 11:27

At this point, the starttime and endtime variables are still strings. To convert them to a datetime object, we can use the parse function from dateutil.parser.

from dateutil.parser import parse
st = parse(starttime)
et = parse(endtime)

We can verify that it worked by printing the type that Python sees one of the variables.

print(type(st))

<class 'datetime.datetime'>

Next, we simply subtract the end time from the start time to get the total time.

totaltime = et-st
print(type(totaltime))

<class 'datetime.timedelta'>

print(totaltime)

3:27:00

Now, here is the stumbling block. You would think that since we have a value that looks like Hours:Minutes:Seconds, that we could simply get the hours by saying:

Hours = totaltime.hours

But, I’ll tell you now that doesn’t work. If you try it, you will get:

hours = totaltime.hours

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

AttributeError: 'datetime.timedelta' object has no attribute 'hours'

Well, that’s no help. The timedelta object type only has 3 attributes that can be used. They are • days • seconds • microseconds

Let’s look at the three possible values…

da = totaltime.days
sec = totaltime.seconds
ms = totaltime.microseconds
print(da)

0

print(sec)

12420

print(ms)

0

We know that totaltime is 3 hours and 27 minutes, but we bill only whole hours, rounded up, so we should bill the customer 4 hours. How would we do that? We use the divmod method. It takes two numbers (the numerator and the denominator) and returns the quotient and remainder.

min, sec = divmod(sec,60)
print(min) # This is the total time (in minutes)

207

print(sec)

0

hour, min = divmod(min,60)
print(hour)

3

print(min)

27

Then we simply use a simple if statement:

if min > 0:

… hour += 1 … »> print(hour) 4

Now it is a simple case of multiplying the number of hours (4) * the billing rate per hour (15):

billperhour = 15
billamount = billperhour * hour
print(billamount)

60

So we can bill the client for £60 . That wasn’t as hard as expected.

Time Zones

I’ll be brutally honest. Time Zones make my brain hurt. REALLY! Sometimes, when I communicate with our wonderful editor, Ronnie, I can remember that he lives in Scotland and that he is somewhere around 6 hours ahead of my time. Scotland is in the Greenwich Mean Time, or GMT, timezone. This is often confused with Coordinated Universal Time (UTC), but while they might be (incorrectly) used interchangeably, GMT is a timezone, UTC is not a timezone, but a time standard.

My friend Halvard lives in Norway and his time is somewhere around 7 hours ahead of mine. My friend Bruce, lives in Colorado and that is 1 hour behind my time.

When I was growing up (yes, back in the days where rainbows were in black and white, and we had to watch TV by candlelight because there was no electricity), I wasn’t aware of timezones at all outside of knowing that when I saw an advertisement for a television show and they said that it aired at 9pm Eastern, 8pm Central, that if I wanted to watch it, I should watch at 8pm, since I lived in the Central timezone. But that was long ago. I suppose that Albert Einstein would say that it is all relative. (That’s supposed to be a geeky joke.)

The Python date/time library doesn’t really handle timezones natively, but there is a third party package that you can install via pip. It’s called pytz.

pip install pytz

So how do we use pytz? It’s fairly easy. Let’s take a look.

We’ll make things a little easier by changing the import statement for this set of tests…

from datetime import datetime
from pytz import timezone

Now we don’t have to use datetime.datetime to get any information as we did earlier.

Now get the native Python datetime object.

native = datetime(2020,10,5,12,00)
print(native)

2020-10-05 12:00:00

Next, we’ll get a datetime object that is timezone aware:

aware=timezone('UTC').localize(native)
print(aware)

2020-10-05 12:00:00+00:00

So it says the datetime object is based on UTC (Coordinated Universal Time). So that’s cool, but what time is it where I live, in the U.S. Central Time zone?

aware2=timezone('America/Chicago').localize(native)
print(aware2)

2020-10-05 12:00:00-05:00

Wait a second. Why would it say that my time is 5 hours behind UTC? That’s because of Daylight Saving Time. (October 10, 2020 was before the change over to Daylight Standard time).

So, let’s do it again, this time using the .now() method…

native = datetime.now()
print(native)

2020-11-05 05:15:35.282475

aware2 = timezone('America/Chicago').localize(native)
print(aware2)

2020-11-05 05:15:35.282475-06:00

Ahhh. That makes a bit more sense. So Ronnie is 6 hours ahead of me.

So, the musical question of the month, “Does anybody really know what time it is?” actually does seem to have a bit more relevance than it did when the article started, doesn’t it? I’ll leave you with that question hanging in your mind, and, hopefully, I didn’t plant the song into your mind so that it keeps running again and again.

As always, until next time; stay safe, healthy, positive and creative!

issue163/python.1606584425.txt.gz · Dernière modification : 2020/11/28 18:27 de auntiee