#pragma once #include #include #include #include #include #include #include #include #include #include "../external/dateChronoRepo/chrono_io.h" #include "../external/dateChronoRepo/date.h" #include "../external/dateChronoRepo/tz.h" #include "NetMessengerStreamBuffer.h" //For usage examples, see AftrUtil_time_test.cpp, but pretty much do this: //std::string str_utc = Aftr::toStringUTC( std::chrono::utc_clock::now() ); //auto utc_time_point = Aftr::fromStringUTC( str_utc ); //To Run GTEST vs std::chrono and std::format, set this to directive to 0 //I had to put this in here because GCC 13.1 doesn't support std::format on a UTC chrono yet //and sadly, lib fmt doesn't match the expected standard's output for std::format. So //I am using Howard Hinnant's date library to do the formatted which matches the ISO SPEC #define _SLN_ONLY_USE_HOWARD_HINNANTS_DATE_LIB_FOR_UTC_PARSE_AND_FORMAT 1 namespace Aftr { //Common helpful functions to using std::chrono, outputting it to a string and vice-versa. //When passed as the format string a time_point will be converted to a string of the format: //"2023.Apr.18_15.01.14.2104535.UTC" // This is also a valid filename, too! constexpr char const* DATE_TIME_FMT_STR{ "{0:%Y.%b.%d_%H.%M.%S.%Z}" }; //Must use this in std::format constexpr char const* DATE_TIME_FMT_STR_FROM_STREAM{ "%Y.%b.%d_%H.%M.%S.%Z" }; //use in std::chrono::from_stream template< typename CLOCK_TYPE > std::string toStringUTC_impl_date_hinnant( std::chrono::time_point tp ) { //SLN written using Howard Hinnant's Date library since GCC 13.1 still doesn't support std::format and fmt::format doesn't match std::format! auto sys_tp = std::chrono::clock_cast(tp); auto str = date::format( DATE_TIME_FMT_STR_FROM_STREAM, sys_tp ); //date::format needs a sys_clock as input return str; } /// Sample usage: /// auto myStr = Aftr::toString( std::chrono::system_clock::now() ); /// now, myStr == ""2023.Apr.18_15.01.14.2104535.UTC"" /// This simplies calls return std::format( DATE_TIME_FMT_STR, tp ); template< typename CLOCK_TYPE > std::string toStringUTC( std::chrono::time_point tp ) { #ifdef _SLN_ONLY_USE_HOWARD_HINNANTS_DATE_LIB_FOR_UTC_PARSE_AND_FORMAT return toStringUTC_impl_date_hinnant( tp ); #else return std::format( DATE_TIME_FMT_STR, tp ); #endif } //Expects time is in format specified by: DATE_TIME_FMT_STR_FROM_STREAM //ie, "2023.Apr.18_15.01.14.2104535.UTC" //Example Usage: //std::chrono::utc_clock time = Aftr::fromStringUTC( utc_time_as_str ); template< typename CLOCK_TYPE > std::chrono::time_point fromStringUTC( std::string const& str_with_date_time ) { #ifdef _SLN_ONLY_USE_HOWARD_HINNANTS_DATE_LIB_FOR_UTC_PARSE_AND_FORMAT return fromStringUTC_impl_date_hinnant(str_with_date_time); #else std::chrono::time_point tPoint; std::istringstream ss{ str_with_date_time }; std::chrono::from_stream( ss, Aftr::DATE_TIME_FMT_STR_FROM_STREAM, tPoint ); return tPoint; #endif } template< typename CLOCK_TYPE > std::chrono::time_point fromStringUTC_impl_date_hinnant( std::string const& str_with_date_time ) { //SLN written using Howard Hinnant's Date library since GCC 13.1 still doesn't support std::format and fmt::format doesn't match std::format! std::chrono::time_point< std::chrono::system_clock > tp; std::istringstream in{ str_with_date_time }; date::from_stream( in, DATE_TIME_FMT_STR_FROM_STREAM, tp ); auto tPoint = std::chrono::clock_cast(tp); return tPoint; } template< typename CLOCK_TYPE > std::chrono::time_point fromStringUTC_impl_date_hinnant( std::istream& is ) { //SLN written using Howard Hinnant's Date library since GCC 13.1 still doesn't support std::format and fmt::format doesn't match std::format! std::string s; is >> s; //sln for some reason, using from_stream on istream only works every other time, but istringstream works everytime. std::istringstream ss{ s }; //sln for //https://github.com/microsoft/STL/issues/1952 std::chrono::time_point< std::chrono::system_clock > tp; date::from_stream( ss, Aftr::DATE_TIME_FMT_STR_FROM_STREAM, tp ); auto tPoint = std::chrono::clock_cast(tp); return tPoint; } //expects time is in format specified by: DATE_TIME_FMT_STR_FROM_STREAM //ie, "2023.Apr.18_15.01.14.2104535.UTC" //Example usage: //std::string utc_time_as_str; //is >> utc_time_as_str; //assume is is an input stream containing the time as a string with no spaces "2023.Apr.18_15.01.14.2104535.UTC" //datum.time = Aftr::fromStringUTC( utc_time_as_str ); template< typename CLOCK_TYPE > std::chrono::time_point fromStringUTC( std::istream& is ) { #ifdef _SLN_ONLY_USE_HOWARD_HINNANTS_DATE_LIB_FOR_UTC_PARSE_AND_FORMAT return fromStringUTC_impl_date_hinnant( is ); #else std::chrono::time_point tPoint; std::string s; is >> s; //sln for some reason, using from_stream on istream only works every other time, but istringstream works everytime. std::istringstream ss{ s }; //sln for //https://github.com/microsoft/STL/issues/1952 std::chrono::from_stream( ss, Aftr::DATE_TIME_FMT_STR_FROM_STREAM, tPoint ); return tPoint; #endif } template< typename CLOCK_TYPE > std::chrono::time_point fromStringUTC_impl_date_hinnant( Aftr::NetMessengerStreamBuffer& is ) { //SLN written using Howard Hinnant's Date library since GCC 13.1 still doesn't support std::format and fmt::format doesn't match std::format! std::string s; is >> s; std::istringstream ss{ s }; std::chrono::time_point tp; date::from_stream( ss, Aftr::DATE_TIME_FMT_STR_FROM_STREAM, tp ); auto tPoint = std::chrono::clock_cast(tp); return tPoint; } template< typename CLOCK_TYPE > std::chrono::time_point fromStringUTC( Aftr::NetMessengerStreamBuffer& is ) { #ifdef _SLN_ONLY_USE_HOWARD_HINNANTS_DATE_LIB_FOR_UTC_PARSE_AND_FORMAT return fromStringUTC_impl_date_hinnant( is ); #else std::chrono::time_point tPoint; std::string s; is >> s; std::istringstream ss{ s }; std::chrono::from_stream( ss, Aftr::DATE_TIME_FMT_STR_FROM_STREAM, tPoint ); return tPoint; #endif } } //namespace Aftr