Maîtrisez le temps avec Delphi

Stéphane Vaillant

Conception d'un fichier d'aide HTML et intégration dans une application Delphi.

- Synchronisation de bases de données entre un poste « Client » et un serveur.

- Mise en place de vidéoconférences.

- Utilisation d'un planificateur de tâches automatiques.

Maîtriser le temps… Un rêve de développeur ! ;-)

À défaut de maîtriser le temps, un développeur a souvent recours aux routines « Date/Heure » pour différentes raisons.

Différents domaines de l'informatique nécessitent des synchronisations d'horloge. Ainsi, dans un but de fiabilité, il peut être nécessaire de synchroniser les date et heure d'un poste client et de son serveur.

Le but de ce tutoriel est de vous présenter les différentes fonctions qui permettent de manipuler aisément les dates et les heures dans vos applications.

Tout d'abord, vous allez devoir supporter deux chapitres théoriques sur les normes en vigueur et les protocoles réseau de gestion du temps. Ces deux chapitres sont nécessaires pour la compréhension du reste du tutoriel…

Ensuite, nous entrerons dans le vif du sujet en concevant ensemble différents petits utilitaires de gestion de l'horloge.

Afin d'atteindre notre but, nous allons suivre les étapes suivantes.

- Titre : Maîtrisez le temps avec Delphi

- Auteur : Stéphane Vaillant

- Parution : 16 septembre 2002

- Mise à jour : 31 décembre 2019

- Licence : Copyright ® 2003 Stéphane Vaillant. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Les différentes représentations normalisées de l'heure

- I-A. Greenwich Mean Time (GMT)

- I-B. Temps Atomique International (TAI)

- I-C. Universal Time Coordinated (UTC)

- I-D. Heure légale et heure locale

- I-E. Les fuseaux horaires

- II. Les protocoles « réseau » utilisés par les serveurs de temps

- II-A. Time Protocol

- II-A-1. Présentation et fonctionnement

- II-A-2. Format de la valeur renvoyée

- II-A-3. Utilisation de ce protocole dans Delphi

- II-B. DayTime Protocol

- II-B-1. Présentation et fonctionnement

- II-B-2. Format de la valeur renvoyée

- II-B-3. Utilisation de ce protocole dans Delphi

- II-C. Network Time Protocol

- II-C-1. Présentation et fonctionnement

- II-C-2. Format de la valeur renvoyée

- II-C-3. Utilisation de ce protocole dans Delphi

- II-D. Simple Network Time Protocol

- II-D-1. Présentation et fonctionnement

- II-D-2. Format de la valeur renvoyée

- II-D-3. Utilisation de ce protocole dans Delphi

- III. Fonctionnement de l'horloge sous Windows

- III-A. Heure « système » et heure locale

- III-B. Les informations « Date/Heure » sous Windows

- III-B-1. Les fuseaux horaires disponibles dans le registre de Windows

- III-B-2. Les informations propres au fuseau horaire local

- IV. Manipulation des dates et heures du système avec Delphi

- IV-A. Lecture des informations liées aux fuseaux horaires

- IV-A-1. Le type « TTimeZoneInformation »

- IV-A-2. Objectif du projet « Time Zones Reader »

- IV-A-3. L'unité « uWinTimeZone.pas »

- IV-A-4. L'interface finale

- IV-B. Mise à l'heure du système au moyen d'un serveur de temps

- IV-B-1. Utilisation des composants TIdTime et TIdDayTime (Indy)

- IV-B-2. Utilisation du composant TIdSNTP (Indy)

- V. Ouvrages et adresses Internet utiles

I - Les différentes représentations normalisées de l'heure

Dans des temps très anciens, le temps international n'existait pas…
Les hommes se déplaçaient très peu sur de longues distances et l'heure déterminée par la position du soleil leur suffisait. Ainsi, chaque pays, chaque région, voire chaque ville, utilisaient une heure qui leur était propre. C'était le temps de l'utilisation des cadrans solaires.

Les siècles ont passé et les hommes sont devenus moins sédentaires. Le système horaire basé sur le soleil a dévoilé de nombreuses défaillances. Afin de remédier à ce problème, différentes normes de coordination du temps sont apparues, mais sans résultat.

L'apparition du chemin de fer et du téléphone marquera un tournant dans l'histoire du temps. En effet, l'homme communiquant et se déplaçant de plus en plus, il a été nécessaire de mettre en place une norme internationale. C'est ainsi que sont apparus différents standards de calcul de l'heure, dont l'heure GMT et l'heure UTC.

Afin de mieux cerner le problème de la coordination du temps dans vos applications Delphi, il est nécessaire d'expliquer brièvement le fonctionnement de ces normes internationales.

I-A - Greenwich Mean Time (GMT)

GMT est un acronyme anglophone signifiant heure solaire moyenne de Greenwich.
Greenwich est une commune située à quelques kilomètres de Londres (Angleterre), accueillant l'Observatoire Royal de Greenwich.

Le système horaire GMT a été adopté au niveau international en 1884.
L'heure y est comptée à partir de midi et est donc décalée de 12 h par rapport au temps universel. L'heure GMT étant basée sur la rotation de la Terre, ce n'est donc pas un temps régulier. En effet, la vitesse de rotation de la Terre subit des variations faibles, mais assez chaotiques ; en plus elle diminue sur le long terme.

La norme GMT, du fait de ces imprécisions, n'est quasiment plus utilisée. Lorsque nous parlons d'heure GMT, nous faisons un abus de langage, la nouvelle norme internationale étant la norme UTC.

