2016-04-08 2 views
9

Fait amusant que je suis sûr que la plupart d'entre nous qui jouons dans les royaumes de temps savent - il y a des dates/heures qui peuvent apparaître valides mais qui n'existent pas, par ex. 02h30 sur une heure de changement d'heure d'été.Existe-t-il un moyen de déterminer si une date/heure n'existe pas?

Existe-t-il un moyen en C++ (standard ou Windows) de déterminer si une date/heure donnée est valide dans une spécification de fuseau horaire donnée?

+0

Une question intrigante, certainement. Devez-vous également soutenir les deuxièmes jours intercalaires, comme le 30 juin 2015, 23 h 59,60? (Si c'est le cas, cela exclut l'API de temps de Google) I * think * booster les bibliothèques date-heure serait le meilleur point de départ.J'utilise ces librairies mais pas pour cette chose en particulier. – Bathsheba

+0

J'ai tagué "boost-date-time" et, peut-être vilainement, "boost" car j'imagine qu'une solution peut être soit disponible hors de la boîte pour cela, soit pas particulièrement difficile à implémenter dans ce cadre. – Bathsheba

+0

La bibliothèque C++ standard ne gère pas le temps. Si vous ciblez Windows, vous pouvez utiliser SystemTimeToFileTime() ou SystemTimeToTzSpecificLocalTime(). Passer une date incorrecte fait échouer la fonction avec ERROR_INVALID_PARAMETER. Si cela doit être multiplateforme, alors vous devez aller faire du shopping pour une bibliothèque. –

Répondre

0

Le format time_t est une valeur entière (secondes depuis le 1/1/1970 00:00 UTC) de sorte que toutes les valeurs possibles de time_t existent (dans les limites du type entier utilisé bien sûr). Par contre, toutes les valeurs possibles de «struct tm» (où vous avez des membres pour le jour, le mois, l'année, l'heure, la minute et la seconde) n'existent pas (et c'est probablement ce que vous voulez dire). Pour vérifier si un "struct tm" existe, vous devez effectuer les opérations suivantes:

  • Définissez le membre tm_isdst sur -1. Cela indique que vous ne savez pas si son heure d'été ou pas.
    • Convertissez "struct tm" en time_t en utilisant mktime().
    • Convertissez time_t en "struct tm" en utilisant localtime().
    • Comparez le "struct tm" résultant avec le "struct tm" initial, ignorez le champ tm_isdst (ou utilisez-le pour voir si vous êtes en DST ou non).
+0

Que fait 'mktime' si vous fournissez une valeur à 02:30 en revenant à l'heure normale? Le problème ici est que l'heure du calendrier serait répéter l'heure 02: xx deux fois (une fois avec dst et une fois sans). Si vous ne savez pas ce que vous voulez dire, l'ordinateur ne peut probablement pas vous dire non plus ... – skyking

+0

La norme n'exige pas que 'time_t' soit un nombre entier, mais sinon il semble que la norme impliquerait que votre solution fonctionne . Si ça va vraiment marcher sur l'implémentation, c'est une autre question ... – skyking

+1

@Skyking: tu as raison (en partie). Lorsque l'horloge est en retrait pendant une heure (DST -> non-DST), et vous ne spécifiez pas si vous êtes en heure d'été ou non, le CRT va deviner, mais au moins j'espère qu'il retournera 2: 30 DST ou 2:30 non-DST. Quoi qu'il en soit, la meilleure façon de le tester est de l'essayer. Le résultat pourrait en effet dépendre de la mise en œuvre du CRT. – Patrick

1

En utilisant cette free, open-source library:

#include "tz.h" 
#include <iostream> 

int 
main() 
{ 
    using namespace date; 
    using namespace std::chrono_literals; 
    try 
    { 
     auto zone = locate_zone("America/New_York"); 
     zone->to_sys(local_days{mar/13/2016} + 2h + 30min); 
    } 
    catch (const std::exception& e) 
    { 
     std::cout << e.what() << '\n'; 
    } 
} 

La sortie de ce programme est:

2016-03-13 02:30 is in a gap between 
2016-03-13 02:00:00 EST and 
2016-03-13 03:00:00 EDT which are both equivalent to 
2016-03-13 07:00:00 UTC 

En bref, ce programme tente de traduire une date locale/heure de 2016- 03-13 02:30:00 à UTC en utilisant le fuseau horaire "America/New_York". La traduction émet une exception car l'heure locale n'existe pas. Une exception est également émise (avec un message d'erreur différent), si l'heure locale est ambiguë, par exemple lors du réglage de l'heure locale à partir de l'heure d'été.

La bibliothèque fournit également une syntaxe permettant d'éviter ces exceptions si tel est le souhait.

Cela fonctionne sur VS-2013, VS-2015, clang et gcc. Il nécessite C++ 11, C++ 14 ou C++ 1z.

Le lien ci-dessus pointe vers la documentation. Voici le dépôt GitHub:

https://github.com/HowardHinnant/date

0

Utilisation des fonctions spécifiques à Windows, vous pouvez faire a call toTzSpecificLocalTimeToSystemTime() suivi par a call toSystemTimeToTzSpecificLocalTime() avec le fuseau horaire pertinent. À la fin, si les deux diffèrent vous avez une heure non valide que TzSpecificLocalTimeToSystemTime convertit l'heure invalide en un temps "réel".

bool IsValidTime(TIME_ZONE_INFORMATION tz, SYSTEMTIME st) 
{ 
    SYSTEMTIME utcSystemTime, st2; 
    TzSpecificLocalTimeToSystemTime(&tz, &st, &utcSystemTime); 
    SystemTimeToTzSpecificLocalTime(&tz, &utcSystemTime, &st2); 

    return (st != st2); 
}