2016-03-23 1 views
2

Ive a écrit la fonction suivante qui reçoit un point de temps et retourner une chaîne ISO avec millisecondes:localtime_s et la construction d'utilisation strftime chaîne de temps ISO

std::string TimePointToISOString(const std::chrono::time_point<std::chrono::system_clock>& time) 
    { 
     std::time_t rawTime = std::chrono::system_clock::to_time_t(time); 
     struct tm timeinfo; 
     localtime_s(&timeinfo, &rawTime); 

     std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(time.time_since_epoch()); 
     std::size_t frac_seconds = ms.count() % 1000; 

     char buffer[32]; 
     std::strftime(buffer, 32, "%FT%TZ", &timeinfo); 

     std::string bufferStr(buffer); 
     std::stringstream ss; 
     ss << bufferStr.substr(0, 19) << "." << std::setw(3) << std::setfill ('0') << frac_seconds << bufferStr.substr(20); 

     return ss.str(); 
    } 

Ive utilisé pour exécuter que sur Linux avec le localtime() fonctionne sans problèmes du tout. Maintenant, je migre vers Windows/VS2012 et le compilateur suggère de changer localtime() pour un localtime_s() plus sûr, fait immédiatement.

Après la conversion de l'appel strftime ne se bloque lors de l'exécution avec l'erreur suivante:

Expression: ("Invalid format directive", 0) 

compilation fonctionne très bien. Aide appréciée pour savoir ce qui se passe ici. Je devine quelque chose de simple que je ne peux pas remarquer ...

Répondre

4

Les conversions %F et %T ont été ajoutées dans C99, et VS 2012 ne supporte que C89. Bien qu'il n'essaie toujours pas de prendre en charge tout le C99, je crois que VS 2015 ajoute suffisamment (en particulier les fonctions de bibliothèque C99, qui font également partie de C++ 11) que cela devrait fonctionner correctement.

Si vous devez continuer à utiliser l'ancien compilateur/bibliothèque,% F et% T sont tous les deux des "raccourcis" pour certains formats déjà pris en charge dans C89. Si je lis les exigences correctement, ce qui suit devrait être équivalent:

std::strftime(buffer, 32, "%Y-%m-%dT%H:%M:%SZ", &timeinfo); 

En aparté, si votre compilateur prend en charge 11 C++, il est généralement plus facile et plus propre à utiliser std::put_time au lieu de strftime.

+0

Jerry, essayé 'ss Ive << std :: put_time (& timeinfo, "% FT% TZ") ; 'sans succès aussi ... Même erreur ... Seens que'% FT' et '% TZ' ne sont pas supportés du tout dans VS2012.Donc j'ai changé pour '"% Y-% m-% dT% H:% M:% SZ "et travaille avec' strftime' ET std :: put_time. Merci pour ton aide. – Mendes

+0

@Mendes: Oui, je suppose que 'put_time' est un peu plus qu'un wrapper autour de' strftime' (ou les deux utilisent le même moteur), donc pour un compilateur donné, les deux sont susceptibles de supporter les mêmes conversions-- La commutation entre eux est purement une question de commodité, pas susceptible d'affecter votre question initiale. –

2

Ceci est une bonne question (mise à jour). Et la réponse de Jerry Coffin est une bonne réponse (également mise à jour). Cette réponse consiste à ajouter d'autres informations sur une autre solution open-source connue pour fonctionner sur VS-2013 et versions ultérieures, gcc et clang. Cette alternative produira sortie identique à TimePointToISOString. Afin de faire la différence, je lui ai donné un autre nom: to_local_string:

std::string 
to_local_string(const std::chrono::system_clock::time_point& time) 
{ 
    using namespace date; 

    auto zone = current_zone(); 
    auto local = floor<std::chrono::milliseconds>(zone->to_local(time).first); 
    auto dp = floor<days>(local); 
    year_month_day ymd = dp; 
    std::stringstream ss; 
    ss << ymd << 'T' << make_time(local-dp); 
    return ss.str(); 
} 

Il utilise l'analyseur de base de données de fuseau horaire trouvé ici:

https://github.com/HowardHinnant/date

et documenté ici:

http://howardhinnant.github.io/tz.html

Ceci est un analyseur du IANA Timezone database, et est utilisé ici simplement trouver le décalage UTC pour le fuseau horaire local. Une fois le time_point local trouvé (stocké comme std::chrono::system_clock::time_point), il est décomposé en types de champs année/mois/jour/heure/minute/seconde/milliseconde en utilisant this library dont l'implémentation se trouve sur le même site github.

Je viens de rencontrer à la fois TimePointToISOString et to_local_string sur la même time_point et la sortie était:

2016-03-23T22:54:52.626 
2016-03-23T22:54:52.626