I-B - Temps Atomique International (TAI)

Le Temps Atomique International est calculé par le Bureau International des Poids et Mesures (BIPM) à partir des données de plus de 200 horloges atomiques situées dans des instituts de météorologie ou des observatoires de plus de 30 pays.
Le BIPM estime que le Temps Atomique International ne diffère pas d'une horloge idéale imaginaire par plus d'un dixième de microseconde (0.0000001 seconde) par an, en avance ou en retard.

La norme UTC en est un dérivé.

I-C - Universal Time Coordinated (UTC)

UTC est un acronyme anglais signifiant Temps universel coordonné.

La norme UTC est la base légale de l'heure dans le monde.

Cette norme est dérivée du Temps Atomique International dont elle diffère seulement par un nombre entier de secondes, actuellement 32. Ces secondes intercalaires sont insérées à l'initiative du Service International de la Rotation Terrestre pour garantir que, en moyenne au cours des ans, le soleil est au méridien de Greenwich à 12:00:00 UTC à 0.9 seconde près.
UTC est donc le successeur du temps moyen de Greenwich, GMT, qui était utilisé quand le jour solaire moyen fournissait l'unité de temps.

I-D - Heure légale et heure locale

Selon la loi du 9 mars 1911 en vigueur jusqu'en 1978, l'heure légale en France était l'heure du temps moyen de Paris retardée de 9 minutes 21 secondes. Cette définition voulait signifier en fait que l'heure en France était le temps universel.

La loi de 1911 a été remplacée par le décret du 9 août 1978 qui stipule que « le temps légal est obtenu en ajoutant ou en retranchant un nombre entier d'heures au temps universel coordonné ». Un décret fixe ce nombre pour chaque partie du territoire de la République française en fonction des fuseaux horaires. Il peut l'accroître ou le diminuer pendant une partie de l'année.

Ce nouveau décret prévoit donc l'usage d'une heure d'été, apparue pour la première fois en 1916.

I-E - Les fuseaux horaires

Chaque pays va donc définir son heure par l'écart au temps universel.
Cet écart étant déterminé de façon à ce que l'heure adoptée respecte le cycle journalier lié au lever du soleil, au midi, et au coucher du soleil. Cependant, pour faciliter les changements d'heure pour les voyageurs, les accords internationaux prévoient d'adopter un écart au temps universel égal à un nombre entier d'heures.

Pour cela, on définit 24 zones autour du globe appelées « fuseaux horaires ».
Chaque pays se rattache ainsi au fuseau le mieux adapté et définit son heure légale ou standard comme Temps Universel (TU) plus ou moins n heures (où n est un nombre entier). Cela ne l'empêche pas d'ajouter ou de retrancher une heure pour définir une heure d'été ou autre.

Les pays très étendus en longitude adoptent plusieurs heures légales.
Par exemple, aux États-Unis, il y a 7 heures légales : Atlantique, Est, Central, Montagne, Ouest, Alaska et Hawaï.
Ces heures légales possèdent deux variantes : l'heure standard applicable en hiver et l'heure « de la lumière du jour » (Daylight Time) qui correspond à notre heure d'été puisqu'on l'applique en été en ajoutant une heure à l'heure standard.

L'existence de fuseaux horaires va entraîner l'existence d'une « ligne de changement de date ».
Examinons en effet l'écart des heures locales au temps universel. En allant vers l'est, le soleil va se lever plus tôt et donc, pour obtenir les heures locales on va ajouter une heure, puis deux, puis trois au temps universel en se déplaçant vers l'est. En allant vers l'ouest ce sera le contraire : on retirera des heures au temps universel pour que midi reste à 12 heures…
En effet, s'il est midi en France, les pays situés à l'est de la France sur une même latitude verront le soleil vers la France, c'est-à-dire vers l'ouest, c'est donc que ce sera l'après-midi et qu'il sera plus tard qu'en France et qu'on ajoutera une ou plusieurs heures à l'heure française pour obtenir l'heure locale.

Donc en allant vers l'est on ajoute des heures : on arrive à la ligne de changement de date quand on a ajouté douze heures.
S'il est midi en temps universel, il sera minuit le soir du même jour sur le dernier fuseau vers l'est que l'on notera FE. En allant vers l'ouest, on retranchera des heures et il sera 0 heure du même jour en arrivant sur le dernier fuseau vers l'ouest que l'on notera FO. Les deux fuseaux concernés sont en fait côte à côte et une heure plus tard, il sera 1 heure du même jour sur le fuseau FO et une heure du lendemain sur le fuseau FE qui vient de passer minuit. Le passage de la ligne de changement de date fait donc effectivement passer d'un jour à l'autre à une même heure ou plutôt à un même moment de la journée. Notons cependant que tout le monde est à la même heure et à la même date en temps universel, ce qui permet de s'y retrouver.

On trouvera ci-dessous la répartition des heures légales selon les fuseaux horaires sur tous les continents.
Remarquons que certains territoires comme le Groenland ou l'Antarctique n'ont pas d'heure légale propre : le Temps Universel y est donc utilisé.
Remarquons aussi que tous les pays n'ont pas adopté un décalage d'un nombre entier d'heures avec le Temps Universel comme l'Inde qui a adopté 5h30.

Que faut-il retenir de tout cela ?
En fait, dans le cadre du développement d'applications, il est important de se souvenir que :

- nous sommes soumis à l'heure UTC (et non GMT) ;

