Aller au menu - Aller au contenu

Icône time.h et ses fonctions

Avatar
Mise à jour : 31/03/2011
Difficulté : Facile Facile Durée d'étude : 2 heures, 30 minutes
378 visites depuis 7 jours, classé 281/786
Bonjour à tous !

Vous venez de terminer la lecture des deux premiers chapitres du cours officiel sur le C ? Mais vous avez peut-être remarqué que la gestion du temps manque à l'appel.

Effectivement, la gestion du temps (que ce soit créer une attente ou afficher la date) ne fait pas partie du tutoriel officiel du C de M@teo21. Et c'est ce que je vais vous apprendre tout au long de ce cours.

La gestion du temps en C/C++ passe par la bibliothèque time.h, renommée en ctime en C++. Donc pour suivre le cours, vous devrez utiliser la directive de préprocesseur correspondant au langage dans lequel vous compilez :

Code : C - Si vous compilez en C…
1
#include <time.h>

Code : C++ - Si vous compilez en C++…
1
#include <ctime>


Grâce à cette directive de préprocesseur, vous serez apte à utiliser l'intégralité des fonctions présentes dans la bibliothèque time.h.

Bonne lecture !

Un nouveau standard C++ est sorti il y a peu, nommé C++ 0x.
Il introduit une nouvelle façon de gérer le temps via la classe « chrono ».
Lorsque la norme C++ 0x sera rendue plus facile d'accès, je rédigerai peut-être un cours dessus.

Obtenir une date et une heure

Dans cette partie nous allons voir :
  • comment obtenir la date et l'heure actuelle ;
  • comment situer son programme dans le temps (et ainsi créer un chronomètre, par exemple).


struct tm : Structure du temps



