Outils pour utilisateurs

Outils du site


issue163:python

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.

En janvier 1969, un groupe de rock américain, Chicago (alors appelé Chicago Transit Authority), a posé la question musicale suivante : « Quelqu'un sait-il vraiment quelle heure il est ? » Bien que la signification de la chanson ne semble pas avoir beaucoup à voir avec l'article de ce mois-ci, la question du titre de la chanson se prête à notre sujet.

Python possède une formidable série de bibliothèques intégrées qui traitent de la date et de l'heure. Souvent, en tant que programmeurs, nous utilisons les bibliothèques de date et d'heure sans nous rendre compte du nombre de fonctionnalités qu'elles contiennent réellement. Nous examinerons certaines de leurs capacités dans cet 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

Lancez votre interpréteur Python dans un terminal et commençons.

Souvent, nous utilisons simplement les bibliothèques de date et d'heure pour obtenir l'heure ou la date actuelle dans nos programmes :

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 »>

Ce qui est bien et facile. Vous pouvez facilement assigner l'horodatage à une variable et le diviser en valeurs unitaires…

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

Vous pouvez facilement imprimer cette information dans des formats « lisibles par un humain » en utilisant la fonction strftime…

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

Mais nous le savons tous ; nous l'avons déjà fait de nombreuses fois. Pourquoi même s'en donner la peine ? Au-delà de l'intégration de l'heure et de la date dans un programme, à quoi cela sert-il ?

Il est très facile de traiter les objets date-heure lorsqu'on fait des calculs de temps et de date.

Disons que nous avons émis une facture aujourd'hui et qu'elle est due dans 30 jours. Quelle serait cette date ?

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.

Lorsque nous traitons avec des bases de données, nous devons souvent mettre une heure ou une date dans la base de données comme « horodatage » pour montrer quand quelque chose s'est passé. C'est très facile.

ts = time.time()
print(ts)

1603875671.3662472

Vous pensez peut-être que cela ne ressemble pas à une heure, à une date ou à quelque chose de semblable. Mais c'est le cas. Il s'agit d'un horodatage UNIX. C'est en fait le nombre de secondes depuis le 1er janvier 1970 UTC. D'après https://www.unixtimestamp.com/, une chose intéressante : le 19 janvier 2038, l'horodatage Unix cessera de fonctionner. Cela est dû à un débordement en 32 bits. Nous avons survécu au passage à l'an 2000, mais pourrons-nous survivre à celui-là ?

Quoi qu'il en soit, revenons au sujet initial.

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.

Comptabilité

L'un des aspects merveilleux des possibilités de manipulation de la date et de l'heure est quand vous devez effectuer des calculs basés sur deux (ou plusieurs) heures ou dates. Disons que nous avons un employé qui peut facturer à un taux de 15 € par heure (arrondi à l'heure supérieure). Supposons en outre que cet employé travaille sur une tâche de programmation de 8 h à 11 h 27. Combien d'heures cela représente-t-il et combien facturez-vous à votre client ?

Bien que cela semble assez simple, nous avons quelques contraintes sur la façon dont nous devons faire les calculs. Tout d'abord, nous devons convertir l'heure de début et l'heure de fin en valeurs.

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)

Nous prenons la date de début et la date de fin et les convertissons en objet d'horodatage.

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

À ce stade, les variables starttime et endtime sont toujours des chaînes. Pour les convertir en objets d'horodatage, nous pouvons utiliser la fonction parse à partir de 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

Nous pouvons vérifier que ça a marché en imprimant le type dans lequel Python voit l'une de ces variables.

print(type(st))

<class 'datetime.datetime'>

Ensuite, nous soustrayons simplement l'horodatage de fin de l'horodatage du début pour obtenir la durée totale.

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'

Voici maintenant la pierre d'achoppement. On pourrait penser que puisque nous avons une valeur qui ressemble à heures:minutes:secondes, nous pourrions simplement obtenir les heures en disant

Hours = totaltime.hours

Mais, je vous dirai tout de suite que ça ne marche pas. Si vous l'essayez, vous obtiendrez :

hours = totaltime.hours

Traceback (most recent call last):

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

AttributeError: 'datetime.timedelta' object has no attribute 'hours' # Erreur d'attribut : l'objet « datetime.timedelta » n'a pas d'attribut « 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