- en hiver, l'heure locale répond à l'équation suivante :
Heure UTC + décalage horaire (Heure UTC + 1h00 en France) ;

- en été, l'heure locale répond à une équation prenant en compte l'heure d'été :
Heure UTC + Décalage horaire + Décalage heure d'été (Heure UTC + 2h00 en France).

En développement, il peut être intéressant de pouvoir mettre à jour l'horloge interne d'un ordinateur en fonction de l'heure internationale, l'heure UTC.
Aussi, nous allons maintenant nous intéresser aux protocoles permettant l'interrogation des serveurs de temps disponibles sur Internet.

II - Les protocoles « réseau » utilisés par les serveurs de temps

Dans ce chapitre, je ne vais pas vous parler du fonctionnement de base des réseaux.
Pour avoir de plus en amples informations, je vous invite à visiter les sites suivants :

- Guill.net - La page des réseaux

- Kudzu Article Collection : Introduction aux sockets, IP, adresses, DNS, TCP, UDP & Ports

Cependant, afin que nous parlions le même langage, je vous donne une petite explication d'un protocole.
Un protocole, à l'instar des langues (français, anglais, etc.), est une convention permettant à deux ordinateurs de se comprendre. Les spécificités de chaque protocole sont définies dans les Request For Comments (RFC), assurant ainsi un standard international.
Vous trouverez les différentes Request For Comments sur les sites suivants :

- community.roxen.com

- RFC Editor

Je vais vous présenter brièvement les différents protocoles en vigueur actuellement sur Internet.

II-A - Time Protocol

II-A-1 - Présentation et fonctionnement

Le « Time Protocol » est conforme à la norme définie, en mai 1983, dans la Request For Comments n° 868 (RFC868).

On interroge un serveur de temps Time sur le port 37, et la réponse est envoyée aux formats UDP/IP ou TCP/IP.

Ce protocole est le plus simple à utiliser pour interroger un serveur de temps, mais il tombe en désuétude, car certaines informations importantes lui font défaut comme la gestion de l'heure d'été ou encore la fiabilité du serveur.

Il n'est plus, actuellement, utilisé que par environ 1 % des serveurs de temps. Le National Institute of Standards and Technology (NIST) propose, à ma connaissance, l'un des derniers serveurs de temps utilisant ce protocole : time.nist.gov.

II-A-2 - Format de la valeur renvoyée

La valeur renvoyée par un serveur de temps Time est composée d'un nombre binaire 32 bits non formaté. Elle représente le temps en secondes UTC séparant la date du jour du 1er janvier 1900 à minuit.

Le format de la valeur renvoyée est défini au niveau du serveur et non au niveau du client, charge au client de créer ses propres routines de formatage de date et heure.

II-A-3 - Utilisation de ce protocole dans Delphi

Ce protocole est notamment utilisé par ces composants standards de Delphi :

Palette

Composant

FastNet

TNMTime

Indy

TIdTime

Nota : La palette « FastNet » de Delphi 6 va disparaître avec Delphi 7.

II-B - DayTime Protocol

II-B-1 - Présentation et fonctionnement

Le « DayTime Protocol » est conforme à la norme définie, en mai 1983, dans la Request For Comments n° 867 (RFC867).

On interroge un serveur de temps DayTime, en écoute sur le port 13, via le protocole TCP.

À la différence des serveurs Time du NIST (voir Time Protocol ci-dessus), l'heure renvoyée par un serveur DayTime est l'heure locale de l'endroit où il est installé. En effet, il est possible d'interroger le serveur américain time.nist.gov par le protocole DayTime, mais les valeurs renvoyées concerneront uniquement les États-Unis…

II-B-2 - Format de la valeur renvoyée

La valeur renvoyée par un serveur DayTime est composée d'une série de champs « Date » et « Heure » au format ASCII anglais.

Il n'y a pas de syntaxe spécifique au protocole DayTime.

Cependant, il est recommandé de délimiter les champs par des caractères ASCII tels que la virgule, le point-virgule ou encore l'espace.

Le format de la valeur renvoyée est défini au niveau du serveur et non au niveau du client, charge au client de créer ses propres routines de formatage de date et heure.

Voici deux exemples de valeurs renvoyées par un serveur DayTime :

Exemple 1

Format

Weekday,Month Day,Year,Time-TimeZone

Valeur

Thursday,August 15,2002,12:30:47-PST

Exemple 2

Format

DD MMM YY HH:mm:ss ZZZ

Valeur

15 AUG 02 12:30:47 PST

II-B-3 - Utilisation de ce protocole dans Delphi

Ce protocole est notamment utilisé par ces composants standards de Delphi :

Palette

Composant

FastNet

TNMDateTime

Indy

TIdDayTime

Nota : La palette « FastNet » de Delphi 6 va disparaître avec Delphi 7.

II-C - Network Time Protocol

II-C-1 - Présentation et fonctionnement

Le « Network Time Protocol » est conforme à la norme définie, en mars 1992, dans la Request For Comments n° 1305 (RFC1305).

Ce protocole est le plus utilisé actuellement, car il fournit des informations plus complètes et plus fiables que les autres protocoles.

De nombreux systèmes d'exploitation fournissent des logiciels NTP en standard. Ces logiciels fonctionnent en tâche de fond et mettent à jour périodiquement l'horloge du poste « Client ».
Sur les gros systèmes et les serveurs, ces logiciels interrogent plusieurs serveurs de temps, ignorent les réponses qui lui semblent mauvaises et font la moyenne des bonnes réponses.
Sur les ordinateurs individuels, ces logiciels synchronisent l'horloge du poste « Client » en n'interrogeant qu'un seul serveur. Ce type de logiciel s'appelle « Logiciel SNTP » (Voir Simple Network Time Protocol ci-après).