Pour manipuler les dates et les heures, il nous faut de quoi stocker le temps de manière compréhensible, c'est-à-dire qu'au lieu d'une seule variable contenant des secondes (on se retrouverait avec des modulos partout), nous aurons une structure contenant un instant mais utilisant les différentes unités et informations que l'on emploie (année, mois, jour du mois, jour de la semaine, jour de l'année, heure, minute, seconde et si nous sommes en heure d'été ou d'hiver).

struct tm répond à ce besoin. Il s'agit d'une structure contenant les variables suivantes.
Variable Représente Rang
tm_year Le nombre d'années depuis 1900. 0 - ?
tm_mon Mois écoulés depuis janvier (n° du mois-1). 0 - 11
tm_yday Nombre de jours écoulés depuis le 1er janvier (n° jour-1). 0 - 365
tm_mday Numéro du jour du mois. 1 - 31
tm_wday Nombre de jours écoulés depuis dimanche (et non lundi). 0 - 6
tm_hour Nombre d'heures écoulées depuis minuit. 0 - 23
tm_min Nombre de minutes écoulées depuis le dernier changement d'heure. 0 - 59
tm_sec Nombre de secondes écoulées depuis le dernier changement de minute. 0 - 60*
tm_isdst -1 si l'information est indisponible ;
0 si c'est l'heure d'hiver ;
+1 si c'est l'heure d'été.
-


? : Dépend de la façon dont la date est gérée par votre système d'exploitation.
* : Certains systèmes nécessitent une marge pour éviter des bugs. Néanmoins, retenez 0 - 59. Cette marge n'a pas vraiment d'importance.

Cette structure correspond donc à la représentation d'un instant avec de nombreuses informations simples à exploiter ! Nous n'allons pas encore la remplir automatiquement suivant l'heure interne de votre ordinateur, mais je vous propose un code d'exemple pour comprendre son utilisation (pas très propre mais c'est pour l'exemple).

Exemple



Code : C - Exemple : Remplir une struct tm
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <time.h>

int main(void)
{
    struct tm instant;
    int remplir;

    printf("Entrez le mois : ");
    scanf("%d", &remplir);
    instant.tm_mon = remplir-1;

    printf("Entrez le jour : ");
    scanf("%d", &remplir);
    instant.tm_mday = remplir-1;

    printf("Entrez l'heure : ");
    scanf("%d", &remplir);
    instant.tm_hour = remplir;

    printf("Entrez la minute : ");
    scanf("%d", &remplir);
    instant.tm_min = remplir;

    printf("Entrez la seconde : ");
    scanf("%d", &remplir);
    instant.tm_sec = remplir;

    printf("%d/%d ; %d:%d:%d", instant.tm_mday+1, instant.tm_mon+1, instant.tm_hour, instant.tm_min, instant.tm_sec);
    return 0;
}


Pour les directives de préprocesseur, on inclut bien sûr stdio.h pour les fonctions printf() et scanf() et time.h pour notre struct tm. stdlib.h n'est pas nécessaire dans notre cas.

Dans la fonction int main(void) (void signifie que la fonction ne prend rien), on a la déclaration de la structure instant de type struct tm et la variable « remplir » qui nous servira à supprimer un décalage par la suite. Puis on demande à l'utilisateur d'entrer des valeurs qui seront conservées dans les variables appropriées en passant par « remplir ». Grâce à « remplir », on supprime le décalage présent pour le mois et le jour. Pour les heures, minutes et secondes, ce n'est pas la peine. Pour remplir la structure, on remplit chaque variable en la précédant du nom de la structure et d'un point. Les structures vous sont expliquées dans le cours officiel.

Au sein de la fonction printf(), on a une mise en forme des valeurs que l'on a remplies. Remarquez que les variables tm_mday et tm_mon ne sont pas affichées telles qu'elles sont mais avec une incrémentation afin d'obtenir les vrais numéros du mois et du jour. En fait, cela sert à remettre tout ça dans les bonnes valeurs. Ces problèmes de décalages peuvent être assez déroutants, mais on comprend très vite grâce au tableau situé au début de cette partie.

Voici ce que ça peut donner :
Code : Console - Et le Site du Zéro fut !
Entrez le mois : 11
Entrez le jour : 10
Entrez l'heure : 0
Entrez la minute : 0
Entrez la seconde : 0
10/11 ; 0:0:0


Il peut être intéressant d'utiliser un pointeur vers une struct tm plutôt qu'une struct tm directement car les fonctions de time.h renvoient des pointeurs et non la structure pointée. Pour le remplissage manuel que nous venons d'effectuer, cela reste assez déconseillé. Les pointeurs vous sont expliqués dans le cours officiel.


Exercice



Ajoutez les années à mon code. Attention, il y a un piège !

clock() : Situer son programme dans le temps



clock() est un bidule assez intéressant. Il permet de situer son programme dans le temps. Voici son prototype :

Code : C - Prototype de clock()
1
clock_t clock (void);


Cette fonction ne prend donc aucun paramètre et renvoie un nombre sous un nouveau type : le clock_t. Le type clock_t permet d'exprimer un nombre de clock ticks. Utilisez donc ce type lorsque vous souhaitez utiliser des clock ticks (comme le type size_t fait référence à une taille).

Le clock tick (ou battement pour les puristes du français) est une unité de mesure du temps interne de votre ordinateur. Qu'est-ce que ça représente par rapport à la seconde ? Eh bien…
Secret (cliquez pour afficher)
Vous l'avez deviné : ça dépend !

En fait, cette valeur dépend de votre système d'exploitation et de votre processeur. time.h possède une macro permettant savoir combien de clock ticks par seconde votre ordinateur gère. Il s'agit de la macro CLOCKS_PER_SEC.

Il est possible que clock() retourne -1.
Si c'est le cas, c'est qu'il y a eu une erreur. Prévoyez ce cas dans vos futurs programmes.


Bon, assez parlé, testons clock().

Code : C - Exemple : Récupérer le tick 0
1
2
3
4
5
6
7
8
#include <stdio.h>
#include <time.h>

int main(void)
{
    printf("%f\n", (double) clock());
    return 0;
}


Ce code est un programme tout bête qui affiche la valeur retournée par clock(). Remarquez le (double) avant l'appel de la fonction. Il permet de transformer les clock_t renvoyés en double afin d'éviter un beau warning. On appelle cette action le cast (un cast en (int) marche, mais néanmoins il arrive que ce type contienne un nombre décimal, alors on utilise %f avec un cast (double), mais attention, ça ne marche pas dans tous les cas).

Qu'affiche-t-il ?
Code : Console - Un résultat nul dans les deux sens du terme
0


Aïe. Quelque chose ne va pas dans ton code.
Laisse-moi deviner. Comme clock() est appelée dès le début, elle renvoie le début du programme, soit 0 clock tick ?


Exactement ! Il va donc falloir mettre une attente avant l'appel de clock().

Code : C - Récupérer un certain tick
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>
#include <time.h>

int main(void)
{
    getchar();

    printf("%f\n", (double) clock());
    return 0;
}


Un getchar() vous demandera d'appuyer sur la touche Entrée avant de continuer et d'afficher la valeur renvoyée par clock().

C'est bien beau, mais tu as dit que cette fonction était intéressante.
Or, ça ne sert à rien.


Bien au contraire ! Réfléchissez bien. Cela permet de faire un chronomètre par exemple ! Voyez cette nouvelle version du Plus ou Moins !

Code : C - Plus ou Moins avec un chronomètre
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    int mystere, nombreentre;
    clock_t temps;

    srand(time(NULL));
    mystere=rand()%100+1;

    do{
        puts("Quel est le nombre ? ");
        scanf("%d", &nombreentre);

        if(nombreentre>mystere)
            puts("C'est moins !\n");
        if(nombreentre<mystere)
            puts("C'est plus !\n");
        if(nombreentre==mystere){
            temps=clock();
            printf("Bravo !\nTu as mis %f secondes a trouver le nombre.\n", (double) temps/CLOCKS_PER_SEC);
        }
    }while(nombreentre!=mystere);

    return 0;
}


