1081ebf06SWludzik, Jozef #pragma once 2081ebf06SWludzik, Jozef 3*b5190062SHieu Huynh #include "app.hpp" 44dbb8aeaSWludzik, Jozef #include "logging.hpp" 54dbb8aeaSWludzik, Jozef 69ea15c35SEd Tanous #include <algorithm> 74dbb8aeaSWludzik, Jozef #include <charconv> 8081ebf06SWludzik, Jozef #include <chrono> 99ea15c35SEd Tanous #include <cstddef> 10d5c80ad9SNan Zhou #include <cstdint> 11f653730dSEd Tanous #include <format> 124dbb8aeaSWludzik, Jozef #include <optional> 139ea15c35SEd Tanous #include <ratio> 14081ebf06SWludzik, Jozef #include <string> 159ea15c35SEd Tanous #include <string_view> 16081ebf06SWludzik, Jozef 17081ebf06SWludzik, Jozef namespace redfish 18081ebf06SWludzik, Jozef { 19081ebf06SWludzik, Jozef 20081ebf06SWludzik, Jozef namespace time_utils 21081ebf06SWludzik, Jozef { 22081ebf06SWludzik, Jozef 23081ebf06SWludzik, Jozef /** 244dbb8aeaSWludzik, Jozef * @brief Convert string that represents value in Duration Format to its numeric 254dbb8aeaSWludzik, Jozef * equivalent. 264dbb8aeaSWludzik, Jozef */ 274f48d5f6SEd Tanous inline std::optional<std::chrono::milliseconds> 281249e9cbSEd Tanous fromDurationString(std::string_view v) 294dbb8aeaSWludzik, Jozef { 304dbb8aeaSWludzik, Jozef std::chrono::milliseconds out = std::chrono::milliseconds::zero(); 311249e9cbSEd Tanous enum class ProcessingStage 324dbb8aeaSWludzik, Jozef { 331249e9cbSEd Tanous // P1DT1H1M1.100S 341249e9cbSEd Tanous P, 351249e9cbSEd Tanous Days, 361249e9cbSEd Tanous Hours, 371249e9cbSEd Tanous Minutes, 381249e9cbSEd Tanous Seconds, 391249e9cbSEd Tanous Milliseconds, 401249e9cbSEd Tanous Done, 411249e9cbSEd Tanous }; 421249e9cbSEd Tanous ProcessingStage stage = ProcessingStage::P; 431249e9cbSEd Tanous 441249e9cbSEd Tanous while (!v.empty()) 451249e9cbSEd Tanous { 461249e9cbSEd Tanous if (stage == ProcessingStage::P) 471249e9cbSEd Tanous { 484dbb8aeaSWludzik, Jozef if (v.front() != 'P') 494dbb8aeaSWludzik, Jozef { 504dbb8aeaSWludzik, Jozef return std::nullopt; 514dbb8aeaSWludzik, Jozef } 524dbb8aeaSWludzik, Jozef v.remove_prefix(1); 531249e9cbSEd Tanous stage = ProcessingStage::Days; 541249e9cbSEd Tanous continue; 551249e9cbSEd Tanous } 56c98dbc64SEd Tanous if (stage == ProcessingStage::Days) 574dbb8aeaSWludzik, Jozef { 581249e9cbSEd Tanous if (v.front() == 'T') 591249e9cbSEd Tanous { 604dbb8aeaSWludzik, Jozef v.remove_prefix(1); 611249e9cbSEd Tanous stage = ProcessingStage::Hours; 621249e9cbSEd Tanous continue; 631249e9cbSEd Tanous } 641249e9cbSEd Tanous } 651249e9cbSEd Tanous uint64_t ticks = 0; 661249e9cbSEd Tanous auto [ptr, ec] = std::from_chars(v.begin(), v.end(), ticks); 671249e9cbSEd Tanous if (ec != std::errc()) 684dbb8aeaSWludzik, Jozef { 6962598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to convert string \"{}\" to decimal", v); 701249e9cbSEd Tanous return std::nullopt; 711249e9cbSEd Tanous } 721249e9cbSEd Tanous size_t charactersRead = static_cast<size_t>(ptr - v.data()); 731249e9cbSEd Tanous if (ptr >= v.end()) 741249e9cbSEd Tanous { 7562598e31SEd Tanous BMCWEB_LOG_ERROR("Missing postfix"); 761249e9cbSEd Tanous return std::nullopt; 771249e9cbSEd Tanous } 781249e9cbSEd Tanous if (*ptr == 'D') 791249e9cbSEd Tanous { 801249e9cbSEd Tanous if (stage > ProcessingStage::Days) 811249e9cbSEd Tanous { 821249e9cbSEd Tanous return std::nullopt; 831249e9cbSEd Tanous } 841249e9cbSEd Tanous out += std::chrono::days(ticks); 851249e9cbSEd Tanous } 861249e9cbSEd Tanous else if (*ptr == 'H') 871249e9cbSEd Tanous { 881249e9cbSEd Tanous if (stage > ProcessingStage::Hours) 891249e9cbSEd Tanous { 901249e9cbSEd Tanous return std::nullopt; 911249e9cbSEd Tanous } 921249e9cbSEd Tanous out += std::chrono::hours(ticks); 931249e9cbSEd Tanous } 941249e9cbSEd Tanous else if (*ptr == 'M') 951249e9cbSEd Tanous { 961249e9cbSEd Tanous if (stage > ProcessingStage::Minutes) 971249e9cbSEd Tanous { 981249e9cbSEd Tanous return std::nullopt; 991249e9cbSEd Tanous } 1001249e9cbSEd Tanous out += std::chrono::minutes(ticks); 1011249e9cbSEd Tanous } 1021249e9cbSEd Tanous else if (*ptr == '.') 1031249e9cbSEd Tanous { 1041249e9cbSEd Tanous if (stage > ProcessingStage::Seconds) 1051249e9cbSEd Tanous { 1061249e9cbSEd Tanous return std::nullopt; 1071249e9cbSEd Tanous } 1081249e9cbSEd Tanous out += std::chrono::seconds(ticks); 1091249e9cbSEd Tanous stage = ProcessingStage::Milliseconds; 1101249e9cbSEd Tanous } 1111249e9cbSEd Tanous else if (*ptr == 'S') 1121249e9cbSEd Tanous { 1131249e9cbSEd Tanous // We could be seeing seconds for the first time, (as is the case in 1141249e9cbSEd Tanous // 1S) or for the second time (in the case of 1.1S). 1151249e9cbSEd Tanous if (stage <= ProcessingStage::Seconds) 1161249e9cbSEd Tanous { 1171249e9cbSEd Tanous out += std::chrono::seconds(ticks); 1181249e9cbSEd Tanous stage = ProcessingStage::Milliseconds; 1191249e9cbSEd Tanous } 1201249e9cbSEd Tanous else if (stage > ProcessingStage::Milliseconds) 1211249e9cbSEd Tanous { 12262598e31SEd Tanous BMCWEB_LOG_ERROR("Got unexpected information at end of parse"); 1231249e9cbSEd Tanous return std::nullopt; 1241249e9cbSEd Tanous } 1251249e9cbSEd Tanous else 1261249e9cbSEd Tanous { 1271249e9cbSEd Tanous // Seconds could be any form of (1S, 1.1S, 1.11S, 1.111S); 1281249e9cbSEd Tanous // Handle them all milliseconds are after the decimal point, 1291249e9cbSEd Tanous // so they need right padded. 1301249e9cbSEd Tanous if (charactersRead == 1) 1311249e9cbSEd Tanous { 1321249e9cbSEd Tanous ticks *= 100; 1331249e9cbSEd Tanous } 1341249e9cbSEd Tanous else if (charactersRead == 2) 1351249e9cbSEd Tanous { 1361249e9cbSEd Tanous ticks *= 10; 1371249e9cbSEd Tanous } 1381249e9cbSEd Tanous out += std::chrono::milliseconds(ticks); 1391249e9cbSEd Tanous stage = ProcessingStage::Milliseconds; 1401249e9cbSEd Tanous } 1411249e9cbSEd Tanous } 1421249e9cbSEd Tanous else 1431249e9cbSEd Tanous { 14462598e31SEd Tanous BMCWEB_LOG_ERROR("Unknown postfix {}", *ptr); 1454dbb8aeaSWludzik, Jozef return std::nullopt; 1464dbb8aeaSWludzik, Jozef } 1474dbb8aeaSWludzik, Jozef 1481249e9cbSEd Tanous v.remove_prefix(charactersRead + 1U); 1494dbb8aeaSWludzik, Jozef } 1504dbb8aeaSWludzik, Jozef return out; 1514dbb8aeaSWludzik, Jozef } 1524dbb8aeaSWludzik, Jozef 1534dbb8aeaSWludzik, Jozef /** 154081ebf06SWludzik, Jozef * @brief Convert time value into duration format that is based on ISO 8601. 155081ebf06SWludzik, Jozef * Example output: "P12DT1M5.5S" 156081ebf06SWludzik, Jozef * Ref: Redfish Specification, Section 9.4.4. Duration values 157081ebf06SWludzik, Jozef */ 158b00dcc27SEd Tanous inline std::string toDurationString(std::chrono::milliseconds ms) 159081ebf06SWludzik, Jozef { 160081ebf06SWludzik, Jozef if (ms < std::chrono::milliseconds::zero()) 161081ebf06SWludzik, Jozef { 162081ebf06SWludzik, Jozef return ""; 163081ebf06SWludzik, Jozef } 164081ebf06SWludzik, Jozef 1651249e9cbSEd Tanous std::chrono::days days = std::chrono::floor<std::chrono::days>(ms); 166081ebf06SWludzik, Jozef ms -= days; 167081ebf06SWludzik, Jozef 168081ebf06SWludzik, Jozef std::chrono::hours hours = std::chrono::floor<std::chrono::hours>(ms); 169081ebf06SWludzik, Jozef ms -= hours; 170081ebf06SWludzik, Jozef 171081ebf06SWludzik, Jozef std::chrono::minutes minutes = std::chrono::floor<std::chrono::minutes>(ms); 172081ebf06SWludzik, Jozef ms -= minutes; 173081ebf06SWludzik, Jozef 174081ebf06SWludzik, Jozef std::chrono::seconds seconds = std::chrono::floor<std::chrono::seconds>(ms); 175081ebf06SWludzik, Jozef ms -= seconds; 176f653730dSEd Tanous std::string daysStr; 177081ebf06SWludzik, Jozef if (days.count() > 0) 178081ebf06SWludzik, Jozef { 179f653730dSEd Tanous daysStr = std::format("{}D", days.count()); 180081ebf06SWludzik, Jozef } 181f653730dSEd Tanous std::string hoursStr; 182081ebf06SWludzik, Jozef if (hours.count() > 0) 183081ebf06SWludzik, Jozef { 184f653730dSEd Tanous hoursStr = std::format("{}H", hours.count()); 185081ebf06SWludzik, Jozef } 186f653730dSEd Tanous std::string minStr; 187081ebf06SWludzik, Jozef if (minutes.count() > 0) 188081ebf06SWludzik, Jozef { 189f653730dSEd Tanous minStr = std::format("{}M", minutes.count()); 190081ebf06SWludzik, Jozef } 191f653730dSEd Tanous std::string secStr; 192081ebf06SWludzik, Jozef if (seconds.count() != 0 || ms.count() != 0) 193081ebf06SWludzik, Jozef { 194f653730dSEd Tanous secStr = std::format("{}.{:03}S", seconds.count(), ms.count()); 195081ebf06SWludzik, Jozef } 196081ebf06SWludzik, Jozef 197f653730dSEd Tanous return std::format("P{}T{}{}{}", daysStr, hoursStr, minStr, secStr); 198081ebf06SWludzik, Jozef } 199081ebf06SWludzik, Jozef 2001b7e696bSLukasz Kazmierczak inline std::optional<std::string> 2011b7e696bSLukasz Kazmierczak toDurationStringFromUint(const uint64_t timeMs) 2021b7e696bSLukasz Kazmierczak { 203f653730dSEd Tanous constexpr uint64_t maxTimeMs = 2041b7e696bSLukasz Kazmierczak static_cast<uint64_t>(std::chrono::milliseconds::max().count()); 2051b7e696bSLukasz Kazmierczak 2061b7e696bSLukasz Kazmierczak if (maxTimeMs < timeMs) 2071b7e696bSLukasz Kazmierczak { 2081b7e696bSLukasz Kazmierczak return std::nullopt; 2091b7e696bSLukasz Kazmierczak } 2101b7e696bSLukasz Kazmierczak 2111b7e696bSLukasz Kazmierczak std::string duration = toDurationString(std::chrono::milliseconds(timeMs)); 2121b7e696bSLukasz Kazmierczak if (duration.empty()) 2131b7e696bSLukasz Kazmierczak { 2141b7e696bSLukasz Kazmierczak return std::nullopt; 2151b7e696bSLukasz Kazmierczak } 2161b7e696bSLukasz Kazmierczak 2171b7e696bSLukasz Kazmierczak return std::make_optional(duration); 2181b7e696bSLukasz Kazmierczak } 2191b7e696bSLukasz Kazmierczak 2202b82937eSEd Tanous namespace details 2212b82937eSEd Tanous { 2222b82937eSEd Tanous // Returns year/month/day triple in civil calendar 2232b82937eSEd Tanous // Preconditions: z is number of days since 1970-01-01 and is in the range: 2242b82937eSEd Tanous // [numeric_limits<Int>::min(), 2252b82937eSEd Tanous // numeric_limits<Int>::max()-719468]. 2262b82937eSEd Tanous // Algorithm sourced from 2272b82937eSEd Tanous // https://howardhinnant.github.io/date_algorithms.html#civil_from_days 2282b82937eSEd Tanous // All constants are explained in the above 2292b82937eSEd Tanous template <class IntType> 2302b82937eSEd Tanous constexpr std::tuple<IntType, unsigned, unsigned> 2312b82937eSEd Tanous civilFromDays(IntType z) noexcept 2322b82937eSEd Tanous { 2332b82937eSEd Tanous z += 719468; 2342b82937eSEd Tanous IntType era = (z >= 0 ? z : z - 146096) / 146097; 2352b82937eSEd Tanous unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096] 23689492a15SPatrick Williams unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 23789492a15SPatrick Williams 365; // [0, 399] 2382b82937eSEd Tanous IntType y = static_cast<IntType>(yoe) + era * 400; 2392b82937eSEd Tanous unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365] 2402b82937eSEd Tanous unsigned mp = (5 * doy + 2) / 153; // [0, 11] 2412b82937eSEd Tanous unsigned d = doy - (153 * mp + 2) / 5 + 1; // [1, 31] 2422b82937eSEd Tanous unsigned m = mp < 10 ? mp + 3 : mp - 9; // [1, 12] 2432b82937eSEd Tanous 2442b82937eSEd Tanous return std::tuple<IntType, unsigned, unsigned>(y + (m <= 2), m, d); 2452b82937eSEd Tanous } 2462b82937eSEd Tanous 2472b82937eSEd Tanous template <typename IntType, typename Period> 2482b82937eSEd Tanous std::string toISO8061ExtendedStr(std::chrono::duration<IntType, Period> t) 2492b82937eSEd Tanous { 2502b82937eSEd Tanous using seconds = std::chrono::duration<int>; 2512b82937eSEd Tanous using minutes = std::chrono::duration<int, std::ratio<60>>; 2522b82937eSEd Tanous using hours = std::chrono::duration<int, std::ratio<3600>>; 2532b82937eSEd Tanous using days = std::chrono::duration< 2542b82937eSEd Tanous IntType, std::ratio_multiply<hours::period, std::ratio<24>>>; 2552b82937eSEd Tanous 2562b82937eSEd Tanous // d is days since 1970-01-01 2572b82937eSEd Tanous days d = std::chrono::duration_cast<days>(t); 2582b82937eSEd Tanous 2592b82937eSEd Tanous // t is now time duration since midnight of day d 2602b82937eSEd Tanous t -= d; 2612b82937eSEd Tanous 2622b82937eSEd Tanous // break d down into year/month/day 2632b82937eSEd Tanous int year = 0; 2642b82937eSEd Tanous int month = 0; 2652b82937eSEd Tanous int day = 0; 2662b82937eSEd Tanous std::tie(year, month, day) = details::civilFromDays(d.count()); 2672b82937eSEd Tanous // Check against limits. Can't go above year 9999, and can't go below epoch 2682b82937eSEd Tanous // (1970) 2692b82937eSEd Tanous if (year >= 10000) 2702b82937eSEd Tanous { 2712b82937eSEd Tanous year = 9999; 2722b82937eSEd Tanous month = 12; 2732b82937eSEd Tanous day = 31; 2742b82937eSEd Tanous t = days(1) - std::chrono::duration<IntType, Period>(1); 2752b82937eSEd Tanous } 2762b82937eSEd Tanous else if (year < 1970) 2772b82937eSEd Tanous { 2782b82937eSEd Tanous year = 1970; 2792b82937eSEd Tanous month = 1; 2802b82937eSEd Tanous day = 1; 2812b82937eSEd Tanous t = std::chrono::duration<IntType, Period>::zero(); 2822b82937eSEd Tanous } 2832b82937eSEd Tanous 2842b82937eSEd Tanous hours hr = duration_cast<hours>(t); 2852b82937eSEd Tanous t -= hr; 2862b82937eSEd Tanous 2872b82937eSEd Tanous minutes mt = duration_cast<minutes>(t); 2882b82937eSEd Tanous t -= mt; 2892b82937eSEd Tanous 2902b82937eSEd Tanous seconds se = duration_cast<seconds>(t); 291f653730dSEd Tanous 2922b82937eSEd Tanous t -= se; 2932b82937eSEd Tanous 294f653730dSEd Tanous std::string subseconds; 2952b82937eSEd Tanous if constexpr (std::is_same_v<typename decltype(t)::period, std::milli>) 2962b82937eSEd Tanous { 2972b82937eSEd Tanous using MilliDuration = std::chrono::duration<int, std::milli>; 2982b82937eSEd Tanous MilliDuration subsec = duration_cast<MilliDuration>(t); 299f653730dSEd Tanous subseconds = std::format(".{:03}", subsec.count()); 3002b82937eSEd Tanous } 3012b82937eSEd Tanous else if constexpr (std::is_same_v<typename decltype(t)::period, std::micro>) 3022b82937eSEd Tanous { 3032b82937eSEd Tanous using MicroDuration = std::chrono::duration<int, std::micro>; 3042b82937eSEd Tanous MicroDuration subsec = duration_cast<MicroDuration>(t); 305f653730dSEd Tanous subseconds = std::format(".{:06}", subsec.count()); 3062b82937eSEd Tanous } 3072b82937eSEd Tanous 308f653730dSEd Tanous return std::format("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}{}+00:00", year, 309f653730dSEd Tanous month, day, hr.count(), mt.count(), se.count(), 310f653730dSEd Tanous subseconds); 3112b82937eSEd Tanous } 3122b82937eSEd Tanous } // namespace details 3132b82937eSEd Tanous 3142b82937eSEd Tanous // Returns the formatted date time string. 3152b82937eSEd Tanous // Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if 3162b82937eSEd Tanous // the given |secondsSinceEpoch| is too large, we return the maximum supported 3172b82937eSEd Tanous // date. 3182b82937eSEd Tanous inline std::string getDateTimeUint(uint64_t secondsSinceEpoch) 3192b82937eSEd Tanous { 3202b82937eSEd Tanous using DurationType = std::chrono::duration<uint64_t>; 3212b82937eSEd Tanous DurationType sinceEpoch(secondsSinceEpoch); 3222b82937eSEd Tanous return details::toISO8061ExtendedStr(sinceEpoch); 3232b82937eSEd Tanous } 3242b82937eSEd Tanous 3252b82937eSEd Tanous // Returns the formatted date time string with millisecond precision 3262b82937eSEd Tanous // Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if 3272b82937eSEd Tanous // the given |secondsSinceEpoch| is too large, we return the maximum supported 3282b82937eSEd Tanous // date. 3292b82937eSEd Tanous inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch) 3302b82937eSEd Tanous { 3312b82937eSEd Tanous using DurationType = std::chrono::duration<uint64_t, std::milli>; 3322b82937eSEd Tanous DurationType sinceEpoch(milliSecondsSinceEpoch); 3332b82937eSEd Tanous return details::toISO8061ExtendedStr(sinceEpoch); 3342b82937eSEd Tanous } 3352b82937eSEd Tanous 3362b82937eSEd Tanous // Returns the formatted date time string with microsecond precision 3372b82937eSEd Tanous inline std::string getDateTimeUintUs(uint64_t microSecondsSinceEpoch) 3382b82937eSEd Tanous { 3392b82937eSEd Tanous using DurationType = std::chrono::duration<uint64_t, std::micro>; 3402b82937eSEd Tanous DurationType sinceEpoch(microSecondsSinceEpoch); 3412b82937eSEd Tanous return details::toISO8061ExtendedStr(sinceEpoch); 3422b82937eSEd Tanous } 3432b82937eSEd Tanous 3442b82937eSEd Tanous inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch) 3452b82937eSEd Tanous { 3462b82937eSEd Tanous using DurationType = std::chrono::duration<std::time_t>; 3472b82937eSEd Tanous DurationType sinceEpoch(secondsSinceEpoch); 3482b82937eSEd Tanous return details::toISO8061ExtendedStr(sinceEpoch); 3492b82937eSEd Tanous } 3502b82937eSEd Tanous 3512b82937eSEd Tanous /** 3522b82937eSEd Tanous * Returns the current Date, Time & the local Time Offset 3538ece0e45SEd Tanous * information in a pair 3542b82937eSEd Tanous * 3552b82937eSEd Tanous * @param[in] None 3562b82937eSEd Tanous * 3572b82937eSEd Tanous * @return std::pair<std::string, std::string>, which consist 3582b82937eSEd Tanous * of current DateTime & the TimeOffset strings respectively. 3592b82937eSEd Tanous */ 3602b82937eSEd Tanous inline std::pair<std::string, std::string> getDateTimeOffsetNow() 3612b82937eSEd Tanous { 3622b82937eSEd Tanous std::time_t time = std::time(nullptr); 3632b82937eSEd Tanous std::string dateTime = getDateTimeStdtime(time); 3642b82937eSEd Tanous 3652b82937eSEd Tanous /* extract the local Time Offset value from the 3668ece0e45SEd Tanous * received dateTime string. 3672b82937eSEd Tanous */ 3682b82937eSEd Tanous std::string timeOffset("Z00:00"); 3692b82937eSEd Tanous std::size_t lastPos = dateTime.size(); 3702b82937eSEd Tanous std::size_t len = timeOffset.size(); 3712b82937eSEd Tanous if (lastPos > len) 3722b82937eSEd Tanous { 3732b82937eSEd Tanous timeOffset = dateTime.substr(lastPos - len); 3742b82937eSEd Tanous } 3752b82937eSEd Tanous 3762b82937eSEd Tanous return std::make_pair(dateTime, timeOffset); 3772b82937eSEd Tanous } 3782b82937eSEd Tanous 379c51afd54SEd Tanous using usSinceEpoch = std::chrono::duration<int64_t, std::micro>; 3801b8b02a4SEd Tanous std::optional<usSinceEpoch> dateStringToEpoch(std::string_view datetime); 381*b5190062SHieu Huynh 382*b5190062SHieu Huynh /** 383*b5190062SHieu Huynh * @brief Returns the datetime in ISO 8601 format 384*b5190062SHieu Huynh * 385*b5190062SHieu Huynh * @param[in] std::string_view the date of item manufacture in ISO 8601 format, 386*b5190062SHieu Huynh * either as YYYYMMDD or YYYYMMDDThhmmssZ 387*b5190062SHieu Huynh * Ref: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/ 388*b5190062SHieu Huynh * xyz/openbmc_project/Inventory/Decorator/Asset.interface.yaml#L16 389*b5190062SHieu Huynh * 390*b5190062SHieu Huynh * @return std::string which consist the datetime 391*b5190062SHieu Huynh */ 392*b5190062SHieu Huynh inline std::optional<std::string> getDateTimeIso8601(std::string_view datetime) 393*b5190062SHieu Huynh { 394*b5190062SHieu Huynh std::optional<redfish::time_utils::usSinceEpoch> us = 395*b5190062SHieu Huynh redfish::time_utils::dateStringToEpoch(datetime); 396*b5190062SHieu Huynh if (!us) 397*b5190062SHieu Huynh { 398*b5190062SHieu Huynh return std::nullopt; 399*b5190062SHieu Huynh } 400*b5190062SHieu Huynh auto secondsDuration = 401*b5190062SHieu Huynh std::chrono::duration_cast<std::chrono::seconds>(*us); 402*b5190062SHieu Huynh 403*b5190062SHieu Huynh return std::make_optional(redfish::time_utils::getDateTimeUint( 404*b5190062SHieu Huynh static_cast<uint64_t>(secondsDuration.count()))); 405*b5190062SHieu Huynh } 406*b5190062SHieu Huynh 407*b5190062SHieu Huynh /** 408*b5190062SHieu Huynh * @brief ProductionDate report 409*b5190062SHieu Huynh */ 410*b5190062SHieu Huynh inline void productionDateReport(crow::Response& res, 411*b5190062SHieu Huynh const std::string& buildDate) 412*b5190062SHieu Huynh { 413*b5190062SHieu Huynh std::optional<std::string> valueStr = 414*b5190062SHieu Huynh redfish::time_utils::getDateTimeIso8601(buildDate); 415*b5190062SHieu Huynh if (!valueStr) 416*b5190062SHieu Huynh { 417*b5190062SHieu Huynh messages::internalError(); 418*b5190062SHieu Huynh return; 419*b5190062SHieu Huynh } 420*b5190062SHieu Huynh res.jsonValue["ProductionDate"] = *valueStr; 421*b5190062SHieu Huynh } 422*b5190062SHieu Huynh 423081ebf06SWludzik, Jozef } // namespace time_utils 424081ebf06SWludzik, Jozef } // namespace redfish 425