On interroge un serveur de temps Network Time sur le port 123, et la réponse est envoyée sous la forme d'un paquet de données UDP/IP au format NTP.

Le « Network Time Protocol » est un protocole sophistiqué permettant la synchronisation permanente avec plusieurs serveurs. De plus, ce protocole prend en compte la correction du décalage provoqué par les délais de transmission des données et par la dérive des horloges locales.

Les serveurs NTP sont répartis en différentes couches numérotées (Strate). Le numéro indique l'éloignement sur le réseau entre le serveur concerné et son horloge de référence :

- un serveur connecté à une horloge de référence est un serveur « Strate 1 » ;

- un serveur synchronisé sur un serveur « Strate 1 » est un serveur « Strate 2 » ;

- et ainsi de suite…

L'avantage de cette structure arborescente réside dans le fait que le trafic réseau des serveurs « Strate 1 » est déchargé sur les serveurs secondaires, « Strate 2 » et autres.

II-C-2 - Format de la valeur renvoyée

Le paquet de données renvoyé inclut un horodateur 64 bits contenant le temps en secondes UTC séparant la date du jour du 1er janvier 1900 avec une résolution 200 picosecondes.

Le format de la valeur renvoyée est défini au niveau du serveur et non au niveau du client, charge au client de créer ses propres routines de formatage de date et heure.

II-C-3 - Utilisation de ce protocole dans Delphi

Actuellement, le « Network Time Protocol » n'est pas utilisé sous sa forme normalisée dans Delphi.
Certains composants en utilisent la forme simplifiée : Le « Simple Network Time Protocol » que je vais vous présenter dès maintenant.

II-D - Simple Network Time Protocol

II-D-1 - Présentation et fonctionnement

Le « Simple Network Time Protocol » est conforme à la norme définie, en octobre 1996, dans la Request For Comments n° 2030 (RFC2030).

C'est une version simplifiée du « Network Time Protocol », dépourvue des mécanismes de sélection.

Il est destiné à des utilisations où une précision de l'ordre de la seconde est suffisante.

Un client SNTP peut bien sûr se synchroniser sur un serveur NTP.

Bien qu'ayant plutôt été conçu pour implémenter des clients simples, SNTP permet également de mettre en œuvre des serveurs, mais ceux-ci doivent alors être synchronisés directement par une référence temporelle.

II-D-2 - Format de la valeur renvoyée

Le paquet de données renvoyé inclut un horodateur 64 bits contenant le temps en secondes UTC séparant la date du jour du 1er janvier 1900 avec une résolution 200 picosecondes.

Le format de la valeur renvoyée est défini au niveau du serveur et non au niveau du client, charge au client de créer ses propres routines de formatage de date et heure.

II-D-3 - Utilisation de ce protocole dans Delphi

Ce protocole est notamment utilisé par ce composant standard de Delphi :

Palette

Composant

Indy

TIdSNTP

Nous verrons l'utilisation de ces composants dans la suite du tutoriel.

Vous connaissez désormais les bases nécessaires permettant l'étude du fonctionnement de l'horloge de Windows. Rendez-vous au chapitre suivant… ;-)

III - Fonctionnement de l'horloge sous Windows

Tout développement de logiciel pour Windows nécessite, au préalable, une bonne connaissance de ce système d'exploitation.
Dans le cadre d'applications manipulant les dates et les heures, vous devez comprendre comment Windows gère ces données.

Contrairement à ce que peut croire un utilisateur classique, il y a une différence entre l'heure affichée dans la boîte de dialogue « Propriétés de Date/Heure » et l'heure du système, proprement dite.

III-A - Heure « système » et heure locale

Windows gère les dates et les heures grâce à un processus relativement simple.
En effet, il prend en compte les paramètres suivants :

- heure GMT / UTC ;

- décalage horaire du fuseau horaire ;

- décalage horaire de l'heure d'été.

En interne, Windows stocke l'heure GMT/UTC, il s'agit de l'heure dite "système'.
Pour afficher l'heure locale, il prend, tout d'abord, en compte le fuseau horaire et ajoute le décalage horaire prévu.
Enfin, il teste si votre région est soumise à l'heure d'été ; si c'est le cas, il ajoute le décalage horaire prévu.

Voici une représentation graphique de ce qui se passe en interne :

Concrètement, Windows calcule l'heure locale pour Paris (GMT+01:00) de la manière suivante :

Période

Fonction mathématique

Hiver

Heure locale = Heure Système + Décalage fuseau horaire

Été

Heure locale = Heure Système + Décalage fuseau horaire + Décalage heure d'été

Heure « Système », heure locale, fuseau horaire, heure d'été… Toutes ces informations sont importantes, mais où et comment peut-on récupérer ces valeurs sous Windows ?

III-B - Les informations « Date/Heure » sous Windows

Les informations « Date/Heure » sont stockées dans le registre de Windows.

Lorsque l'utilisateur ouvre la boîte de dialogue « Propriétés de Date/Heure », Windows fait appel à plusieurs clés de registre que nous allons étudier une à une.

Nous verrons ensuite comment créer un petit programme Delphi permettant de récupérer ces informations.

III-B-1 - Les fuseaux horaires disponibles dans le registre de Windows

Comme nous l'avons vu précédemment, Windows stocke le décalage horaire à appliquer en fonction du fuseau horaire. Dans le registre, les fuseaux horaires se nomment « Time Zones » et se situent à la clé de registre suivante :