C'est le même logiciel (je l'ai un peu simplifié mais c'est le même principe) sauf que l'on a ici une variable temps de type clock_t et lorsque le nombre est trouvé, on lui donne la bonne valeur via la fonction clock(). Après cela, on affiche les résultats grâce au fameux %f et une division temps/CLOCKS_PER_SEC sans oublier le cast (double) avant pour éviter un warning. Grâce à cette division, on obtient des secondes et non des clock ticks.

Code : Console - Ce qu'affichent les résultats sous Windows 32 bits (1000 CLOCKS_PER_SEC)
Quel est le nombre ?
61
Bravo !
Tu as mis 13.156000 secondes a trouver le nombre.


Exercice



On peut faire un chronomètre, mais aussi une attente ! Créez une fonction permettant de faire une attente et qui aura ce prototype :
Code : C
1
void attendre(float temps);

Le temps sera bien sûr en secondes (et pas en siècles…).

C'est parti !

Correction
Secret (cliquez pour afficher)
Il fallait utiliser une boucle vide se répétant tant que clock() ne renvoie pas une valeur que l'on a prédite à l'avance via un petit calcul. J'ai réalisé, en plus de cette fonction, un petit programme pour tester.

Code : C - Exemple d'attente
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <time.h>

void attendre(float temps);

int main(void)
{
    int compteur;

    for(compteur=10;compteur>0;compteur--){
        printf("%d...\n", compteur);

        attendre(1);
    }

    puts("BONNE ANNEE !!!\n");

    return 0;
}

void attendre(float temps)
{
    clock_t arrivee=clock()+(temps*CLOCKS_PER_SEC); // On calcule le moment où l'attente devra s'arrêter

    while(clock()<arrivee);
}