Bon, ça ne nous aide pas. L'objet timedelta n'a que 3 attributs qui peuvent être utilisés. Ce sont : • days # jours • seconds # secondes • microseconds # microsecondes

Regardons ces trois valeurs :

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

Nous savons que le temps total est de 3 heures et 27 minutes, mais nous ne facturons que des heures entières, arrondies, donc nous devrions facturer 4 heures au client. Comment ferons-nous ? Nous utilisons la méthode divmod. Elle prend deux nombres (le numérateur et le dénominateur) et retourne le quotient et le reste.

min, sec = divmod(sec,60)
print(min) # C'est le temps total (en 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.

Ensuite, il suffit d'utiliser une simple déclaration if :

if min > 0:

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

Il s'agit maintenant de multiplier le nombre d'heures (4) * le taux de facturation par heure (15) :

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

60

Ainsi, nous pourrons facturer 60 € au client. Ce n'est pas aussi dur qu'attendu.

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.

Fuseaux horaires

Je vais être brutalement honnête. Les fuseaux horaires me font mal au cerveau. VRAIMENT ! Parfois, lorsque je communique avec notre merveilleux rédacteur en chef, Ronnie, je me souviens qu'il vit en Écosse et qu'il est quelque part en avance d'environ 6 heures sur mon temps. L'Écosse est dans le fuseau horaire du Greenwich Mean Time, ou GMT. On le confond souvent avec le Temps universel coordonné (UTC), mais s'ils peuvent être (à tort) utilisés indifféremment, GMT est un fuseau horaire, UTC n'est pas un fuseau horaire, mais une norme horaire.

Mon ami Halvard vit en Norvège et son heure est en avance de 7 heures sur la mienne. Mon ami Bruce, qui vit dans le Colorado, a une heure de retard sur moi.

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

Quand j'étais jeune (oui, à l'époque où les arcs-en-ciel étaient en noir et blanc et où nous devions regarder la télévision à la bougie parce qu'il n'y avait pas d'électricité), je n'étais pas du tout conscient des fuseaux horaires. À part le fait que lorsque je voyais une publicité pour une émission de télévision et qu'ils disaient qu'elle était diffusée à 21 heures, heure de l'Est, 20 heures, heure centrale, et que, si je voulais la regarder, je devais le faire à 20 heures, puisque je vivais dans le fuseau horaire de l'heure centrale. Mais c'était il y a longtemps. Je suppose qu'Albert Einstein dirait que tout cela est relatif. (C'est censé être une blague de geek.)

La bibliothèque date/heure en Python ne gère pas vraiment les fuseaux horaires de façon native, mais il existe un paquet tiers que vous pouvez installer via pip. Il s'appelle 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

Alors, comment utiliser pytz? C'est assez facile. Jetons-y un œil.

Nous faciliterons les choses en modifiant la déclaration d'import pour ces tests :

from datetime import datetime
from pytz import timezone

Maintenant, nous ne sommes pas obligés d'utiliser datetime.datetime pour avoir des informations, comme nous l'avons fait précédemment.

Ici, nous obtenons l'objet d'horodatage natif de Python.

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).

Ensuite, nous obtiendrons un objet d'horodatage qui tient compte des fuseaux horaires :

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

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

L'objet d'horodatage est donc basé sur le temps universel coordonné (UTC). C'est cool, mais quelle heure est-il là où je vis, dans le fuseau horaire central des États-Unis ?

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

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

Attendez une seconde. Pourquoi dit-il que mon temps a 5 heures de retard sur UTC ? C'est à cause de l'heure d'été. (Le 10 octobre 2020 était avant le passage à l'heure normale.)

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.

Refaisons-le maintenant, mais, cette fois, en utilisant la méthode .now() :

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 ! C'est un peu plus compréhensible. Donc, Ronnie est en avance de 6 heures sur moi.

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!

Ainsi, la question musicale du mois, « Quelqu'un sait-il vraiment quelle heure il est ? », semble un peu plus pertinente que lorsque l'article a commencé, n'est-ce pas ? Je vous laisse avec cette question en tête, et j'espère ne pas vous avoir mis dans votre tête cette chanson qui pourrait devenir lancinante.

Comme toujours, jusqu'à la prochaine fois ; restez prudent, en bonne santé, positif et créatif !

issue163/python.txt · Dernière modification : 2020/12/01 17:42 de andre_domenech