OS

Clé de registre

Win 9x

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\

Win NT / 2000

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

Dans cette clé de registre, vous trouverez 74 sous-clés contenant les paramètres spécifiques à chaque fuseau horaire (Time Zone) :

La « Time Zone » de Paris est stockée dans la sous-clé de registre « Romance Standard Time ».

Chaque clé « Time Zone » contient six sous-clés que nous allons voir en détail…

Voici le descriptif de chacune des sous-clés disponibles par clé « Time Zone » :

Display (Affichage)

Aperçu

Type de donnée

REG_SZ (Chaîne de caractères)

Contenu

Nom explicite du fuseau horaire

Exemple d'utilisation

Boîte de dialogue « Propriétés de Date/Heure » de Windows

Dlt (« Daylight » - Heure d'été)

Aperçu

Type de donnée

REG_SZ (Chaîne de caractères)

Contenu

Nom explicite de l'heure locale en période d'heure d'été

Exemple d'utilisation

Boîte de dialogue « Propriétés de Date/Heure » de Windows

Index

Aperçu

Type de donnée

REG_DWORD (Valeur entière à représentation décimale ou hexadécimale)

Contenu

Valeur notamment utilisée pour ordonner tous les fuseaux horaires de (GMT-12:00) à (GMT+12:00) en passant par le fuseau horaire (GMT).

Exemple d'utilisation

Boîte de dialogue « Propriétés de Date/Heure » de Windows

MapID

Aperçu

Type de donnée

REG_SZ (Chaîne de caractères)

Contenu

Valeur notamment utilisée pour afficher la carte correspondant au fuseau horaire.
Nous n'utiliserons pas cette clé dans nos sources Delphi.

Exemple d'utilisation

Boîte de dialogue « Propriétés de Date/Heure » de Windows

Std (« Standard »)

Aperçu

Type de donnée

REG_SZ (Chaîne de caractères)

Contenu

Nom explicite de l'heure locale hors période d'heure d'été

Exemple d'utilisation

Boîte de dialogue « Propriétés de Date/Heure » de Windows

TZI (« Time Zone Information » - Informations de fuseau horaire)

Aperçu

Type de donnée

REG_BINARY (Enregistrement binaire).
Valeur codée sur 44 octets.

Contenu

Valeur contenant toutes les informations propres à un fuseau horaire :

- décalage horaire par rapport à l'heure GMT ;

- décalage horaire heure d'été / heure d'hiver ;

- paramètres du début de la période de l'heure d'été :

- mois de l'année,

- jour de la semaine,

- ordre du jour dans le mois,

- heures,

- minutes,

- secondes ;

- paramètres de fin de la période de l'heure d'été :

- mois de l'année,

- jour de la semaine,

- ordre du jour dans le mois,

- heures,

- minutes,

- secondes ;

- bascule automatique heure d'été / l'heure d'hiver.

Nous verrons le contenu précis de cette valeur quand nous utiliserons Delphi, dans la suite de ce tutoriel.

Vous savez désormais où sont stockés les fuseaux horaires dans le registre de Windows et quelles sont les informations disponibles.
Cependant, pour que l'heure locale soit juste, il faut que Windows stocke les paramètres propres à votre situation géographique, c'est l'objet de la prochaine rubrique.

III-B-2 - Les informations propres au fuseau horaire local

Où sont stockées les données propres au système ?
Ces données font partie des « Paramètres régionaux » (Win 9x) ou « Options régionales » (Win 2000) et sont stockées dans la clé de registre suivante :

OS

Clé de registre

Win 9x / NT / 2000

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\

Dans cette clé de registre, vous trouverez huit sous-clés de registre :

Voici le descriptif de chacune des sous-clés disponibles :

ActiveTimeBias (Décalage horaire actif)

Aperçu

Type de donnée

REG_DWORD (Valeur entière à représentation décimale ou hexadécimale)

Contenu

Décalage horaire actif

Bias (Décalage horaire)

Aperçu

Type de donnée

REG_DWORD (Valeur entière à représentation décimale ou hexadécimale)

Contenu

Décalage horaire normal

DaylightBias (Décalage horaire d'été)

Aperçu

Type de donnée

REG_DWORD (Valeur entière à représentation décimale ou hexadécimale)

Contenu

Décalage horaire à appliquer en période d'heure d'été

DaylightName (Nom du décalage horaire d'été)

Aperçu

Type de donnée

REG_SZ (Chaîne de caractères)

Contenu

Nom du décalage horaire à appliquer en période d'heure d'été

DaylightStart (Démarrage de l'horaire d'été)

Aperçu

Type de donnée

REG_DWORD (Valeur entière à représentation décimale ou hexadécimale)

Contenu

Date et heure auxquelles démarre la période d'heure d'été

StandardBias (Décalage horaire standard)

Aperçu

Type de donnée

REG_DWORD (Valeur entière à représentation décimale ou hexadécimale)

Contenu

Décalage horaire normal

StandardName (Nom du décalage horaire standard)

Aperçu

Type de donnée

REG_SZ (Chaîne de caractères)

Contenu

Nom du décalage horaire à appliquer hors période d'heure d'été

StandardStart (Démarrage de l'horaire standard)

Aperçu

Type de donnée

REG_DWORD (Valeur entière à représentation décimale ou hexadécimale)

Contenu

Date et heure auxquelles démarre la période d'horaire normal (Heure d'hiver)

IV - Manipulation des dates et heures du système avec Delphi

IV-A - Lecture des informations liées aux fuseaux horaires

Sous Windows, nous pouvons lire deux types d'informations liées aux fuseaux horaires (voir le chapitre précédent) :

- les informations concernant tous les fuseaux horaires connus de Windows ;

- les informations concernant le fuseau horaire local.

La plupart des clés de registre sont de type RG_SZ (chaînes de caractères) ou RG_DWORD (nombres) et sont facilement lisibles au moyen de la classe TRegistry.

Un problème se pose pour la lecture de la valeur de la clé « TZI » qui est de type RG_BINARY (valeur binaire).
Aussi, Delphi a prévu une classe permettant de lire et manipuler ces informations : le type TTimeZoneInformation.

Avant de se creuser les méninges dans le développement d'une application de lecture des informations des fuseaux horaires, nous allons étudier ce type.

IV-A-1 - Le type « TTimeZoneInformation »

TTimeZoneInformation est un type record, défini dans l'unité Windows.pas de Delphi.
Ce type permet d'accéder aux informations spécifiques à chaque fuseau horaire.

En voici la structure :

type
PTimeZoneInformation = ^TTimeZoneInformation;
_TIME_ZONE_INFORMATION = record
Bias: Longint;
StandardName: array[0..31] of WCHAR;
StandardDate: TSystemTime;
StandardBias: Longint;
DaylightName: array[0..31] of WCHAR;
DaylightDate: TSystemTime;
DaylightBias: Longint;
end;
{$EXTERNALSYM _TIME_ZONE_INFORMATION}
TTimeZoneInformation = _TIME_ZONE_INFORMATION;
TIME_ZONE_INFORMATION = _TIME_ZONE_INFORMATION;
{$EXTERNALSYM TIME_ZONE_INFORMATION}

Étudions les champs disponibles dans un enregistrement de type TtimeZoneInformation.

- Bias
Ce champ, de type LongInt (Entier 32 bits signé), contient la valeur en minutes du décalage horaire appliqué actuellement.
La valeur de Bias est la différence, en minutes, entre l'heure UTC et l'heure locale.

- StandardName
Ce champ, de type WideChar (Caractère standard Unicode 16 bits), contient le nom à afficher hors de la période d'heure d'été.

- StandardDate
Ce champ, de type record TSystemTime, contient plusieurs informations dont le jour, le mois, l'ordre du jour dans le mois, l'heure de passage à la période d'heure normale (« Passage à l'heure d'hiver »).

- StandardBias
Ce champ, de type LongInt (Entier 32 bits signé), contient la valeur en minutes du décalage horaire à appliquer hors période d'heure d'été.
La valeur de StandardBias est ajoutée à la valeur de Bias hors de la période d'heure d'été.
Pour de nombreux fuseaux horaires, StandardBias renvoie la valeur « 0 ».

- DaylightName
Ce champ, de type WideChar (Caractère standard Unicode 16 bits), contient le nom à afficher durant la période d'heure d'été.
Pour les pays n'utilisant pas le système heure d'été/heure d'hiver, ce champ n'est pas renseigné.

- DaylightDate
Ce champ, de type record TSystemTime, contient plusieurs informations dont le jour, le mois, l'ordre du jour dans le mois, l'heure de passage à la période d'heure d'été.

- DaylightBias
Ce champ, de type LongInt (Entier 32 bits signé), contient la valeur en minutes du décalage horaire à appliquer durant la période d'heure d'été.
La valeur de DaylightBias est ajoutée à la valeur de Bias durant la période d'heure d'été.
Cette valeur est ignorée si le champ DaylightDate n'est pas renseigné.

En route pour le fabuleux monde de Delphi…

IV-A-2 - Objectif du projet « Time Zones Reader »

Qu'est-ce que « Time Zones Reader » ? C'est le nom arbitraire que j'ai donné au petit logiciel que nous allons développer. ;-)

Comme son nom l'indique, il s'agira de développer un lecteur des informations de fuseaux horaires.
Il est vrai qu'il est possible d'en créer des nouveaux et de modifier les existants, mais je ne veux pas être tenu responsable de mauvaises manipulations et de suppressions de fuseaux horaires.
Je vous laisse donc le privilège de développer la partie gérant les ajouts, modifications et suppressions de fuseaux horaires…

Voici, représenté schématiquement, ce que notre logiciel va devoir être capable de faire :

Son interface sera très simple, vous pouvez la voir ci-après, en lecture de la clé concernant le fuseau horaire de Paris :

Afin d'obtenir ce magnifique résultat, nous allons devoir créer une nouvelle classe qui nous permettra d'accéder à toutes ces informations. Ce sera la partie du développement la plus complexe, le reste étant de la création d'interfaces et de l'affichage d'informations.

Vous pouvez, d'ores et déjà, télécharger les sources de ce petit programme. Cela vous permettra de suivre le tutoriel plus aisément :

Allez ! Au boulot ! Attaquons la création de la nouvelle classe… :-))

IV-A-3 - L'unité « uWinTimeZone.pas »

Afin de pouvoir récupérer, stocker et manipuler toutes ces informations, nous allons créer une nouvelle classe que nous nommerons « TWinTimeZone » dans laquelle nous trouverons des items de type « TWinTimeZoneItem » :

Comme vous pouvez le voir sur le schéma ci-dessus, TWinTimeZoneItem hérite de TObject.
Nous allons lui définir des propriétés qui lui seront propres. Pour notre logiciel, nous avons besoin des propriétés suivantes :

- DisplayValue: String
Valeur de la clé « Display » dans le registre de Windows.

- KeyNameValue: String
Nom de la clé propre au fuseau horaire en cours dans le registre de Windows.

- IndexValue: Integer
Valeur de la clé « Index » dans le registre de Windows.

- NextStandardDate: String
Valeur de la date de passage à l'heure standard (Heure d'hiver)

- NextDaylightDate: String
Valeur de la date de passage à l'heure d'été.

- TZIValue: TTimeZoneInformation
Valeur de la clé « TZI » dans le registre de Windows.

Quant au type TWinTimeZone, qui hérite de TObjectList, nous allons lui définir une seule et unique propriété qui nous permettra d'accéder aux valeurs récupérées :

- Items[Index: Integer]: TWinTimeZoneItem
Valeur d'un item de type TWinTimeZoneItem, défini par son index.

Cependant, nous allons lui ajouter différentes méthodes qui permettront de manipuler les Items :

- function GetItem(Index: integer): TWinTimeZoneItem;
Cette fonction permettra d'accéder à un item de TWinTimeZone via son index.

- procedure AddItem(WinTimeZoneItem: TWinTimeZoneItem); overload;
procedure AddItem(TzDisplay: string; TzKeyName: string; TzIndex: integer; TzTZI: TTimeZoneInformation); overload;
Ces deux déclarations de la même procédure permettront d'ajouter des items à TWinTimeZone.

- procedure Initialize;
Cette procédure sera chargée de lire la base de registre et d'alimenter TWinTimeZone.

- function Count: integer;
Cette fonction renverra au développeur, le nombre d'éléments contenus dans TWinTimeZone, en l'occurrence ce sera le nombre de fuseaux horaires trouvés dans le registre de Windows.

