IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Notes sur le langage C


précédentsommairesuivant

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 chaine 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 chaine 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 n’utilise pas l'adresse d'un time_t, il faut le préciser à la fonction en passant NULL :

 
Sélectionnez
#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éments 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 pseudoaléatoire du C avec une valeur différente à chaque lancement :

 
Sélectionnez
srand((unsigned) time(NULL));

ce qui permet de démarrer le cycle de la séquence pseudoalé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 grâce à 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.

 
Sélectionnez
#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 chaine 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;
}
 
Sélectionnez
'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.

 
Sélectionnez
#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 pseudoalé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.

À chaque fois que l'on appelle rand(), une nouvelle valeur sort :

 
Sélectionnez
#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 :

 
Sélectionnez
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 :

 
Sélectionnez
#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 :

 
Sélectionnez
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.

 
Sélectionnez
#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 :

 
Sélectionnez
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.


précédentsommairesuivant

Copyright © 2009 Emmanuel Delahaye. Aucune reproduction, même partielle, ne peut être faite de ce site ni 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.