XXXV. <time.h> : La gestion du temps▲
XXXV-A. Introduction▲
Le langage C fournit un certain nombre de fonctions permettant de lire l'heure/date courante et de convertir la valeur lue en structure ou en chaîne de caractères. Ces éléments sont définis et déclarés dans le header standard <time.h>
Élément | Nature | Description |
struct tm | structure | Structure de date et heure |
time() | fonction | Lecture de l'heure courante |
time_t | type | Type retourné par time() |
localtime() | fonction | Charge la structure tm avec l'heure locale |
gmtime() | fonction | Charge la structure tm avec l'heure GMT |
mktime() | fonction | Normalise la structure tm Retourne le temps en time_t |
strftime() | fonction | Crée une chaîne formatée à partir d'une structure tm |
difftime() | fonction | Calcule la différence entre deux dates |
XXXV-B. Usage▲
XXXV-B-1. Lire l'heure courante▲
On utilise la fonction time(). On peut soit passer l'adresse d'un time_t, soit récupérer la valeur dans un time_t. Si on utilise pas l'adresse d'un time_t, il faut le préciser à la fonction en passant NULL :
#include <time.h>
int
main (
void
)
{
time_t ta;
time_t tb;
time (&
ta);
tb =
time (
NULL
);
return
0
;
}
Telle quelle, la valeur contenue dans ta et tb n'a pas grande signification. La norme dit que c'est un grand entier qui représente un nombre d'élément de temps depuis une date donnée. Sous POSIX.1, c'est un nombre de secondes depuis le 1er janvier 1970. (Epoch). En principe, on ne manipule pas la valeur directement, mais via sa représentation en struct tm.
Cette valeur a quand même un intérêt pratique. Il y a de fortes chances qu'elle soit différente d'un lancement de programme à l'autre. On l'utilise donc couramment pour initialiser le générateur pseudo-aléatoire du C avec une valeur différente à chaque lancement :
srand
((
unsigned
) time
(
NULL
));
ce qui permet de démarrer le cycle de la séquence pseudo-aléatoire à un endroit difficilement prévisible, renforçant ainsi l'effet 'aléatoire' pour les jeux et autres programmes statistiques.
XXXV-B-2. Afficher l'heure courante▲
L'affichage de la date ou de l'heure de fait grace à la fonction strftime() qui a été conçue pour ça. Elle attend l'adresse d'une structure tm, qu'il va donc falloir mettre à jour au préalable. On utilise pour ça la valeur retournée par time(), qui donne la datation courante sous la forme d'un entier et une des fonction localtime() ou gmtime() selon que l'on veut convertir en heure locale ou en heure GMT (Greenwich). En France, il y a une heure de différence.
L'usage précis de strftime() et de ses nombreux paramètres de formatage doit être étudié dans un document de référence.
#include <stdio.h>
#include <time.h>
int
main (
void
)
{
/* lire l'heure courante */
time_t now =
time (
NULL
);
/* la convertir en heure locale */
struct
tm tm_now =
*
localtime (&
now);
/* Créer une chaîne JJ/MM/AAAA HH:MM:SS */
char
s_now[sizeof
"
JJ/MM/AAAA HH:MM:SS
"
];
strftime (
s_now, sizeof
s_now, "
%d/%m/%Y %H:%M:%S
"
, &
tm_now);
/* afficher le résultat : */
printf (
"
'%s'
\n
"
, s_now);
return
0
;
}
'29/01/2009 02:34:00'
Process returned 0 (0x0) execution time : 0.054 s
Press any key to continue.
XXXVI. <time.h> : bien utiliser difftime()▲
Les fonctions de <time.h> offrent une interface assez complexe. Voici un exemple qui rassemble l'usage de la plupart de ces fonctions.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int
main (
void
)
{
time_t now =
time (
NULL
);
struct
tm tm_now =
*
localtime (&
now);
char
s[64
];
strftime (
s, sizeof
s, "
%d/%m/%Y
"
, &
tm_now);
printf (
"
Aujourd'hui : %s
\n
"
, s);
/* prochain Noel */
{
struct
tm tm_xmas =
{
0
}
;
tm_xmas.tm_year =
tm_now.tm_year;
tm_xmas.tm_mon =
12
-
1
;
tm_xmas.tm_mday =
25
;
/* ajustement */
{
time_t xmas =
mktime (&
tm_xmas);
strftime (
s, sizeof
s, "
%d/%m/%Y
"
, &
tm_xmas);
printf (
"
Noel : %s
\n
"
, s);
{
time_t diff =
difftime (
xmas, now);
struct
tm tm_diff =
*
gmtime (&
diff);
printf (
"
Plus que %d jours avant Noel
\n
"
, tm_diff.tm_yday);
}
}
}
return
0
;
}
XXXVII. rand(), srand()... j'y comprends rien...▲
Un générateur pseudo-aléatoire est une machine qui génère une séquence de nombres déterminée, cyclique, mais difficile à prévoir pour un humain. De plus, la répartition des valeurs (histogramme) est supposée être équilibrée.
La génération n'est pas 'spontanée', mais 'à la demande' (par appel de la fonction rand()). Les valeurs produites sont comprises entre 0 et RAND_MAX inclus.
A chaque fois que l'on appelle rand(), une nouvelle valeur sort :
#include <stdio.h>
#include <stdlib.h>
int
main (
void
)
{
int
i;
printf (
"
Les valeurs vont de 0 a %d
\n
"
, RAND_MAX);
for
(
i =
0
; i <
10
; i++
)
{
int
val =
rand (
);
printf (
"
%d
"
, val);
}
printf (
"
\n
"
);
return
0
;
}
Par exemple :
Les valeurs vont de 0 à 32767
41 18467 6334 26500 19169 15724 11478 29358 26962 24464
Mais on constate que si on lance le programme plusieurs fois, la séquence est toujours la même.
On peut modifier l'origine de la séquence avec srand(), en passant une valeur comprise entre 0 et RAND_MAX. Par exemple 10 :
#include <stdio.h>
#include <stdlib.h>
int
main (
void
)
{
int
i;
srand
(
10
); /* MODIF */
printf (
"
Les valeurs vont de 0 a %d
\n
"
, RAND_MAX);
for
(
i =
0
; i <
10
; i++
)
{
int
val =
rand (
);
printf (
"
%d
"
, val);
}
printf (
"
\n
"
);
return
0
;
}
On constate que les valeurs sont différentes du tirage précédent, mais que si on relance le programme, elles restent identiques :
Les valeurs vont de 0 à 32767
71 16899 3272 13694 13697 18296 6722 3012 11726 1899
Pour avoir une séquence différente à chaque lancement du programme, il faut donc trouver un moyen de passer une valeur 'changeante' à srand(), d'où l'idée d'utiliser la valeur retournée par time(), qui change une fois par seconde, indépendamment du programme (c'est une valeur gérée par le système).
Une seconde, c'est long, mais ça suffit pour les besoins courants.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int
main (
void
)
{
int
i;
srand
((
unsigned
) time
(
NULL
)); /* MODIF */
printf (
"
Les valeurs vont de 0 a %d
\n
"
, RAND_MAX);
for
(
i =
0
; i <
10
; i++
)
{
int
val =
rand (
);
printf (
"
%d
"
, val);
}
printf (
"
\n
"
);
return
0
;
}
Si on lance plusieurs fois le programme (au moins une seconde entre chaque lancement), on obtient maintenant des séquences différentes :
25985 16903 23861 29724 17917 23752 17039 25712 20507 30816
26197 27421 5384 20976 236 16846 22741 32047 12417 24408
26433 14874 13653 16830 21990 4658 17461 17892 21603 7731
etc. Je précise que pour que les valeurs changent dans le programme, il faut évidemment que srand() ne soit appelé qu'une seule fois au début du programme.
Après, il y a des astuces arithmétiques pour réduire la plage de valeurs... C'est du bête calcul entier... Détails dans la FAQ de f.c.l.c., notamment ici. D'autre part, ceci peut aider.