- procedure Clear;
Cette procédure servira à nettoyer notre objet TWinTimeZone.

- procedure SortDisplayByIndex;
Cette procédure permettra au développeur de classer les valeurs de « Display » en fonction des valeurs de « Index » contenues dans le registre de Windows, c'est-à-dire de classer les fuseaux horaires de (GMT+13:00) à (GMT-12:00).

Je vous invite à lancer Delphi pour regarder plus en détail ces procédures, fonctions et propriétés succinctement décrites ci-dessus.

Lançons-nous maintenant dans la création du logiciel final…

IV-A-4 - L'interface finale

Voici enfin le moment de tester notre unité…
Afin que vous puissiez comprendre les portions de code que je vais vous expliquer, regardez la composition de la fiche principale nommée 'fMain' :

La première manipulation à effectuer est d'ajouter l'unité uWinTimeZone.pas dans la section uses de frmMain :

unit fMain;
interface
uses
Windows, ..., uWinTimeZone;

Afin d'afficher les informations concernant le décalage horaire actuel sur le poste « client », nous allons implémenter le Create de frmMain de la manière suivante :

procedure TfrmMain.FormCreate(Sender: TObject);
var (...)
tziCurrent: TTimeZoneInformation;
begin
// Affichage de la date et l'heure actuelle
lblLocalDateValue.Caption := DateTimeToStr(Now);
// Affichage des informations de décalage horaire actuel
case GetTimeZoneInformation(tziCurrent) of
TIME_ZONE_ID_STANDARD:
begin
lblLocalNameValue.Caption := tziCurrent.StandardName;
lblLocalBiasValue.Caption := TimeZoneBiasToStr(tziCurrent.Bias + tziCurrent.StandardBias);
end;
TIME_ZONE_ID_DAYLIGHT:
begin
lblLocalNameValue.Caption := tziCurrent.DaylightName;
lblLocalBiasValue.Caption := TimeZoneBiasToStr(tziCurrent.Bias + tziCurrent.DaylightBias);
end;
end;
(...)
end;

Ces informations étant affichées, un Timer, tmrMain (TTimer) sera chargé de mettre à jour la date et l'heure actuelle.

Il faut maintenant remplir la liste déroulante lstFuseaux (TListBox) et afficher les informations correspondantes au fuseau horaire sélectionné dans la liste.
Pour cela, il suffit de créer et d'instancier un objet de type TWinTimeZone, puis de faire appel à ses méthodes…
Les sources du programme étant commentées, je vous laisse le soin d'étudier le code spécifique à ces méthodes…

Récupérer les informations sur les fuseaux horaires est une chose intéressante, mais il est aussi important de pouvoir se connecter à un serveur de temps pour mettre à l'heure son PC.
Nous allons voir cela dans le prochain chapitre… :-)

IV-B - Mise à l'heure du système au moyen d'un serveur de temps

Comme vous avez pu le voir dans les chapitres précédents, Internet et Intranet offrent la possibilité de mettre à l'heure les systèmes au moyen de serveurs de temps.

Ces serveurs de temps utilisant des protocoles différents, la VCL de Delphi s'est dotée de différents composants adaptés à ces protocoles. Si vous avez un trou de mémoire, retournez voir le chapitre « Les protocoles » Réseau« utilisés par les serveurs de temps »… ;-)

Les composants « FastNet » disparaissant de Delphi 7, je ne vais pas m'étendre sur l'utilisation de ces composants, leur fonctionnement étant relativement simple. Cependant, comme je suis bon prince, vous trouverez des exemples à télécharger avec ce tutoriel…

Pour tous ces exemples, nous utiliserons la même interface et nous nous contenterons de changer les composants d'interrogation des serveurs de temps :

