Accueil > .Net, C#, Divers > De l’importance d’une bonne gestion des temps

De l’importance d’une bonne gestion des temps

Horloge astronomique de Prague @flickr

Horloge astronomique de Prague

Aujourd’hui, on va se pencher un peu sur la gestion des dates et de petits problèmes qui peuvent apparaître.

Alors je ne vais pas réexpliquer les évidences, mais plutôt donner quelques informations que je trouve utiles et qui ne sont parfois pas trop prises en compte (du moins pas avant le drame prévisible).

En effet, cela peut paraître stupide, mais il y a certains cas où les dates et temps ont leur importance.

Et dans le monde, à un instant T, il n’est pas la même heure partout.

 

Plantons le décor

 

Dans le monde, il existe 40 fuseaux horaires (timezones par pays).
Dans un même fuseau horaire, l’heure doit être identique, mais elle varie lorsque l’on change de fuseau horaire.

Il y a encore peu (en 1972), c’était l’heure GMT (Greenwich Mean Time, heure moyenne de Greenwich) qui était le référent, représentant l’heure solaire moyenne.

Depuis 1972, le référent dans la majeure partie du globe est le temps UTC (Coordinated Universal Time, Temps universel coordonné).

Pour en revenir aux fuseaux horaires, ils vont de UTC-12 à UTC+14. On retrouve également le « daylight saving time » (heure d’été) qui complique encore un peu la donne et qui pose chaque année son lot de problèmes.

Enfin, le 30 juin 2012, il y a eu une seconde intercalaire, à 23:59:60.
Avec tous les problèmes que cela a occasionnés (une recherche sur internet donnera son lot d’articles, donc je ne m’étends pas).

Donc, avec tout cela, on peut comprendre que la gestion des dates et surtout des temps soit un peu…complexe.

Je vous conseille donc la lecture des articles Wikipédia mentionnés pour plus d’informations (n’étant pas le sujet ici).

 

La problématique – mise en situation

 

Le problème des dates est souvent assez peu abordé, alors que parfois les applications sont internationales.
Donc, deux petits exemples triviaux du problème.

Dans une entreprise A, il existe un workflow pour la création d’une transaction, en trois étapes : proposition de la transaction à une autre entité, acceptation de la transaction par cette entité, validation par une troisième. Rien de bien complexe.
On se place dans un contexte purement franco-français. A Mayotte, un utilisateur créé une transaction avant de partir pour la plage, il est 17h pour lui (exemple fictif, hein ^^). La transaction se fait avec Fort-de-France en Martinique, qui l’accepte à 10h. Enfin, Paris valide la transaction à 16h.
Si la gestion des dates se fait toujours en local, on a donc :
Etape 1 : 17h
Etape 2 : 10h
Etape 3 : 16h
Le même jour.
Pour n’importe qu’elle personne voyant ça, mettons un administrateur qui vérifie les données…et bien, ça ne parait pas bon du tout.
A raison, mais pas pour celle qui semble évidente.

Autre exemple.
Une entreprise B gère plusieurs succursales dans le monde, mais le marketnig est centralisé en France (oui, je sais, peu crédible ^^) via un CMS maison. Mettons qu’un marketeux poste une news à 15h. A New York, pour le client qui voit la news, il sera 9h. Donc, la news sera postée…dans le futur. Coucou Marty !

Vous voyez le problème ? Les exemples sont triviaux, mais c’est l’idée qui compte.
Le problème se pose également lorsque l’on échange des données avec des entreprises dans différents fuseaux horaires.

Donc, que faire ?

 

Résolution

 

Quand j’ai planté le décor, j’ai parlé de l’UTC.
Et c’est bien ça la solution : toujours stocker une date au format UTC.
Si on connait pertinemment son fuseau horaire, il sera possible de la convertir sans difficulté.

Dans les bases de données, il est possible de stocker des dates, avec l’indicateur de fuseau horaire, mais est-ce réellement pertinent ?
Je ne crois pas.
Cela oblige à réaliser des conversions dans le code dès que l’utilisateur n’est pas dans la bonne zone (et éventuellement dans des procédures stockées, où l’information n’est pas forcément accessible).

Du coup, autant partir du postulat que la date est au format UTC et la convertir en locale. C’est simple, direct et on ne se pose plus de question.
Et s’il y a besoin d’ordonner les dates directement dans une procédure stockée, eh bien ce sera quand même nettement plus simple.

 

Et en .Net ?

 
Dans le Framework .Net, il y a bien évidemment la structure DateTime, que tout le monde connait.

Pour l’implémentation, on a, entre autres (via ILSpy) :

public static readonly DateTime MaxValue = new DateTime(3155378975999999999L, DateTimeKind.Unspecified);

public static readonly DateTime MinValue = new DateTime(0L, DateTimeKind.Unspecified);

public static DateTime UtcNow
{
    get
    {
        long systemTimeAsFileTime = DateTime.GetSystemTimeAsFileTime();
        return new DateTime((ulong)(systemTimeAsFileTime + 504911232000000000L | 4611686018427387904L));
    }
}

public static DateTime Now
{
    get
    {
        DateTime utcNow = DateTime.UtcNow;
        bool isAmbiguousDst = false;
        long ticks = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utcNow, out isAmbiguousDst).Ticks;
        long num = utcNow.Ticks + ticks;
        if (num > 3155378975999999999L)
        {
            return new DateTime(3155378975999999999L, DateTimeKind.Local);
        }
        if (num < 0L)
        {
            return new DateTime(0L, DateTimeKind.Local);
        }
        return new DateTime(num, DateTimeKind.Local, isAmbiguousDst);
    }
}

Et oui, c’est toujours bon à savoir : DateTime.Now utilise DateTime.UtcNow avant de le convertir en temps local.
Argument supplémentaire pour utiliser les dates UTC en priorité.

Ensuite, il y a, comme vu dans la propriété .Now, la classe TimeZoneInfo.

C’est cette classe qui va permettre de gérer les changements de fuseaux horaires.
Il y en a 104 au total :

ReadOnlyCollection<TimeZoneInfo> timezones = TimeZoneInfo.GetSystemTimeZones();
foreach(TimeZoneInfo tzi in timezones)
	Console.WriteLine("{0} - {1}", tzi.DisplayName, tzi.Id);

 
Et puis, petite info pour MongoDB (parce que je l’aime bien ^^).
Il est possible de spécifier le type de date lors de la sérialisation (code tiré de l’exemple) :

public class MyClass {
    [BsonDateTimeOptions(DateOnly = true)]
    public DateTime DateOfBirth { get; set; }
    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
    public DateTime AppointmentTime { get; set; }
}

 
Voilà, j’espère que les informations de ce billet vous serons utiles et pas forcément que pour le code.

Catégories :.Net, C#, Divers
  1. Aucun commentaire pour l’instant.
  1. No trackbacks yet.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :