1081ebf06SWludzik, Jozef #pragma once 2081ebf06SWludzik, Jozef 34dbb8aeaSWludzik, Jozef #include "logging.hpp" 44dbb8aeaSWludzik, Jozef 5c2e32007SEd Tanous #include <boost/date_time.hpp> 6c2e32007SEd Tanous 79ea15c35SEd Tanous #include <algorithm> 84dbb8aeaSWludzik, Jozef #include <charconv> 9081ebf06SWludzik, Jozef #include <chrono> 109ea15c35SEd Tanous #include <cstddef> 11d5c80ad9SNan Zhou #include <cstdint> 124dbb8aeaSWludzik, Jozef #include <optional> 139ea15c35SEd Tanous #include <ratio> 14081ebf06SWludzik, Jozef #include <string> 159ea15c35SEd Tanous #include <string_view> 16081ebf06SWludzik, Jozef 17d5c80ad9SNan Zhou // IWYU pragma: no_include <stddef.h> 18d5c80ad9SNan Zhou // IWYU pragma: no_include <stdint.h> 19d5c80ad9SNan Zhou 20081ebf06SWludzik, Jozef namespace redfish 21081ebf06SWludzik, Jozef { 22081ebf06SWludzik, Jozef 23081ebf06SWludzik, Jozef namespace time_utils 24081ebf06SWludzik, Jozef { 25081ebf06SWludzik, Jozef 26081ebf06SWludzik, Jozef namespace details 27081ebf06SWludzik, Jozef { 28081ebf06SWludzik, Jozef 297be4c8adSEd Tanous // Creates a string from an integer in the most efficient way possible without 307be4c8adSEd Tanous // using std::locale. Adds an exact zero pad based on the pad input parameter. 317be4c8adSEd Tanous // Does not handle negative numbers. 327be4c8adSEd Tanous inline std::string padZeros(int64_t value, size_t pad) 33081ebf06SWludzik, Jozef { 347be4c8adSEd Tanous std::string result(pad, '0'); 357be4c8adSEd Tanous for (int64_t val = value; pad > 0; pad--) 36081ebf06SWludzik, Jozef { 377be4c8adSEd Tanous result[pad - 1] = static_cast<char>('0' + val % 10); 387be4c8adSEd Tanous val /= 10; 39081ebf06SWludzik, Jozef } 407be4c8adSEd Tanous return result; 41081ebf06SWludzik, Jozef } 424dbb8aeaSWludzik, Jozef 43081ebf06SWludzik, Jozef } // namespace details 44081ebf06SWludzik, Jozef 45081ebf06SWludzik, Jozef /** 464dbb8aeaSWludzik, Jozef * @brief Convert string that represents value in Duration Format to its numeric 474dbb8aeaSWludzik, Jozef * equivalent. 484dbb8aeaSWludzik, Jozef */ 494f48d5f6SEd Tanous inline std::optional<std::chrono::milliseconds> 50*1249e9cbSEd Tanous fromDurationString(std::string_view v) 514dbb8aeaSWludzik, Jozef { 524dbb8aeaSWludzik, Jozef std::chrono::milliseconds out = std::chrono::milliseconds::zero(); 53*1249e9cbSEd Tanous enum class ProcessingStage 544dbb8aeaSWludzik, Jozef { 55*1249e9cbSEd Tanous // P1DT1H1M1.100S 56*1249e9cbSEd Tanous P, 57*1249e9cbSEd Tanous Days, 58*1249e9cbSEd Tanous T, 59*1249e9cbSEd Tanous Hours, 60*1249e9cbSEd Tanous Minutes, 61*1249e9cbSEd Tanous Seconds, 62*1249e9cbSEd Tanous Milliseconds, 63*1249e9cbSEd Tanous Done, 64*1249e9cbSEd Tanous }; 65*1249e9cbSEd Tanous ProcessingStage stage = ProcessingStage::P; 66*1249e9cbSEd Tanous 67*1249e9cbSEd Tanous while (!v.empty()) 68*1249e9cbSEd Tanous { 69*1249e9cbSEd Tanous if (stage == ProcessingStage::P) 70*1249e9cbSEd Tanous { 714dbb8aeaSWludzik, Jozef if (v.front() != 'P') 724dbb8aeaSWludzik, Jozef { 734dbb8aeaSWludzik, Jozef return std::nullopt; 744dbb8aeaSWludzik, Jozef } 754dbb8aeaSWludzik, Jozef v.remove_prefix(1); 76*1249e9cbSEd Tanous stage = ProcessingStage::Days; 77*1249e9cbSEd Tanous continue; 78*1249e9cbSEd Tanous } 79*1249e9cbSEd Tanous if (stage == ProcessingStage::Days || stage == ProcessingStage::T) 804dbb8aeaSWludzik, Jozef { 81*1249e9cbSEd Tanous if (v.front() == 'T') 82*1249e9cbSEd Tanous { 83*1249e9cbSEd Tanous if (stage == ProcessingStage::T) 84*1249e9cbSEd Tanous { 854dbb8aeaSWludzik, Jozef return std::nullopt; 864dbb8aeaSWludzik, Jozef } 874dbb8aeaSWludzik, Jozef v.remove_prefix(1); 88*1249e9cbSEd Tanous stage = ProcessingStage::Hours; 89*1249e9cbSEd Tanous continue; 90*1249e9cbSEd Tanous } 91*1249e9cbSEd Tanous } 92*1249e9cbSEd Tanous uint64_t ticks = 0; 93*1249e9cbSEd Tanous auto [ptr, ec] = std::from_chars(v.begin(), v.end(), ticks); 94*1249e9cbSEd Tanous if (ec != std::errc()) 954dbb8aeaSWludzik, Jozef { 96*1249e9cbSEd Tanous BMCWEB_LOG_ERROR << "Failed to convert string \"" << v 97*1249e9cbSEd Tanous << "\" to decimal"; 98*1249e9cbSEd Tanous return std::nullopt; 99*1249e9cbSEd Tanous } 100*1249e9cbSEd Tanous size_t charactersRead = static_cast<size_t>(ptr - v.data()); 101*1249e9cbSEd Tanous if (ptr >= v.end()) 102*1249e9cbSEd Tanous { 103*1249e9cbSEd Tanous BMCWEB_LOG_ERROR << "Missing postfix"; 104*1249e9cbSEd Tanous return std::nullopt; 105*1249e9cbSEd Tanous } 106*1249e9cbSEd Tanous if (*ptr == 'D') 107*1249e9cbSEd Tanous { 108*1249e9cbSEd Tanous if (stage > ProcessingStage::Days) 109*1249e9cbSEd Tanous { 110*1249e9cbSEd Tanous return std::nullopt; 111*1249e9cbSEd Tanous } 112*1249e9cbSEd Tanous out += std::chrono::days(ticks); 113*1249e9cbSEd Tanous } 114*1249e9cbSEd Tanous else if (*ptr == 'H') 115*1249e9cbSEd Tanous { 116*1249e9cbSEd Tanous if (stage > ProcessingStage::Hours) 117*1249e9cbSEd Tanous { 118*1249e9cbSEd Tanous return std::nullopt; 119*1249e9cbSEd Tanous } 120*1249e9cbSEd Tanous out += std::chrono::hours(ticks); 121*1249e9cbSEd Tanous } 122*1249e9cbSEd Tanous else if (*ptr == 'M') 123*1249e9cbSEd Tanous { 124*1249e9cbSEd Tanous if (stage > ProcessingStage::Minutes) 125*1249e9cbSEd Tanous { 126*1249e9cbSEd Tanous return std::nullopt; 127*1249e9cbSEd Tanous } 128*1249e9cbSEd Tanous out += std::chrono::minutes(ticks); 129*1249e9cbSEd Tanous } 130*1249e9cbSEd Tanous else if (*ptr == '.') 131*1249e9cbSEd Tanous { 132*1249e9cbSEd Tanous if (stage > ProcessingStage::Seconds) 133*1249e9cbSEd Tanous { 134*1249e9cbSEd Tanous return std::nullopt; 135*1249e9cbSEd Tanous } 136*1249e9cbSEd Tanous out += std::chrono::seconds(ticks); 137*1249e9cbSEd Tanous stage = ProcessingStage::Milliseconds; 138*1249e9cbSEd Tanous } 139*1249e9cbSEd Tanous else if (*ptr == 'S') 140*1249e9cbSEd Tanous { 141*1249e9cbSEd Tanous // We could be seeing seconds for the first time, (as is the case in 142*1249e9cbSEd Tanous // 1S) or for the second time (in the case of 1.1S). 143*1249e9cbSEd Tanous if (stage <= ProcessingStage::Seconds) 144*1249e9cbSEd Tanous { 145*1249e9cbSEd Tanous out += std::chrono::seconds(ticks); 146*1249e9cbSEd Tanous stage = ProcessingStage::Milliseconds; 147*1249e9cbSEd Tanous } 148*1249e9cbSEd Tanous else if (stage > ProcessingStage::Milliseconds) 149*1249e9cbSEd Tanous { 150*1249e9cbSEd Tanous BMCWEB_LOG_ERROR 151*1249e9cbSEd Tanous << "Got unexpected information at end of parse"; 152*1249e9cbSEd Tanous return std::nullopt; 153*1249e9cbSEd Tanous } 154*1249e9cbSEd Tanous else 155*1249e9cbSEd Tanous { 156*1249e9cbSEd Tanous // Seconds could be any form of (1S, 1.1S, 1.11S, 1.111S); 157*1249e9cbSEd Tanous // Handle them all milliseconds are after the decimal point, 158*1249e9cbSEd Tanous // so they need right padded. 159*1249e9cbSEd Tanous if (charactersRead == 1) 160*1249e9cbSEd Tanous { 161*1249e9cbSEd Tanous ticks *= 100; 162*1249e9cbSEd Tanous } 163*1249e9cbSEd Tanous else if (charactersRead == 2) 164*1249e9cbSEd Tanous { 165*1249e9cbSEd Tanous ticks *= 10; 166*1249e9cbSEd Tanous } 167*1249e9cbSEd Tanous out += std::chrono::milliseconds(ticks); 168*1249e9cbSEd Tanous stage = ProcessingStage::Milliseconds; 169*1249e9cbSEd Tanous } 170*1249e9cbSEd Tanous } 171*1249e9cbSEd Tanous else 172*1249e9cbSEd Tanous { 173*1249e9cbSEd Tanous BMCWEB_LOG_ERROR << "Unknown postfix " << *ptr; 1744dbb8aeaSWludzik, Jozef return std::nullopt; 1754dbb8aeaSWludzik, Jozef } 1764dbb8aeaSWludzik, Jozef 177*1249e9cbSEd Tanous v.remove_prefix(charactersRead + 1U); 1784dbb8aeaSWludzik, Jozef } 1794dbb8aeaSWludzik, Jozef return out; 1804dbb8aeaSWludzik, Jozef } 1814dbb8aeaSWludzik, Jozef 1824dbb8aeaSWludzik, Jozef /** 183081ebf06SWludzik, Jozef * @brief Convert time value into duration format that is based on ISO 8601. 184081ebf06SWludzik, Jozef * Example output: "P12DT1M5.5S" 185081ebf06SWludzik, Jozef * Ref: Redfish Specification, Section 9.4.4. Duration values 186081ebf06SWludzik, Jozef */ 187b00dcc27SEd Tanous inline std::string toDurationString(std::chrono::milliseconds ms) 188081ebf06SWludzik, Jozef { 189081ebf06SWludzik, Jozef if (ms < std::chrono::milliseconds::zero()) 190081ebf06SWludzik, Jozef { 191081ebf06SWludzik, Jozef return ""; 192081ebf06SWludzik, Jozef } 193081ebf06SWludzik, Jozef 194081ebf06SWludzik, Jozef std::string fmt; 195081ebf06SWludzik, Jozef fmt.reserve(sizeof("PxxxxxxxxxxxxDTxxHxxMxx.xxxxxxS")); 196081ebf06SWludzik, Jozef 197*1249e9cbSEd Tanous std::chrono::days days = std::chrono::floor<std::chrono::days>(ms); 198081ebf06SWludzik, Jozef ms -= days; 199081ebf06SWludzik, Jozef 200081ebf06SWludzik, Jozef std::chrono::hours hours = std::chrono::floor<std::chrono::hours>(ms); 201081ebf06SWludzik, Jozef ms -= hours; 202081ebf06SWludzik, Jozef 203081ebf06SWludzik, Jozef std::chrono::minutes minutes = std::chrono::floor<std::chrono::minutes>(ms); 204081ebf06SWludzik, Jozef ms -= minutes; 205081ebf06SWludzik, Jozef 206081ebf06SWludzik, Jozef std::chrono::seconds seconds = std::chrono::floor<std::chrono::seconds>(ms); 207081ebf06SWludzik, Jozef ms -= seconds; 208081ebf06SWludzik, Jozef 209081ebf06SWludzik, Jozef fmt = "P"; 210081ebf06SWludzik, Jozef if (days.count() > 0) 211081ebf06SWludzik, Jozef { 212081ebf06SWludzik, Jozef fmt += std::to_string(days.count()) + "D"; 213081ebf06SWludzik, Jozef } 214081ebf06SWludzik, Jozef fmt += "T"; 215081ebf06SWludzik, Jozef if (hours.count() > 0) 216081ebf06SWludzik, Jozef { 217081ebf06SWludzik, Jozef fmt += std::to_string(hours.count()) + "H"; 218081ebf06SWludzik, Jozef } 219081ebf06SWludzik, Jozef if (minutes.count() > 0) 220081ebf06SWludzik, Jozef { 221081ebf06SWludzik, Jozef fmt += std::to_string(minutes.count()) + "M"; 222081ebf06SWludzik, Jozef } 223081ebf06SWludzik, Jozef if (seconds.count() != 0 || ms.count() != 0) 224081ebf06SWludzik, Jozef { 225081ebf06SWludzik, Jozef fmt += std::to_string(seconds.count()) + "."; 2267be4c8adSEd Tanous fmt += details::padZeros(ms.count(), 3); 2277be4c8adSEd Tanous fmt += "S"; 228081ebf06SWludzik, Jozef } 229081ebf06SWludzik, Jozef 230081ebf06SWludzik, Jozef return fmt; 231081ebf06SWludzik, Jozef } 232081ebf06SWludzik, Jozef 2331b7e696bSLukasz Kazmierczak inline std::optional<std::string> 2341b7e696bSLukasz Kazmierczak toDurationStringFromUint(const uint64_t timeMs) 2351b7e696bSLukasz Kazmierczak { 2361b7e696bSLukasz Kazmierczak static const uint64_t maxTimeMs = 2371b7e696bSLukasz Kazmierczak static_cast<uint64_t>(std::chrono::milliseconds::max().count()); 2381b7e696bSLukasz Kazmierczak 2391b7e696bSLukasz Kazmierczak if (maxTimeMs < timeMs) 2401b7e696bSLukasz Kazmierczak { 2411b7e696bSLukasz Kazmierczak return std::nullopt; 2421b7e696bSLukasz Kazmierczak } 2431b7e696bSLukasz Kazmierczak 2441b7e696bSLukasz Kazmierczak std::string duration = toDurationString(std::chrono::milliseconds(timeMs)); 2451b7e696bSLukasz Kazmierczak if (duration.empty()) 2461b7e696bSLukasz Kazmierczak { 2471b7e696bSLukasz Kazmierczak return std::nullopt; 2481b7e696bSLukasz Kazmierczak } 2491b7e696bSLukasz Kazmierczak 2501b7e696bSLukasz Kazmierczak return std::make_optional(duration); 2511b7e696bSLukasz Kazmierczak } 2521b7e696bSLukasz Kazmierczak 2532b82937eSEd Tanous namespace details 2542b82937eSEd Tanous { 2552b82937eSEd Tanous // Returns year/month/day triple in civil calendar 2562b82937eSEd Tanous // Preconditions: z is number of days since 1970-01-01 and is in the range: 2572b82937eSEd Tanous // [numeric_limits<Int>::min(), 2582b82937eSEd Tanous // numeric_limits<Int>::max()-719468]. 2592b82937eSEd Tanous // Algorithm sourced from 2602b82937eSEd Tanous // https://howardhinnant.github.io/date_algorithms.html#civil_from_days 2612b82937eSEd Tanous // All constants are explained in the above 2622b82937eSEd Tanous template <class IntType> 2632b82937eSEd Tanous constexpr std::tuple<IntType, unsigned, unsigned> 2642b82937eSEd Tanous civilFromDays(IntType z) noexcept 2652b82937eSEd Tanous { 2662b82937eSEd Tanous z += 719468; 2672b82937eSEd Tanous IntType era = (z >= 0 ? z : z - 146096) / 146097; 2682b82937eSEd Tanous unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096] 26989492a15SPatrick Williams unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 27089492a15SPatrick Williams 365; // [0, 399] 2712b82937eSEd Tanous IntType y = static_cast<IntType>(yoe) + era * 400; 2722b82937eSEd Tanous unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365] 2732b82937eSEd Tanous unsigned mp = (5 * doy + 2) / 153; // [0, 11] 2742b82937eSEd Tanous unsigned d = doy - (153 * mp + 2) / 5 + 1; // [1, 31] 2752b82937eSEd Tanous unsigned m = mp < 10 ? mp + 3 : mp - 9; // [1, 12] 2762b82937eSEd Tanous 2772b82937eSEd Tanous return std::tuple<IntType, unsigned, unsigned>(y + (m <= 2), m, d); 2782b82937eSEd Tanous } 2792b82937eSEd Tanous 2802b82937eSEd Tanous template <typename IntType, typename Period> 2812b82937eSEd Tanous std::string toISO8061ExtendedStr(std::chrono::duration<IntType, Period> t) 2822b82937eSEd Tanous { 2832b82937eSEd Tanous using seconds = std::chrono::duration<int>; 2842b82937eSEd Tanous using minutes = std::chrono::duration<int, std::ratio<60>>; 2852b82937eSEd Tanous using hours = std::chrono::duration<int, std::ratio<3600>>; 2862b82937eSEd Tanous using days = std::chrono::duration< 2872b82937eSEd Tanous IntType, std::ratio_multiply<hours::period, std::ratio<24>>>; 2882b82937eSEd Tanous 2892b82937eSEd Tanous // d is days since 1970-01-01 2902b82937eSEd Tanous days d = std::chrono::duration_cast<days>(t); 2912b82937eSEd Tanous 2922b82937eSEd Tanous // t is now time duration since midnight of day d 2932b82937eSEd Tanous t -= d; 2942b82937eSEd Tanous 2952b82937eSEd Tanous // break d down into year/month/day 2962b82937eSEd Tanous int year = 0; 2972b82937eSEd Tanous int month = 0; 2982b82937eSEd Tanous int day = 0; 2992b82937eSEd Tanous std::tie(year, month, day) = details::civilFromDays(d.count()); 3002b82937eSEd Tanous // Check against limits. Can't go above year 9999, and can't go below epoch 3012b82937eSEd Tanous // (1970) 3022b82937eSEd Tanous if (year >= 10000) 3032b82937eSEd Tanous { 3042b82937eSEd Tanous year = 9999; 3052b82937eSEd Tanous month = 12; 3062b82937eSEd Tanous day = 31; 3072b82937eSEd Tanous t = days(1) - std::chrono::duration<IntType, Period>(1); 3082b82937eSEd Tanous } 3092b82937eSEd Tanous else if (year < 1970) 3102b82937eSEd Tanous { 3112b82937eSEd Tanous year = 1970; 3122b82937eSEd Tanous month = 1; 3132b82937eSEd Tanous day = 1; 3142b82937eSEd Tanous t = std::chrono::duration<IntType, Period>::zero(); 3152b82937eSEd Tanous } 3162b82937eSEd Tanous 3172b82937eSEd Tanous std::string out; 3182b82937eSEd Tanous out += details::padZeros(year, 4); 3192b82937eSEd Tanous out += '-'; 3202b82937eSEd Tanous out += details::padZeros(month, 2); 3212b82937eSEd Tanous out += '-'; 3222b82937eSEd Tanous out += details::padZeros(day, 2); 3232b82937eSEd Tanous out += 'T'; 3242b82937eSEd Tanous hours hr = duration_cast<hours>(t); 3252b82937eSEd Tanous out += details::padZeros(hr.count(), 2); 3262b82937eSEd Tanous t -= hr; 3272b82937eSEd Tanous out += ':'; 3282b82937eSEd Tanous 3292b82937eSEd Tanous minutes mt = duration_cast<minutes>(t); 3302b82937eSEd Tanous out += details::padZeros(mt.count(), 2); 3312b82937eSEd Tanous t -= mt; 3322b82937eSEd Tanous out += ':'; 3332b82937eSEd Tanous 3342b82937eSEd Tanous seconds se = duration_cast<seconds>(t); 3352b82937eSEd Tanous out += details::padZeros(se.count(), 2); 3362b82937eSEd Tanous t -= se; 3372b82937eSEd Tanous 3382b82937eSEd Tanous if constexpr (std::is_same_v<typename decltype(t)::period, std::milli>) 3392b82937eSEd Tanous { 3402b82937eSEd Tanous out += '.'; 3412b82937eSEd Tanous using MilliDuration = std::chrono::duration<int, std::milli>; 3422b82937eSEd Tanous MilliDuration subsec = duration_cast<MilliDuration>(t); 3432b82937eSEd Tanous out += details::padZeros(subsec.count(), 3); 3442b82937eSEd Tanous } 3452b82937eSEd Tanous else if constexpr (std::is_same_v<typename decltype(t)::period, std::micro>) 3462b82937eSEd Tanous { 3472b82937eSEd Tanous out += '.'; 3482b82937eSEd Tanous 3492b82937eSEd Tanous using MicroDuration = std::chrono::duration<int, std::micro>; 3502b82937eSEd Tanous MicroDuration subsec = duration_cast<MicroDuration>(t); 3512b82937eSEd Tanous out += details::padZeros(subsec.count(), 6); 3522b82937eSEd Tanous } 3532b82937eSEd Tanous 3542b82937eSEd Tanous out += "+00:00"; 3552b82937eSEd Tanous return out; 3562b82937eSEd Tanous } 3572b82937eSEd Tanous } // namespace details 3582b82937eSEd Tanous 3592b82937eSEd Tanous // Returns the formatted date time string. 3602b82937eSEd Tanous // Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if 3612b82937eSEd Tanous // the given |secondsSinceEpoch| is too large, we return the maximum supported 3622b82937eSEd Tanous // date. 3632b82937eSEd Tanous inline std::string getDateTimeUint(uint64_t secondsSinceEpoch) 3642b82937eSEd Tanous { 3652b82937eSEd Tanous using DurationType = std::chrono::duration<uint64_t>; 3662b82937eSEd Tanous DurationType sinceEpoch(secondsSinceEpoch); 3672b82937eSEd Tanous return details::toISO8061ExtendedStr(sinceEpoch); 3682b82937eSEd Tanous } 3692b82937eSEd Tanous 3702b82937eSEd Tanous // Returns the formatted date time string with millisecond precision 3712b82937eSEd Tanous // Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if 3722b82937eSEd Tanous // the given |secondsSinceEpoch| is too large, we return the maximum supported 3732b82937eSEd Tanous // date. 3742b82937eSEd Tanous inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch) 3752b82937eSEd Tanous { 3762b82937eSEd Tanous using DurationType = std::chrono::duration<uint64_t, std::milli>; 3772b82937eSEd Tanous DurationType sinceEpoch(milliSecondsSinceEpoch); 3782b82937eSEd Tanous return details::toISO8061ExtendedStr(sinceEpoch); 3792b82937eSEd Tanous } 3802b82937eSEd Tanous 3812b82937eSEd Tanous // Returns the formatted date time string with microsecond precision 3822b82937eSEd Tanous inline std::string getDateTimeUintUs(uint64_t microSecondsSinceEpoch) 3832b82937eSEd Tanous { 3842b82937eSEd Tanous using DurationType = std::chrono::duration<uint64_t, std::micro>; 3852b82937eSEd Tanous DurationType sinceEpoch(microSecondsSinceEpoch); 3862b82937eSEd Tanous return details::toISO8061ExtendedStr(sinceEpoch); 3872b82937eSEd Tanous } 3882b82937eSEd Tanous 3892b82937eSEd Tanous inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch) 3902b82937eSEd Tanous { 3912b82937eSEd Tanous using DurationType = std::chrono::duration<std::time_t>; 3922b82937eSEd Tanous DurationType sinceEpoch(secondsSinceEpoch); 3932b82937eSEd Tanous return details::toISO8061ExtendedStr(sinceEpoch); 3942b82937eSEd Tanous } 3952b82937eSEd Tanous 3962b82937eSEd Tanous /** 3972b82937eSEd Tanous * Returns the current Date, Time & the local Time Offset 3982b82937eSEd Tanous * infromation in a pair 3992b82937eSEd Tanous * 4002b82937eSEd Tanous * @param[in] None 4012b82937eSEd Tanous * 4022b82937eSEd Tanous * @return std::pair<std::string, std::string>, which consist 4032b82937eSEd Tanous * of current DateTime & the TimeOffset strings respectively. 4042b82937eSEd Tanous */ 4052b82937eSEd Tanous inline std::pair<std::string, std::string> getDateTimeOffsetNow() 4062b82937eSEd Tanous { 4072b82937eSEd Tanous std::time_t time = std::time(nullptr); 4082b82937eSEd Tanous std::string dateTime = getDateTimeStdtime(time); 4092b82937eSEd Tanous 4102b82937eSEd Tanous /* extract the local Time Offset value from the 4112b82937eSEd Tanous * recevied dateTime string. 4122b82937eSEd Tanous */ 4132b82937eSEd Tanous std::string timeOffset("Z00:00"); 4142b82937eSEd Tanous std::size_t lastPos = dateTime.size(); 4152b82937eSEd Tanous std::size_t len = timeOffset.size(); 4162b82937eSEd Tanous if (lastPos > len) 4172b82937eSEd Tanous { 4182b82937eSEd Tanous timeOffset = dateTime.substr(lastPos - len); 4192b82937eSEd Tanous } 4202b82937eSEd Tanous 4212b82937eSEd Tanous return std::make_pair(dateTime, timeOffset); 4222b82937eSEd Tanous } 4232b82937eSEd Tanous 424c2e32007SEd Tanous using usSinceEpoch = std::chrono::duration<uint64_t, std::micro>; 425c2e32007SEd Tanous inline std::optional<usSinceEpoch> dateStringToEpoch(std::string_view datetime) 426c2e32007SEd Tanous { 427c2e32007SEd Tanous std::string date(datetime); 428c2e32007SEd Tanous std::stringstream stream(date); 429c2e32007SEd Tanous // Convert from ISO 8601 to boost local_time 430c2e32007SEd Tanous // (BMC only has time in UTC) 431c2e32007SEd Tanous boost::posix_time::ptime posixTime; 432c2e32007SEd Tanous boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); 433c2e32007SEd Tanous // Facet gets deleted with the stringsteam 434c2e32007SEd Tanous auto ifc = std::make_unique<boost::local_time::local_time_input_facet>( 435c2e32007SEd Tanous "%Y-%m-%d %H:%M:%S%F %ZP"); 436c2e32007SEd Tanous stream.imbue(std::locale(stream.getloc(), ifc.release())); 437c2e32007SEd Tanous 438c2e32007SEd Tanous boost::local_time::local_date_time ldt(boost::local_time::not_a_date_time); 439c2e32007SEd Tanous 440c2e32007SEd Tanous if (!(stream >> ldt)) 441c2e32007SEd Tanous { 442c2e32007SEd Tanous return std::nullopt; 443c2e32007SEd Tanous } 444c2e32007SEd Tanous posixTime = ldt.utc_time(); 445c2e32007SEd Tanous boost::posix_time::time_duration dur = posixTime - epoch; 446c2e32007SEd Tanous uint64_t durMicroSecs = static_cast<uint64_t>(dur.total_microseconds()); 447c2e32007SEd Tanous return std::chrono::duration<uint64_t, std::micro>{durMicroSecs}; 448c2e32007SEd Tanous } 449c2e32007SEd Tanous 450081ebf06SWludzik, Jozef } // namespace time_utils 451081ebf06SWludzik, Jozef } // namespace redfish 452