Pour calculer le moment où l'attente s'arrête, on prend le moment dans lequel on se trouve (le début de l'attente) puis on y ajoute le temps d'attente en le transformant en clock ticks (d'où la multiplication par CLOCKS_PER_SEC).


Par contre, cette attente n'est pas aussi géniale que l'on pourrait le croire. En effet, elle consomme beaucoup de CPU. Il existe deux fonctions plus propres et moins gourmandes pour faire une attente : sleep() et Sleep() (la majuscule fait toute la différence).

sleep() est dans le header unistd.h (Linux et Mac uniquement) et Sleep() dans windows.h (vous savez pour quel système d'exploitation !). De plus elles ne prennent pas la même unité : Sleep() attend des millisecondes d'après sa page sur la MSDN et sleep() des secondes. Voici donc un code préprocesseur vous permettant d'obtenir une fonction attendre propre et portable sous forme de macro :

Code : C - Macro ATTENDRE() portable
1
2
3
4
5
6
7
#if defined (WIN32) || defined (WIN64)
#include <windows.h>
#define ATTENDRE(temps) Sleep(temps*1000)
#else
#include <unistd.h>
#define ATTENDRE(temps) sleep(temps)
#endif


time() : Obtenir la date et l'heure



Attention, nous allons enfin voir comment remplir une struct tm avec l'heure interne de votre ordinateur. Mais nous avons besoin de passer par deux fonctions pour ce faire. La première est time(). Elle est souvent utilisée dans la génération de nombres pseudo-aléatoires (voyez le Plus ou Moins). Mais que fait-elle ? Voyons son prototype…

Code : C - Prototype de time()
1
time_t time(time_t *variable);


Un nouveau type ! time_t est un type de variable qui sert à indiquer un nombre de secondes.

Bon ! En fait, time() a un fonctionnement assez bizarre : faire variable=time(NULL) revient à faire time(&variable) (n'oubliez pas le &, sinon, warning). time() va mettre la valeur à renvoyer directement dans la variable dans les deux cas (d'où l'utilisation du NULL dans le premier cas, vu qu'il n'y a aucune variable à remplir en paramètre).

Et ce qu'elle renvoie, ça correspond à quoi ?


La valeur renvoyée correspond au nombre de secondes écoulées depuis le premier janvier 1970. Non, cette date ne correspond à rien d'autre que le début du calendrier sur la plupart des systèmes d'exploitation.

Il est possible que time() retourne -1.
Si c'est le cas, c'est qu'elle n'a pas réussi à récupérer la valeur de temps.
Prévoyez ce cas dans vos futurs programmes.


Juste comme ça, pourquoi l'utilise-t-on pour générer des nombres pseudo-aléatoires ?


srand() demande un nombre pour l'initialiser car si on lui donne le même nombre, la fonction génèrera la même suite de nombres. Alors on utilise le temps car il est très rare de lancer deux fois le même programme dans la même seconde.

Voyons un exemple tout bête de la fonction time() :
Code : C - Exemple : Le temps interne de votre ordinateur
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <time.h>

int main(void)
{
    printf("Il s'est ecoule %f secondes depuis le 1er janvier 1970.\n", (double) time(NULL));

    return 0;
}


Code : Console
Il s'est ecoule 1298819112 secondes depuis le 1er janvier 1970.

Spécial quizz : devinez à quel moment j'ai lancé mon programme sans utiliser les fonctions que nous verrons par la suite !

localtime() : Utiliser ce qui est renvoyé par time() pour remplir une struct tm



time(), c'est bien, mais on ne peut pas en faire grand chose. localtime() va nous permettre d'utiliser time() pour remplir une struct tm. Voici son prototype :

Code : C - Prototype de localtime()
1
struct tm* localtime (const time_t *secondes);


Elle prend un nombre de secondes pour renvoyer un pointeur vers une struct tm. Et devinez comment on fait pour remplir une struct tm avec l'heure actuelle ? C'est simple ! On récupère d'abord le temps actuel grâce à time() puis on remplit notre struct tm via localtime().

La valeur renvoyée est un pointeur vers une zone mémoire allouée statiquement et partagée entre les fonctions gmtime(), localtime() et ctime(). Vous pouvez donc utiliser des pointeurs pour ne pas avoir à copier la valeur de cette zone mémoire. Attention cependant à utiliser cela correctement car les précédentes valeurs de la zone mémoire seront écrasées lors des prochains appels de ces fonctions.

Code : C - Exemple : Horloge
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t secondes;
    struct tm instant;

    time(&secondes);
    instant=*localtime(&secondes);

    printf("%d/%d ; %d:%d:%d\n", instant.tm_mday+1, instant.tm_mon+1, instant.tm_hour, instant.tm_min, instant.tm_sec);
    return 0;
}


C'est le même code que lorsque je vous ai appris à remplir une struct tm sauf que, cette fois-ci, les fonctions le font pour nous. Remarquez que pour remplir « instant », j'utilise un pointeur. Si je ne mets pas cet astérisque (*), on renvoie un pointeur dans une struct tm, ce qui provoque une erreur lors de la compilation.

Code : Console - Vous avez un gros indice pour le top spécial quizz
28/2 ; 16:32:28


Notez qu'il existe une fonction pour directement mettre notre struct tm en forme : asctime().
Mais nous verrons tout ça dans la troisième partie.


gmtime() : Obtenir l'heure GMT



Lire l'article GMT sur Wikipédia

L'heure GMT, c'est l'heure qu'il est en Grande Bretagne, chez nos amis les anglais. Or, en France, au Québec ou en Australie ce n'est pas la même heure. Mais en utilisant gmtime(), on peut récupérer l'heure GMT.

Code : C - Prototype de gmtime()
1
struct tm* gmtime (const time_t *temps);


Cette fonction prend en paramètre le nombre de secondes depuis le 1er janvier 1970 dans votre fuseau horaire (pas besoin de conversion) et renvoie l’adresse mémoire de time.h destinée aux struct tm (reportez-vous à la partie sur localtime()) après l'avoir remplie avec l'heure GMT. Par exemple en France, ce sera une heure avant puisque la France se situe dans le fuseau horaire +1.

Son utilité ? Imaginez que vous habitiez à Sydney en Australie et que vous souhaitiez prendre l'avion pour New York aux États-Unis. Vous savez combien de temps dure le trajet mais vous voulez arriver dans une fourchette d'heures bien précise (disons entre 13h et 15h, heure de New York). Vous connaissez la durée du trajet, oui mais pas l'heure qu'il est là-bas. gmtime() vous permettra de la trouver avec des calculs très simples.

Voici la représentation du monde avec les différents fuseaux horaires.

Représentation du monde avec les différents fuseaux horaires
Représentation du monde avec les différents fuseaux horaires.
Image tirée de Wikipédia, œuvre placée dans le domaine public.


Sydney se trouve donc dans un fuseau horaire GST (GMT+10) et New York dans un fuseau horaire EST (GMT-5). Cela signifie que lorsqu'il est minuit à Greenwich — ville où a été placé le méridien d'origine et donc le fuseau horaire UDC (celui correspondant à l'heure GMT) —, il est 10 heures à Sydney et 19h à New York.

Code : C - Des macros utiles pour le décalage horaire
1
2
#define SYD 10
#define NYC -5

Un moyen simple est de créer des macros correspondant aux fuseaux horaires (certains fuseaux horaires ont des noms civils et militaires mais pour des raisons de simplicité, j'ai mis les noms des villes Sydney et New York City) correspondant au décalage horaire par rapport à GMT.



Code : C - Exemple : Le voyage Sydney-New York
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <time.h>
#define SYD 10
#define NYC -5

int main(void)
{
    time_t temps;
    struct tm date;

    time(&temps);
    date=*gmtime(&temps);

    printf("GMT: %d:%d\n", date.tm_hour, date.tm_min);
    printf("Sydney: %d:%d\n", (date.tm_hour+SYD+24)%24, date.tm_min);
    printf("New-York: %d:%d\n", (date.tm_hour+NYC+24)%24, date.tm_min);

    return 0;
}


Après avoir placé nos macros et initialisé nos variables, on récupère l'heure GMT actuelle via time() et gmtime(). Ensuite, on place des printf() qui doivent nous indiquer l'heure GMT, l'heure de Sydney et l'heure de New York. Pour la calculer, on fait le calcul (heure+décalage+24)%24. Le modulo est nécessaire car si on ne le met pas, on pourrait se retrouver avec des heures comme 26:30. Et je n'aimerais pas créer de faille spatio-temporelle. De même pour le +24 avant le modulo. Si avec la soustraction de l'heure pour le fuseau horaire de New York on obtient une heure négative, il va falloir la transformer en un nombre positif entre 0 et 24. Pour ce faire, on ajoute tout simplement 24. Le modulo supprimera les heures en trop s'il y en a.

Code : Console
GMT: 17:1
Sydney: 3:1
New-York: 12:1


Entre nous, je crois que c'est fichu pour aller à New York aujourd'hui.

En tout cas, on en a enfin fini avec les différentes manières d'obtenir des informations relatives au temps. La partie 2 porte sur quelques manipulations et calculs réalisables avec les informations obtenues.

Effectuer des manipulations avec les informations obtenues

Vous savez maintenant obtenir un moment précis et situer votre programme dans le temps. Maintenant, nous allons utiliser les informations obtenues pour effectuer quelques manipulations. Seules deux fonctions seront vues, en fait :
  • difftime() pour trouver l'intervalle entre deux moments ;
  • mktime() pour compléter une struct tm à partir de seulement 3 variables et/ou exécuter le procédé inverse de localtime().


difftime() : Faire la différence entre deux instants



Ici, nous allons apprendre à faire une différence entre deux moments. Imaginez que vous souhaitiez battre le record du monde du temps d'enfermement dans un carton (oui ; je sais, c'est pourri). N'ayant pas de montre et dormant fréquemment, vous ne savez pas combien de temps vous avez passé dans votre boîte. Mais imaginez qu'à côté vous ayez un ordinateur ayant enregistré le moment où vous êtres entré et celui où vous êtes sorti. Eh bien difftime() fera automatiquement la différence entre ces deux moments ! Allez, lisez cette partie et tentez le record !

Code : C - Prototype de difftime()
1
double difftime (time_t arrivee, time_t depart);


Vous l'aurez remarqué, on fait la différence à partir de deux time_t, soit deux nombres représentant le nombre de secondes écoulées depuis le 1er janvier 1970. Voyons voir ça.

Code : C - Exemple : Chronométrer une longue durée
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t depart, arrivee;
    time(&depart);

    puts("Tu peux maintenant aller faire autre chose...\n");
    getchar();

    time(&arrivee);
    printf("Tu t'es absente pendant %f secondes.", difftime(arrivee, depart));

    return 0;
}


Voilà, vous pouvez rentrer dans votre carton. Donc on initialise deux variables qui stockeront le départ et l'arrivée et on donne la bonne valeur à « départ ». Un getchar() sert à faire une attente jusqu'à ce que l'utilisateur appuie sur Entrée, et on donne la bonne valeur à « arrivee ». Puis viennent les résultats où on affiche ce que renvoie difftime(), soit le temps qui s'est écoulé entre le départ et l'arrivée. Il y a des avantages par rapport à clock(), mais pour de petites durées, il vaut mieux un bon clock() car vous obtiendrez des résultats plus précis en fonction du nombre de clock ticks par seconde.

Code : Console
Tu peux maintenant aller faire autre chose...


Tu t'es absente pendant 411.000000 secondes.


mktime() : Compléter une struct tm



Il arrivera souvent que vous remplissiez une struct tm mais à moitié. Et tout à coup, vous avez besoin d'une valeur que vous n'avez pas remplie. Comment la calculer ? mktime() va faire tout le boulot à votre place.

Code : C - Prototype de mktime()
1
time_t mktime (struct tm *structure);


Cette fonction prend en paramètre une struct tm et renvoie la valeur time_t correspondante à celle-ci, soit le procédé inverse de localtime(). Mais elle ne sert pas qu'à ça. Elle sert en effet à remplir une struct tm incomplète à partir de ces 3 valeurs :
  • tm_year ;
  • tm_mon ;
  • tm_mday.

Toutes les autres valeurs mises à part « tm_hour », « tm_min » et « tm_sec » seront calculées à partir des 3 variables nécessaires. Cette fonction permet notamment de savoir quel jour de la semaine on est à partir du jour du mois, ou alors de connaître quel jour on sera dans x jours. Je pense que l'on peut trouver pas mal d'exemples, alors on va faire tout simple : savoir quel jour de l'année on est à partir d'une date précise !

Il est possible que mktime() retourne -1.
Si c'est le cas, c'est qu'il y a eu une erreur. Prévoyez ce cas dans vos futurs programmes.


Code : C - Exemple : Trouver le numéro du jour dans l'année
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t temps;
    struct tm date;
    int remplir;

    // On demande à l'utilisateur de remplir les valeurs demandées.
    // Ne pas oublier d'additionner ou de soustraire les bonnes valeurs pour éviter les décalages.
    puts("Annee ? ");
    scanf("%d", &remplir);
    date.tm_year=remplir-1900;

    puts("Mois ? ");
    scanf("%d", &remplir);
    date.tm_mon=remplir-1;

    puts("Jour ? ");
    scanf("%d", &remplir);
    date.tm_mday=remplir;

    // On s'assure que l'instant est bien placé à minuit.
    date.tm_hour=0;
    date.tm_min=0;
    date.tm_sec=0;

    temps=mktime(&date);

    printf("C'est le %deme jour de l'annee !\nEt minuit est la %deme seconde depuis le 1er janvier 1970.\n", date.tm_yday, (int) temps);

    return 0;
}

On demande donc à l'utilisateur de remplir les champs « année », « mois » et « jour du mois » pour remplir les autres cases de la structure. Remarquez que j'ai mis les variables de l'heure, minutes et secondes à 0 pour se positionner sur minuit. Ensuite, après mktime(), on affiche « date.tm_yday » que mktime() a calculée, et petit bonus, la valeur renvoyée par mktime() qui correspond au nombre de secondes écoulées entre le 1er janvier 1970 à minuit et cette date.

Code : Console - Et le Site du Zéro fut 2.0
Annee ?
1999
Mois ?
11
Jour ?
10
C'est le 312eme jour de l'annee !
Et minuit est la 942184800eme seconde depuis le 1er janvier 1970.


Après vérification, j'ai pu constater que mktime remplit la struct tm avec deux jours de décalage en arrière pour les jours de l'année. Je n'ai aucune idée de la cause de ce décalage ni s'il est présent sur tous les systèmes, mais si c'est le cas chez vous (vous pouvez vérifier avec Wikipédia), vous pouvez régler ce problème de deux façons :
  • changer la valeur de tm_yday après l'usage de mktime :
    Code : C - Changer tm_yday
    1
    2
    temps=mktime(&date);
    date.tm_yday+=2;
    
  • appeler ensuite les valeurs de cette manière (dans notre cas, la valeur est appelée dans printf) :
    Code : C - Ajouter une valeur lors de la lecture
    1
    date.tm_yday+2
    

Je recommande toutefois la première solution car vous n'aurez qu'à rajouter une ligne et pas faire des mois de recherche dans un gros code.


C'est loin d'être le seul exemple. Soyez créatif, il y a pas mal de possibilités !

Afficher l'heure obtenue

Cette troisième partie n'est pas la plus importante. Elle est cependant intéressante car elle va vous permettre d'écrire les moments obtenus dans vos programmes.

Un coup de printf() ne suffit-il pas ?


En fait, on va apprendre à placer l'heure écrite dans un format bien précis et directement dans une chaîne de caractères.

asctime() : Transformer une struct tm en char[]



Ce titre vous semble délirant, et pourtant c'est entièrement vrai : asctime() vous permet de transformer une struct tm en char[], c'est à dire mettre en forme le contenu de la struct tm et stocker le résultat dans une chaîne de caractères. Voici la syntaxe de cette fonction.

À l'image de la zone mémoire dédiée aux struct tm (reportez-vous à la partie sur localtime()), la valeur renvoyée par asctime() est un pointeur vers une zone mémoire de 26 caractères partagée entre asctime() et ctime().

Code : C - Prototype de asctime()
1
char* asctime (const struct tm* instant);


Cette fonction prend donc un pointeur vers une struct tm en paramètre et retourne une chaîne (terminée par un retour à la ligne et un caractère 0) de caractères. La mise en forme obtenue est la suivante :

Jjj Mmm jm hh:mm:ss aaaa.


Dans l'ordre :
  • tm_wday, le jour de la semaine est exprimé en 3 lettres dans son nom anglais (ex : Lundi → Mon) ;
  • tm_mon, le nom du mois exprimé en 3 lettres dans son nom anglais (ex : Juin → Jun) ;
  • tm_mday, le jour du mois ;
  • tm_hour, l'heure ;
  • tm_min, les minutes ;
  • tm_sec, les secondes ;
  • tm_year, l'année.


Voyons voir ça !

Code : C - Exemple : Horloge
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t temps;
    struct tm date;

    time(&temps);
    date=*localtime(&temps);

    printf("%s\n", asctime(&date));

    return 0;
}


Donc après avoir donné la bonne valeur à temps, on remplit date via localtime() et on utilise dans printf() la fonction asctime() en lui envoyant notre structure date.

On obtient la date et l'heure écrite dans le format que j'ai indiqué plus haut.

Code : Console - Exemple de ce que donne asctime()
Sun Feb 27 21:39:40 2011


Exercice



Avec la fonction (ou la macro, comme vous préférez) attendre, créez une horloge ! Afin d'être la plus précise possible, votre horloge devra comporter une phase de synchronisation, boucle vide qui se répète tant que l'on n'est pas sûr que l'on est tout au début de la seconde.

ctime() : Transformer un time_t en char[]



Code : C - Prototype de ctime()
1
char* ctime (const time_t *temps);


ctime() est une version raccourcie de asctime(). Au lieu de lui donner une struct tm, on lui donne directement un time_t, ce qui fait gagner du temps. Pour un exemple plus concret :

Code : C - Deux instructions strictement identiques, mais différentes…
1
2
3
// Ces deux instructions donnent le même résultat.
asctime(localtime(&temps));
ctime(&temps);


La valeur renvoyée est un pointeur vers une zone mémoire qui est également utilisée par asctime(). Ces deux fonctions écraseront donc la chaîne contenue dans cet espace mémoire (à l'image des fonctions utilisant les struct tm).

Code : C - Exemple : Horloge simplifiée
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t temps;

    time(&temps);

    printf("%s\n", ctime(&temps));

    return 0;
}


Tout est du déjà vu, donc pas besoin de s'acharner là-dessus.

Le fonctionnement de ctime() fait en sorte que la zone mémoire destinée aux struct tm soit modifiée (reportez-vous à la partie sur localtime()).
Faites attention à cela car cette fonction écrasera le précédent contenu de la zone mémoire.


strftime() : Créer son propre format



Là ce sera plus dur : Nous allons toujours mettre en forme notre structure dans une chaîne de caractères, mais cette fois, nous allons créer notre propre format. En gros nous allons « créer » notre propre asctime().

Code : C - Prototype de strftime()
1
size_t strftime (char *variable, size_t taillemax, const char *format, const struct tm *date);


C'est du lourd ! En fait, cette fonction est comme un printf(). Ses paramètres sont :
  • la chaîne qui contiendra la mise en forme ;
  • la longueur maximale de la chaîne ;
  • la mise en forme ;
  • un pointeur vers la structure à utiliser.

Qu'est-ce qu'elle retourne ? La longueur de la mise en forme si elle ne dépasse pas la longueur maximale autorisée. Si la chaîne mise en forme dépasse la limite que vous autorisez, la fonction retourne 0.

Donc la variable sera contenue dans une chaîne, il serait déjà bien d'en allouer une. 48 caractères suffiront, à moins que vous ne souhaitiez mettre un roman en tant que mise en forme. Après, à l'image de printf(), les « % » servent à afficher des valeurs. Voici un tableau pour vous donner une petite idée.
Symbole Affichera Exemple
%A Nom du jour de la semaine. Monday
%a Nom du jour de la semaine en abrégé. Mon
%B Nom du mois. January
%b Nom du mois en abrégé. Jan
%c Représentation de la date et de l'heure classique. 02/27/11 22:05:45
%d Numéro du jour dans le mois. 29
%H Heure (0-24). 16
%I Heure (0-12). 4
%j Jour dans l'année. 342
%m Numéro du mois. 12
%M Minute. 51
%p Affiche « AM » le matin et « PM » l'après-midi (utile après un « %I »). PM
%S Secondes. 12
%U Numéro de la semaine dans l'année (dimanche = premier jour de la semaine). 53
%w Numéro du jour dans la semaine (dimanche = 0). 2
%W Numéro de la semaine dans l'année (lundi = premier jour de la semaine). 1
%x Affiche la date (format mm/jj/aa). 03/20/05
%X Affiche l'heure (format hh:mm:ss). 12:34:56
%Y L'année. 2005
%y Les deux derniers chiffres de l'année. 05
%Z Nom du fuseau horaire. Paris, Madrid
%% Affiche un « % ». %


Un gros morceau mais qui vous permettra un truc assez custom. Vous pourrez afficher le contenu de la chaîne obtenue avec un puts() :
Code : C - Pour afficher la valeur d'une chaîne
1
puts(format);


Allez, voici une horloge pour servir d'exemple :
Code : C - Exemple : Horloge personnalisée
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <time.h>

int main(void)
{
    char format[128];
    time_t temps;
    struct tm date;

    // On récupère la date et l'heure actuelles.
    time(&temps);
    date=*localtime(&temps);

    // On remplit la chaîne avec le format choisi, puis on l'affiche.
    strftime(format, 128, "%a %x\n%X %Z\n", &date);
    puts(format);

    return 0;
}


On stocke donc la mise en forme dans la chaîne « format » en accordant une longueur maximale de 128 caractères, puis l'écriture du format et l'adresse de « date » d'où seront tirées les informations.

Code : Console
Sun 02/27/11
22:24:32 Paris, Madrid


Grâce à cette fonction, vous serez capable de mettre en forme vos dates avec une bonne liberté !

Q.C.M.

Lequel de ces types ne concerne pas time.h ?
À quoi correspond un clock tick ?
Que fait ce code ?

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <time.h>

void attendre(float temps);

int main(void)
{
    attendre(5);
    puts("Ah ! vous etes la. Je ne vous avais pas entendu entrer.\n");

    return 0;
}

void attendre(float temps)
{
    clock_t fin=temps*1000+clock();
    while(clock()<fin);
}
Que fait la fonction struct tm* gmtime(const time_t *temps) ?
Pourquoi recommande t-on des calculs armés de clock() plutôt que difftime() pour les petites durées ?
Jusqu'à combien peut aller la valeur des secondes dans une struct tm ?

Statistiques de réponses au QCM

Vous savez maintenant comment gérer le temps dans vos programmes ! De nouvelles aventures vous attendent ! Datez vos sauvegardes et vos meilleurs scores ! Placez un chronomètre dans vos programmes pour forcer le joueur à se creuser les méninges pour trouver la solution à vos jeux ! Battez le record du plus long enfermement dans un carton ou faites un voyage Sydney-New York sans aucun problème ! Le temps n'a plus de secret pour vous !

Liens utilisés pour la rédaction du tutoriel :

Partager

13 commentaires pour "time.h et ses fonctions"
Note moyenne : 3.48 / 4 (23 votes)
Pseudo Commentaire
Hors ligne megacier # Posté le 23/10/2011 à 18:36:49
404 Non Trouvée
Avatar

mmmmh ça sent le http://www.cplusplus.com/reference/clibrary ...

J'écris aussi un tutoriel sur les bibliothèque en C/C++ ça t’intéresses?

Image utilisateur
Image utilisateur


JE VAIS TOUS VOUS CROQUER



C [||||||||||] ---> théorie finie_______________________C++ [||||||||||]---> fin de la première partie
 
Hors ligne megacier # Posté le 23/10/2011 à 21:15:57
404 Non Trouvée
Avatar

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<citation nom="Craki">int main(void)
{
    time_t secondes;
    struct tm instant;

    time(&secondes);
    instant=*localtime(&secondes);

    printf("%d/%d ; %d:%d:%d\n", instant.tm_mday+1, instant.tm_mon+1, instant.tm_hour, instant.tm_min, instant.tm_sec);
    return 0;
}</citation>




Pourquoi n'utilises-tu pas tu pas dans ta partie localtime()

Code : C
1
2
time(&secondes);
 instant=*localtime(&secondes);

avec toutes les autres variables à la place des +1?

Image utilisateur
Image utilisateur


JE VAIS TOUS VOUS CROQUER



C [||||||||||] ---> théorie finie_______________________C++ [||||||||||]---> fin de la première partie
 
Hors ligne comcomberto # Posté le 06/12/2011 à 01:19:21

Salut, très bon tuto mais je crois avoir repéré un problème dans le code pour trouver le numéro du jour dans l'année
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t temps;
    struct tm date;
    int remplir;

    // On demande à l'utilisateur de remplir les valeurs demandées
    // Ne pas oublier d'additionner ou soustraire les bonnes valeurs pour éviter les décalages
    puts("Annee ? ");
    scanf("%d", &remplir);
    date.tm_year=remplir-1900;

    puts("Mois ? ");
    scanf("%d", &remplir);
    date.tm_mon=remplir-1;

    puts("Jour ? ");
    scanf("%d", &remplir);
    date.tm_mday=remplir;

    // On s'assure que l'instant est bien placé à minuit
    date.tm_hour=0;
    date.tm_min=0;
    date.tm_sec=0;

    temps=mktime(&date);

    printf("C'est le %deme jour de l'annee !\nEt minuit est la %deme seconde depuis le 1er janvier 1970.\n", date.tm_yday, (int) temps);

    return 0;
}