De plus, afin d'uniformiser tous les exemples, la liste des serveurs de temps sera toujours stockée dans un fichier au format texte nommé « timeservers.txt ».

Je ne vous ferai pas l'affront de vous prévenir que pour tester ces sources, il faut évidemment être connecté à Internet !!! ;-)

Allez, testons ces composants…

IV-B-1 - Utilisation des composants TIdTime et TIdDayTime (Indy)

Ces composants utilisent les protocoles Time Protocol et DayTime Protocol.

Palette

Composant

Indy

TIdTime

Indy

TIdDayTime

Le seul serveur de ce type actuellement disponible est le serveur time.nist.gov.
Nous interrogerons ce serveur de temps via le port 13.

Je vous invite à consulter le format de chaîne utilisé par ce serveur pour renvoyer les informations de date et d'heure sur le site du NIST :
http://www.boulder.nist.gov/timefreq/service/its.htm.
En effet, ces informations sont nécessaires pour élaborer votre routine d'affichage des informations au format local.

Pour interroger ce serveur de temps, il est indispensable de renseigner certaines propriétés du composant TIdDayTime :

- Host : il s'agit de l'adresse ou de l'alias du serveur de temps (Exemple : time.nist.gov) ;

- Port : il s'agit du port via lequel il est possible d'interroger le serveur de temps (Exemple : 13).

La valeur qui nous intéresse est renvoyée via la propriété DayTimeStr du composant TIdDayTime.

Maintenant que vous avez les principales informations nécessaires à la compréhension des sources, vous pouvez les télécharger et les tester à votre guise :

Continuons notre voyage dans le temps avec les composants utilisant le protocole Simple Network Time Protocol…

IV-B-2 - Utilisation du composant TIdSNTP (Indy)

Le composant TIdSNTP disponible sous Delphi 6 possède de nombreux bogues et ne fonctionne pas correctement.

Aussi, pour tester cet exemple, vous devez télécharger la version 9.0 de la suite Indy sur le site de Nevrona :

Télécharger une des versions récentes de Indy

Si vous avez mis à jour vos composants Indy, nous allons pouvoir utiliser le composant TIdSNTP qui utilise le protocole Simple Network Time Protocol.

Palette

Composant

Indy

TIdSNTP

De nombreux serveurs utilisant ce protocole sont disponibles sur Internet.
Pour en avoir la liste, consultez la page des liens de ce tutoriel. Lisez bien les conditions d'accès à ces serveurs…

Je vous rappelle qu'en tant que poste « Client », vous devez uniquement vous connecter à des serveurs de temps secondaires (« Strate 2 »).

Nous interrogerons ces serveurs via le port 123.

Voici les propriétés du composant TIdSNTP à renseigner pour interroger un de ces serveurs de temps :

- Host : il s'agit de l'adresse ou de l'alias du serveur de temps (Exemple : ntp.univ-lyon1.fr) ;

- Port : il s'agit du port via lequel il est possible d'interroger le serveur de temps (Exemple : 123).

La valeur qui nous intéresse est renvoyée via la propriété DayTime.

Maintenant que vous avez les principales informations nécessaires à la compréhension des sources, vous pouvez les télécharger et les tester à votre guise :

Je vous laisse le loisir d'étudier les autres propriétés de ces composants.
Si vous désirez plus amples informations sur tous les domaines abordés dans ce tutoriel, je vous ai sélectionné quelques sites intéressants…

V - Ouvrages et adresses Internet utiles

Vous trouverez ci-après différentes informations et utilitaires qui m'ont permis de créer ce tutoriel. Cette liste est bien évidemment non exhaustive… ;-)

Serveurs de temps

Les serveurs de temps français

Liste des serveurs de temps français utilisant le protocole « Network Time Protocol ».

National Institute of Standards and Technology

Site gouvernemental américain proposant un serveur de temps utilisant le protocole « Time Protocol ».

Sources Delphi

Indy

La très célèbre suite de composants « Internet Direct » développée par la société Nevrona.

Synapse Project

Projet Delphi proposant notamment des routines d'interrogation des serveurs de temps.

Time Memo

Projet Delphi utilisant les routines Synapse pour interroger des serveurs de temps.

Informations techniques

community.roxen.com

Ce site propose lui aussi les Request For Comments, mais au format HTML.

Guill.net - La page des réseaux

Excellent site d'information sur le fonctionnement des réseaux, les protocoles, les normes, etc.

Documentation Indy

Documentation sur les protocoles Date/Heure sur le site de Nevrona.

Kudzu Article Collection

Introduction aux Sockets, IP, adresses, Host Names, DNS, TCP, UDP & Ports…

RFC Editor

Ce site propose une base de données contenant les différentes Request For Comments (RFC) au format TXT disponibles sur le web.

Groupes de discussion

comp.protocols.time.ntp

Groupe de discussion traitant du protocole « Network Time Protocol ».

Voilà ! Vous avez tout en main pour créer des logiciels utilisant la date et l'heure…

En guise de bonus, je vous offre l'ensemble des informations de ce tutoriel dans le fichier ci-dessous. Vous y trouverez le tutoriel au format PDF et les sources des petits programmes Delphi que nous avons développés… :-)

Je tiens à remercier très sincèrement les développeurs suivants pour leur aide précieuse :

- Sylvain James (TeamB-Fr) pour la relecture et la correction du tutoriel ;

- Henri Cesbron-Lavau (TeamB-Fr) pour ces conseils avisés ;

- Kurt Barthelmess (TeamB-US) pour ces explications concernant les bogues du composant TIdSNTP sous Delphi 6.