DateTime::Event::
Commençons par une devinette. Quel est le mois le plus long en 2009 ?
use DateTime; use DateTime::Span;
my $annee = $ARGV[0] || 2009; my $fuseau = $ARGV[1] || 'Europe/Paris';
my %mois_par_duree; # hachage de listes
foreach (1..12) { my $debut = DateTime->new(year => $annee, month => $_, day => 1, time_zone => $fuseau, locale => 'fr'); my $fin = $debut->clone->add(months => 1);
my $mois = DateTime::Span->from_datetimes(start => $debut, end => $fin); my $duree = $mois->duration; my $secondes = $duree->in_units('seconds'); push @{$mois_par_duree{$secondes}}, $debut->strftime("%B %Y");
}
foreach (sort keys %mois_par_duree) { print "$_ : ", join ' ', @{$mois_par_duree{$_}}, "\n"; }
Ce qui nous donne :
2419200 : février 2009 2592000 : avril 2009 juin 2009 septembre 2009 novembre 2009 2674800 : mars 2009 2678400 : mai 2009 juillet 2009 août 2009 décembre 2009 2678401 : janvier 2009 2682000 : octobre 2009
Explication :
Le mois le plus long est le mois d'octobre, car il comporte 31 jours, dont 30 jours de 24 heures et 1 jour de 25 heures (en France métropolitaine et dans un certain nombre d'autres pays européens). Ensuite, c'est le mois de janvier, car il y a eu une seconde intercalaire le 31 décembre 2008 à 23 h 59 mn 60 s UTC, c'est-à-dire le 1er janvier 2009 à 0 h 59 mn 59 s dans le fuseau horaire de Paris.
On voit donc que le module DateTime
, ou plutôt des modules annexes
chargés de façon implicite connaissent les changements d'heure
et les secondes intercalaires.
À l'origine, Perl devait reprendre les bonnes idées de C, de Awk et du shell en laissant tomber les mauvaises idées de ces trois langages. Hélas, quelques défauts de C sont passés à travers les mailles du filet, dont deux concernent les dates :
perl -e 'printf "%02d/%02d/%d\n", (gmtime())[3, 4, 5]'
qui donne pour le 2 octobre 2009 :
02/09/109
Pourquoi avoir numéroté les mois de 0 à 11 ?
L'argument de l'indexation d'un tableau par $mm
ne tient
pas, il est facile d'écrire
print "Le joli mois de $nom_du_mois[$mm-1]"
Quant au nombre magique 1900...
Note d'espoir : la RFC-48 de Perl 6 suggère de corriger
cette bourde en renvoyant un numéro de mois dans l'intervalle
1..12 et une année numériquement correcte. Il s'agirait de
la fonction utctime
au lieu de gmtime
.
Date::Calc Date::Manip Date::Simple Date::Handler Class::Date
etc, jusqu'à
Date::MMDDYY DateTime::PerpetualCalendar Date::LeapYear
Il existe aussi une liste (http://www.nntp.perl.org/group/perl.datetime/), mais son trafic est faible : 386 messages de la création en mai 2001 jusqu'en janvier 2003.
Message historique de Dave Rolsky, Picking up the ball (http://www.nntp.perl.org/group/perl.datetime/2003/01/msg388.html). Il décrit l'état désolant des modules de dates et d'heures et lance le développement d'un nouveau module (encore un).
Trafic de la liste : 320 messages la première semaine, le message de Dave a dû toucher une corde sensible chez plusieurs personnes. Il y a eu 466 messages en janvier 2003 et 4368 pour l'année 2003 dans son ensemble. Le trafic a considérablement diminué à partir de 2004 : 833 en 2004, 595 en 2005 pour arriver à 287 en 2008. Nous sommes donc revenus à un rythme assez calme, espérons que cela cessera de décroître.
DateTime
pour le calendrier grégorien
DateTime::Locale DateTime::Locale::fr DateTime::Locale::fr_BE DateTime::Locale::fr_CA DateTime::Locale::de DateTime::Locale::it
etc. : modules qui travaillent dans l'ombre de DateTime
et permettent de traduire
dans une langue autre que l'anglais
DateTime::LeapSecond
Autre module travaillant dans l'ombre de DateTime
pour
tenir compte des secondes intercalaires comme celle
de fin 2008 (début 2009 pour notre fuseau horaire).
DateTime::TimeZone
Support des fuseaux horaires
DateTime::TimeZone
est basé sur la base de données Olson,
peut-être la plus complète des bases existantes :
elle donne la liste des plages de dates où l'heure d'été est
en vigueur. Pour cette raison, entre autres, le nombre
de fuseaux horaires dépasse largement 24.
On peut même voir à quelle époque l'heure légale française était basée sur le méridien de Paris : décalage de 9mn 21s par rapport à Greenwich.
use DateTime;
my ($aaaa, $mm, $jj, $tz) = @ARGV; my $auj = DateTime->now; $aaaa ||= $auj->year; $mm ||= $auj->month; $jj ||= $auj->day; $tz ||= 'Europe/Paris';
my $date = DateTime->new(year => $aaaa, month => $mm, day => $jj, time_zone => $tz, locale => 'fr');
my $fuseau = DateTime::TimeZone->new(name => $tz); my $decalage = $fuseau->offset_for_datetime($date); my $s = $decalage % 60; my $m = int($decalage / 60) % 60; my $h = int($decalage / 3600); print $date->strftime("%d/%m/%Y décalage $h h $m mn $s s%n");
DateTime::Span
Définit un intervalle de dates, avec une date de début et une date de fin.
DateTime::Duration
Définit une durée. La solution évidente qui consiste à définir une durée comme un nombre de secondes et rien de plus n'est pas valide : 1 jour n'est pas 86400 secondes, car lorsque vous partez du 31/12/2008 à 12:00:00 et que vous ajoutez 86400 secondes, vous obtenez le 01/01/2009 à 11:59:59. De même, lorsque vous partez du 24/10/2009 à 12:00:00 et que vous ajoutez 86400 secondes, vous obtenez le 25/10/2009 à 11:00:00.
DateTime::Set
Mieux que les tableaux @dates
: plus efficace, permet de définir des
ensembles infinis.
DateTime::Event::Recurrence
Alternative au précédent lorsque les dates répondent à des critères de récurrence. Mais, me direz-vous, cela existe déjà avec ICal (RFC 2445). Effectivement, c'est pourquoi il y a :
DateTime::Event::ICal
Par exemple, pour les réunions du groupe Paris.pm, le deuxième mercredi de chaque mois à 20 h, on pourrait définir une récurrence ICal par :
'FREQ=MONTHLY;BYDAY=2WE;BYHOUR=20;BYMINUTE=0;BYSECOND=0'
et la donner à DateTime::Event::Ical
. Mais c'est déjà fait avec :
Acme::PM::Paris::Meetings
À part deux exceptions, ces modules ont été conçus pour une utilisation sérieuse, pour les bases de données et pour Internet.
DateTime::Format::DBI DateTime::Format::MySQL DateTime::Format::Pg (PostgreSQL) DateTime::Format::ICal DateTime::Format::HTTP DateTime::Format::Mail
Avec en plus des modules pour générer des modules de formattage :
DateTime::Format::Builder DateTime::Format::Strptime
DateTime::Event::
Le lever et le coucher du soleil :
DateTime::Event::Sunrise
Attention : contenait un bug jusqu'à la version 0.0501, cf http://rt.cpan.org/Public/Bug/Display.html. Heureusement, la version 0.0502 corrige ce bug.
Pour connaître la date de Pâques et des fêtes mobiles associées :
DateTime::Event::Easter
Mais, même s'il en a été beaucoup question sur la liste, ne cherchez pas
DateTime::Event::FourthOfJuly
Pour connaître le saint patron du jour :
DateTime::Event::NameDay
Il existe également quelques modules un peu plus sérieux,
comme DateTime::Event::Cron
qui permet d'interfacer Perl avec
cron
ainsi que DateTime::Event::ICal
et DateTime::Event::Recurrence
déjà cités.
Anecdote : pendant la campagne d'Italie de 1943-1944, les troupes alliées sont restées bloquées plusieurs mois sur la ligne du Garigliano, devant le Mont Cassin. Les services de propagande de l'Axe se sont inspirés de la tradition selon laquelle les cloches vont à Rome à Pâques pour diffuser ce jour-là des tracts en forme de cloche et sur lesquels était écrit :
Je reviens de Rome... Les Anglais n'y étaient pas encore... Alors... à la Trinité ?
Avec le programme suivant :
use strict; use warnings; use DateTime::Event::Easter;
my $construc = DateTime::Event::Easter->new(); my $paques = $construc->following(DateTime->new(year => 1944, month => 1, day => 1)); print $paques->strftime("Pâques : %d/%m/%Y%n"); print $paques->add(weeks => 8)->strftime("Trinité : %d/%m/%Y%n");
Vous pourrez constater qu'en 1944, le dimanche de Pâques était le 9 avril 1944 et que le dimanche de la Trinité était le 4 juin 1944... jour où les premiers éléments alliés sont entrés dans Rome.
Anecdote dans l'anecdote (même si cela nous éloigne de DateTime
).
L'association entre Pâques et la Trinité était déjà présente dans
la chanson « Malbrouk s'en va-t-en guerre ». Dans cette chanson,
Malbrouk est basé sur John Churchill, duc de Marlborough, général dans l'armée
britannique et vainqueur de la bataille de Blenheim. Son descendant
est Sir Winston Churchill de Marlborough, dont on peut dire qu'il
était un peu impliqué dans la campagne d'Italie et la libération
de Rome.
Une autre devinette : Shakespeare et Cervantès sont tous les deux morts le 23 avril 1616. Lequel des deux est mort le premier ?
use DateTime::Calendar::Christian;
my $ws = DateTime::Calendar::Christian->new( year => 1616, month => 4, day => 23, reform_date => 'uk' ); my $mc = DateTime::Calendar::Christian->new( year => 1616, month => 4, day => 23, reform_date => 'italy' ); # même date que l'Espagne my $dt_ws = DateTime->from_object(object => $ws); # pour avoir un "overload" my $dt_mc = DateTime->from_object(object => $mc); # sur les comparaisons my $comp = 'le même jour que'; $comp = 'avant' if $dt_mc < $dt_ws; $comp = 'après' if $dt_mc > $dt_ws; print "Cervantes est mort $comp Shakespeare\n";
my $d = $dt_mc - $dt_ws; print abs($d->delta_days), " jour(s) d'écart\n";
Utilise
DateTime (calendrier grégorien) DateTime::Calendar::Julian DateTime::Calendar::Christian (bascule automatiquement de julien vers grégorien)
et nous apprenons que Cervantes est mort le premier, 10 jours avant Shakespeare.
DateTime::Calendar::Coptic DateTime::Calendar::Chinese DateTime::Calendar::Hebrew DateTime::Calendar::Hijri DateTime::Calendar::Japanese DateTime::Calendar::Maya DateTime::Calendar::FrenchRevolutionary DateTime::Calendar::Pataphysical DateTime::Format::Roman DateTime::Fiction::JRRTolkien::Shire
Ces modules sont un peu plus récréatifs que les modules DateTime::Event::xxx
et surtout les modules DateTime::Format::xxx
. Toutefois, certains sont
très utilisés, notamment DateTime::Calendar::Japanese
car les Japonais
utilisent traditionnellement des dates basées sur les ères japonaises,
c'est-à-dire l'accession au trône d'un nouvel empereur (merci à Sébastien
pour ces précisions). D'autres modules sont peut-être utilisés pour
des raisons analogues : les modules des calendriers julien, coptique,
hébreu et chinois.
En revanche, les calendriers maya, révolutionnaire, hobbit et 'pataphysique sont là essentiellement pour la culture et la distraction. Par exemple, chaque fois que je me connecte sur ma machine, j'obtiens un message du genre :
Grégorien : 2009-10-02, vendredi 02 octobre 2009 JD 2455107.16666667 MJD 55106.6666666665 Les saints du jour : Léger, Ruth La grande aiguille est sur le douze et la petite aiguille est sur le six Zee beeg hund is un zee tvelfe und zee little hund is un zee six. Bork, bork, bork! Lever du soleil à 07:50:47 Coucher du soleil à 19:30:10
Calendrier romain : VI Non oct. 2009
Julien : 2009-09-19, Friday 19 September 2009
Calendrier maya 12.19.16.13.4 (baktun, katun, tun, uinal, kin) 2 Yax (Haab) 11 Kan (Tzolkin)
Hébreu : 5770-07-14, Friday 14 Tishrei 5770 Hijri : 1430-10-12 AH Hobbit : Monday 10 Winterfilth 7473
Calendrier républicain 0218-01-11T7:50:00, Primidi 11 Vendémiaire CCXVIII, jour de la pomme de terre 11 Vendémiaire II Armée des Alpes. Capture du poste de Valmeyer, du poste de Beaufort, de Moutiers, du bourg Saint-Maurice et du Col de la Madeleine. 11 Vendémiaire III Armée de Sambre-et-Meuse. Bataille d'Aldenhoven et déroute des troupes coalisées. 11 Vendémiaire V. L'Armée du Rhin et Moselle attaque sur toute la ligne et met l'ennemi en déroute.
Pataphysique 137-01-25, mercredi 25 Absolu 137, Nativité de Sa Magnificence Opach
On remarque l'utilisation des deux modules DateTime::Format::xxx
« récréatifs », DateTime::Format::Roman
, qui utilise
le système disparu des ides, des nones et des calendes et
DateTime::Format::Baby
, qui affiche l'heure comme le
feraient un bébé
et le Chef suédois du Muppet Show.
Autre remarque : de l'aveu même de son auteur,
DateTime::Calendar::Hijri
(calendrier de
l'Hégire) donne des informations
à titre indicatif, qui ne doivent pas être considérées
comme faisant autorité. En effet, les irrégularités
de ce calendrier font intervenir les autorités musulmanes,
un peu comme les changements d'heure font intervenir les
autorités nationales de chaque pays concerné et les secondes
intercalaires font intervenir un organisme international.
En fait, il faudrait que le module soit diffusé avec d'une façon
analogue à la diffusion de DateTime::TimeZone
et de
DateTime::LeapSeconds
, avec une nouvelle distribution
chaque fois que les autorités concernées statuent sur
les irrégularités du calendrier.
Pas de problème, Eugene van der Pijll a créé :
Bundle::DateTime::complete
Si, comme sur ma machine, CPAN.pm vous demande s'il faut installer
les modules prérequis à chaque fois qu'il en manque,
alors CPAN.pm vous demandera maintes fois s'il faut
installer DateTime::Set
et DateTime::Format::Builder
.
Donc, pour diminuer le nombre d'interactions,
il peut se révéler judicieux d'installer ces deux
modules en premier lieu, puis seulement après d'installer
Bundle::DateTime::Complete
.
Attention, certains modules sont bugués et ne peuvent pas s'installer.
DateTime::Calendar::Hebrew DateTime::Fiction::JRRTolkien::Shire DateTime::Event::NameDay DateTime::TimeZone::Alias DateTime::TimeZone::LMT
DateTime::Calendar::Hebrew
présente un problème avec
le fuseau horaire « flottant ». Si vous spécifiez toujours
un fuseau horaire précis, alors vous pouvez utiliser
ce module après un force install
.
Post-scriptum de 2012 : une
nouvelle version 0.05
écrite par un nouveau développeur
est disponible depuis novembre 2011. Cette version corrige le problème du fuseau
horaire « flottant ».
Pour DateTime::Fiction::JRRTolkien::Shire
, un test
échoue. Mais vous ne risquez pas grand chose à faire
également un force install
.
Pour DateTime::Event::NameDay
, j'ai déclaré un bug
40834
avec un patch correctif.
Donc, récupérez le patch, appliquez-le à la distribution
et installez le module.
Pour DateTime::TimeZone::Alias
, aucun ticket n'a été déclaré dans RT.
Pour DateTime::TimeZone::LMT
, il y a un ticket 39340 mais pas de patch.
Un autre, DateTime::Event::Sunrise
s'installe correctement
mais donnait des résultats incorrects jusqu'à la version 0.0501, cf mon rapport de bug
34770.
Donc, récupérez le patch, appliquez-le à la distribution
et réinstallez le module.
Post-scriptum de 2013 : j'ai obtenu d'être co-mainteneur de DateTime::Event::Sunrise et la nouvelle version 0.0502 ne contient plus ce bug.
D'autres modules s'installent correctement, mais génèrent des avertissements
à l'exécution : DateTime::Format::Baby
,
DateTime::Format::Roman
et
DateTime::Format::Pataphysical
.
J'ai déclaré des tickets sur CPAN pour chacun :
69841 pour DT::F::Baby,
69845 pour DT::F::Roman
et 69846 pour DT::C::Pataphysical.
Récupérez les patchs associés, appliquez-les et réinstallez les modules.
Post-scriptum de 2014 : BooK est maintenant co-mainteneur de DateTime::Calendar::Pataphysical et la nouvelle version 0.05 ne contient plus ce bug. Donc en fait, avant d'installer les patchs que je vous propose, vérifiez le statut du ticket sur RT.CPAN
Finalement, je n'ai pas installé DateTime::Calendar::Japanese
ni
DateTime::Calendar::Chinese
à cause d'un prérequis, mais d'après
les CPAN-Testers, si le prérequis est installé, ces deux modules
n'ont pas de problème.
Remarque : je ne sais pas si les outils automatiques comme cpanm permettent d'installer un module en le patchant. Moi, je reviens à l'époque de make et j'applique la procédure suivante :
tar -zxvf DateTime-Event-NameDay-0.02.tar.gz mv DateTime-Event-NameDay-0.02 DateTime-Event-NameDay-0.03 patch -p0 < dt-e-nameday.patch cd DateTime-Event-NameDay-0.03 perl Makefile.PL make make test sudo make install
Complet mais en anglais
http://datetime.perl.org/
En français mais loin d'être complet ni à jour
http://datetime.mongueurs.net/
La liste de diffusion (en anglais)
http://lists.perl.org/showlist.cgi?name=datetime