en effet, lorsque l'on execute ce code, il nous donne un numero de jour erroné, qui est décalé de 2 jours !
en testant pour des valeurs simples à calculer, on s'en aperçoit tout de suite !
j'ai du coup modifié le code en mettant Code : C
1
date.tm_yday + 2
à la place de Code : C
1
date.tm_yday
mais quelqu'un peut-il m'expliquer pourquoi il y a ce décalage et suis-je le seul à l'avoir ?
merci et bonne soirée !
Connecté informaticienzero # Posté le 02/05/2012 à 12:59:22
City Hunter
Avatar

Citation : Tutoriel
Code : C
1
2
3
4
5
6
7
#if defined (WIN32) || defined (WIN64)
#include <windows.h>
#define ATTENDRE(temps) Sleep(temps*1000)
#else
#include <unistd.h>
#define ATTENDRE(temps) sleep(temps)
#endif


Ce code ne marche pas chez moi. Pour Windows, c'est __WIN32__ et __WIN64__.

Image utilisateur Aidez ce chat à conquérir le monde, mettez-le dans votre signature.

Vous voulez apprendre à programmer mais vous ne savez pas par où commencer ?

90% of teens today would die if Facebook was completely destroyed. If you are one of the 10% that would be laughing, copy and paste this to your signature.
 
Hors ligne lionceau87 # Posté le 05/05/2012 à 21:45:43
Avatar

Avis : Très bon

Études : 3iL

Rien à dire.
Merci beaucoup , c'est très claire et rigoureux.

Voir tous les commentaires
Ce tutoriel a été corrigé par les zCorrecteurs.