LCOV - code coverage report
Current view: top level - lib/support - TimeUtils.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 96 121 79.3 %
Date: 2024-02-15 08:20:41 Functions: 15 19 78.9 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4             :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5             :  *    All rights reserved.
       6             :  *
       7             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       8             :  *    you may not use this file except in compliance with the License.
       9             :  *    You may obtain a copy of the License at
      10             :  *
      11             :  *        http://www.apache.org/licenses/LICENSE-2.0
      12             :  *
      13             :  *    Unless required by applicable law or agreed to in writing, software
      14             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      15             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16             :  *    See the License for the specific language governing permissions and
      17             :  *    limitations under the License.
      18             :  */
      19             : 
      20             : /**
      21             :  *    @file
      22             :  *      Various utility functions for dealing with time and dates.
      23             :  *
      24             :  */
      25             : 
      26             : #ifndef __STDC_LIMIT_MACROS
      27             : #define __STDC_LIMIT_MACROS
      28             : #endif
      29             : #include <limits>
      30             : #include <stdint.h>
      31             : #include <type_traits>
      32             : 
      33             : #include <lib/core/CHIPCore.h>
      34             : #include <lib/support/SafeInt.h>
      35             : 
      36             : #include "TimeUtils.h"
      37             : 
      38             : namespace chip {
      39             : 
      40             : enum
      41             : {
      42             :     // Number of days during the invariant part of the year (after the leap day).
      43             :     kDaysFromMarch1ToDecember31 = 306,
      44             : 
      45             :     // Number of years in a Gregorian "cycle", where a cycle is the 400-year period
      46             :     // over which the Gregorian calendar repeats.
      47             :     kYearsPerCycle = 400,
      48             : 
      49             :     // Total number of days within cycle.
      50             :     kDaysPerCycle = 146097,
      51             : 
      52             :     // Total number of days between 0000/03/01 and 1970/01/01.
      53             :     kEpochOffsetDays = 719468
      54             : };
      55             : 
      56             : /* Returns the number of days between January 1st and March 1st for a given year.
      57             :  */
      58     6713097 : static inline uint8_t DaysToMarch1(uint16_t year)
      59             : {
      60     6713097 :     if (IsLeapYear(year))
      61     1630272 :         return 60;
      62     5082825 :     return 59;
      63             : }
      64             : 
      65             : /* Converts a March-based month number (0=March, 1=April, etc.) to a March-1st based day of year (0=March 1st, 1=March 2nd, etc.).
      66             :  *
      67             :  * NOTE: This is based on the math described in http://howardhinnant.github.io/date_algorithms.html.
      68             :  */
      69    28548444 : static uint16_t MarchBasedMonthToDayOfYear(uint8_t month)
      70             : {
      71    28548444 :     return static_cast<uint16_t>((153 * month + 2) / 5);
      72             : }
      73             : 
      74             : /* Converts a March-1st based day of year (0=March 1st, 1=March 2nd, etc.) to a March-based month number (0=March, 1=April, etc.).
      75             :  */
      76    14293272 : static uint8_t MarchBasedDayOfYearToMonth(uint16_t dayOfYear)
      77             : {
      78             :     // This assumes dayOfYear is not using the full uint16_t range, so the cast
      79             :     // to uint8_t doesn't overflow.
      80    14293272 :     return static_cast<uint8_t>((5 * dayOfYear + 2) / 153);
      81             : }
      82             : 
      83             : /**
      84             :  *  @def IsLeapYear
      85             :  *
      86             :  *  @brief
      87             :  *    Returns true if the given year is a leap year according to the Gregorian calendar.
      88             :  *
      89             :  *  @param year
      90             :  *    Gregorian calendar year.
      91             :  *
      92             :  */
      93     7500335 : bool IsLeapYear(uint16_t year)
      94             : {
      95     7500335 :     return (year % kLeapYearInterval) == 0 && ((year % kYearsPerCentury) != 0 || (year % kYearsPerCycle) == 0);
      96             : }
      97             : 
      98             : /**
      99             :  *  @def DaysInMonth
     100             :  *
     101             :  *  @brief
     102             :  *    Returns the number of days in the given month/year.
     103             :  *
     104             :  *  @param year
     105             :  *    Gregorian calendar year.
     106             :  *
     107             :  *  @param month
     108             :  *    Month in standard form (1=January ... 12=December).
     109             :  *
     110             :  *  @return
     111             :  *    Number of days in the given month.
     112             :  */
     113    10026729 : uint8_t DaysInMonth(uint16_t year, uint8_t month)
     114             : {
     115             :     static const uint8_t daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
     116             : 
     117    10026729 :     if (month == kFebruary && IsLeapYear(year))
     118      193380 :         return 29;
     119     9833349 :     if (month >= kJanuary && month <= kDecember)
     120     9833349 :         return daysInMonth[month - 1];
     121           0 :     return 0;
     122             : }
     123             : 
     124             : /**
     125             :  *  @def FirstWeekdayOfYear
     126             :  *
     127             :  *  @brief
     128             :  *    Returns the day of the week for January 1st of the given year.
     129             :  *
     130             :  *  @param year
     131             :  *    Gregorian calendar year.
     132             :  *
     133             :  *  @return
     134             :  *    The day-of-week (0=Sunday...6=Saturday).
     135             :  */
     136           0 : uint8_t FirstWeekdayOfYear(uint16_t year)
     137             : {
     138             :     // Compute the day of the week for the first day of the given year using Gauss' algorithm.
     139             :     return static_cast<uint8_t>(
     140           0 :         (1 + 5 * ((year - 1) % kLeapYearInterval) + 4 * ((year - 1) % kYearsPerCentury) + 6 * ((year - 1) % kYearsPerCycle)) %
     141           0 :         kDaysPerWeek);
     142             : }
     143             : 
     144             : /**
     145             :  *  @def OrdinalDateToCalendarDate
     146             :  *
     147             :  *  @brief
     148             :  *    Convert an ordinal date (year/day-of-year) to a calendar date.
     149             :  *
     150             :  *  @param year
     151             :  *    Gregorian calendar year.
     152             :  *
     153             :  *  @param dayOfYear
     154             :  *    Ordinal day of year, base 1 (1=January 1st, 2=January 2nd, etc.).
     155             :  *
     156             :  *  @param month
     157             :  *    [OUTPUT] Corresponding month in standard form (1=January ... 12=December).
     158             :  *
     159             :  *  @param dayOfMonth
     160             :  *    [OUTPUT] Corresponding day-of-month in standard form (1=1st, 2=2nd, etc.).
     161             :  *
     162             :  */
     163     3652791 : void OrdinalDateToCalendarDate(uint16_t year, uint16_t dayOfYear, uint8_t & month, uint8_t & dayOfMonth)
     164             : {
     165     3652791 :     uint8_t daysToMarch1 = DaysToMarch1(year);
     166             : 
     167             :     // Make dayOfYear base 0.
     168     3652791 :     dayOfYear = static_cast<uint16_t>(dayOfYear - 1);
     169             : 
     170             :     // Adjust dayOfYear to a March 1st base (i.e. 0 = March 1, 1 = March 2, etc.).  This numbers January
     171             :     // and February at the end of the range, with the benefit that day numbering is identical between
     172             :     // standard and leap years with the exception of the leap day itself.
     173     3652791 :     if (dayOfYear < daysToMarch1)
     174      592485 :         dayOfYear = static_cast<uint16_t>(dayOfYear + kDaysFromMarch1ToDecember31);
     175             :     else
     176     3060306 :         dayOfYear = static_cast<uint16_t>(dayOfYear - daysToMarch1);
     177             : 
     178             :     // Compute a March-based month number (i.e. 0=March...11=February) from the day of year.  This is based
     179             :     // on the logic in http://howardhinnant.github.io/date_algorithms.html.
     180     3652791 :     month = MarchBasedDayOfYearToMonth(dayOfYear);
     181             : 
     182             :     // Compute the days from March 1st to the start of the corresponding month.
     183     3652791 :     uint16_t daysFromMarch1ToStartOfMonth = MarchBasedMonthToDayOfYear(month);
     184             : 
     185             :     // Compute the day of month in standard form (1=1st, 2=2nd, etc.).
     186     3652791 :     dayOfMonth = static_cast<uint8_t>(dayOfYear - daysFromMarch1ToStartOfMonth + 1);
     187             : 
     188             :     // Convert the month number to standard form (1=January...12=December).
     189     3652791 :     month = static_cast<uint8_t>(month + (month < 10 ? 3 : -9));
     190     3652791 : }
     191             : 
     192             : /**
     193             :  *  @def CalendarDateToOrdinalDate
     194             :  *
     195             :  *  @brief
     196             :  *    Convert an calendar date to ordinal form (year/day-of-year).
     197             :  *
     198             :  *  @param year
     199             :  *    Gregorian calendar year.
     200             :  *
     201             :  *  @param month
     202             :  *    Month in standard form (1=January ... 12=December).
     203             :  *
     204             :  *  @param dayOfMonth
     205             :  *    Day-of-month in standard form (1=1st, 2=2nd, etc.).
     206             :  *
     207             :  *  @param dayOfYear
     208             :  *    [OUTPUT] Ordinal day of year, base 1 (1=January 1st, 2=January 2nd, etc.).
     209             :  *
     210             :  */
     211     3652791 : void CalendarDateToOrdinalDate(uint16_t year, uint8_t month, uint8_t dayOfMonth, uint16_t & dayOfYear)
     212             : {
     213             :     // Convert month to a March-based month number (i.e. 0=March, 1=April, ...11=February).
     214     3652791 :     month = static_cast<uint8_t>(month + (month > kFebruary ? -3 : 9));
     215             : 
     216             :     // Compute the days from March 1st to the start of the corresponding month.
     217     3652791 :     dayOfYear = MarchBasedMonthToDayOfYear(month);
     218             : 
     219             :     // Adjust dayOfYear to be January-based (0=January 1st, 1=January 2nd...).
     220     3652791 :     if (dayOfYear < kDaysFromMarch1ToDecember31)
     221     3060306 :         dayOfYear = static_cast<uint16_t>(dayOfYear + DaysToMarch1(year));
     222             :     else
     223      592485 :         dayOfYear = static_cast<uint16_t>(dayOfYear - kDaysFromMarch1ToDecember31);
     224             : 
     225             :     // Add in day of month, converting to base 1 in the process.
     226     3652791 :     dayOfYear = static_cast<uint16_t>(dayOfYear + dayOfMonth);
     227     3652791 : }
     228             : 
     229             : /**
     230             :  *  @def CalendarDateToDaysSinceUnixEpoch
     231             :  *
     232             :  *  @brief
     233             :  *    Convert a calendar date to the number of days since 1970-01-01.
     234             :  *
     235             :  *  @param year
     236             :  *    Gregorian calendar year in the range 1970 to 28276.
     237             :  *
     238             :  *  @param month
     239             :  *    Month in standard form (1=January ... 12=December).
     240             :  *
     241             :  *  @param dayOfMonth
     242             :  *    Day-of-month in standard form (1=1st, 2=2nd, etc.).
     243             :  *
     244             :  *  @param daysSinceEpoch
     245             :  *    [OUTPUT] Number of days since 1970-01-01.
     246             :  *
     247             :  *  @return
     248             :  *    True if the date was converted successfully.  False if the given year falls outside the
     249             :  *    representable range.
     250             :  *
     251             :  *  @note
     252             :  *    This function makes no attempt to verify the correct range of any arguments other than year.
     253             :  *    Therefore callers must make sure the supplied values are valid prior to calling the function.
     254             :  */
     255    10602381 : bool CalendarDateToDaysSinceUnixEpoch(uint16_t year, uint8_t month, uint8_t dayOfMonth, uint32_t & daysSinceEpoch)
     256             : {
     257             :     // NOTE: This algorithm is based on the logic described in http://howardhinnant.github.io/date_algorithms.html.
     258             : 
     259             :     // Return immediately if the year is out of range.
     260    10602381 :     if (year < kUnixEpochYear || year > kMaxYearInDaysSinceUnixEpoch32)
     261             :     {
     262           0 :         daysSinceEpoch = UINT32_MAX;
     263           0 :         return false;
     264             :     }
     265             : 
     266             :     // Adjust the year and month to be March-based (i.e. 0=March, 1=April, ...11=February).
     267    10602381 :     if (month <= kFebruary)
     268             :     {
     269     1719774 :         year--;
     270     1719774 :         month = static_cast<uint8_t>(month + 9);
     271             :     }
     272             :     else
     273     8882607 :         month = static_cast<uint8_t>(month - 3);
     274             : 
     275             :     // Compute the days from March 1st to the start of the specified day.
     276    10602381 :     uint16_t dayOfYear = static_cast<uint16_t>(MarchBasedMonthToDayOfYear(month) + (dayOfMonth - 1));
     277             : 
     278             :     // Compute the 400-year Gregorian "cycle" within which the given year falls.
     279    10602381 :     uint16_t cycle = static_cast<uint16_t>(year / kYearsPerCycle);
     280             : 
     281             :     // Compute the relative year within the cycle.
     282    10602381 :     uint32_t yearOfCycle = year - (cycle * kYearsPerCycle);
     283             : 
     284             :     // Compute the relative day within the cycle, accounting for leap-years.
     285    10602381 :     uint32_t dayOfCycle =
     286    10602381 :         (yearOfCycle * kDaysPerStandardYear) + dayOfYear - (yearOfCycle / kYearsPerCentury) + (yearOfCycle / kLeapYearInterval);
     287             : 
     288             :     // Compute the total number of days since the start of the logical calendar (0000-03-01).
     289    10602381 :     uint32_t daysSinceCalendarStart = (cycle * kDaysPerCycle) + dayOfCycle;
     290             : 
     291             :     // Adjust the days value to be days since 1970-01-01.
     292    10602381 :     daysSinceEpoch = daysSinceCalendarStart - kEpochOffsetDays;
     293             : 
     294    10602381 :     return true;
     295             : }
     296             : 
     297             : /**
     298             :  *  @def DaysSinceUnixEpochToCalendarDate
     299             :  *
     300             :  *  @brief
     301             :  *    Convert the number of days since 1970-01-01 to a calendar date.
     302             :  *
     303             :  *  @param daysSinceEpoch
     304             :  *    Number of days since 1970-01-01.
     305             :  *
     306             :  *  @param year
     307             :  *    [OUTPUT] Gregorian calendar year.
     308             :  *
     309             :  *  @param month
     310             :  *    [OUTPUT] Month in standard form (1=January ... 12=December).
     311             :  *
     312             :  *  @param dayOfMonth
     313             :  *    [OUTPUT] Day-of-month in standard form (1=1st, 2=2nd, etc.).
     314             :  *
     315             :  *  @return
     316             :  *     True if the conversion was successful.  False if the year would not fit
     317             :  *     in uint16_t.
     318             :  */
     319    10640481 : bool DaysSinceUnixEpochToCalendarDate(uint32_t daysSinceEpoch, uint16_t & year, uint8_t & month, uint8_t & dayOfMonth)
     320             : {
     321             :     // NOTE: This algorithm is based on the logic described in http://howardhinnant.github.io/date_algorithms.html.
     322    10640481 :     if (daysSinceEpoch / kDaysPerStandardYear + 1 > std::numeric_limits<std::remove_reference<decltype(year)>::type>::max())
     323             :     {
     324             :         // Our year calculation will likely overflow.
     325           0 :         return false;
     326             :     }
     327             : 
     328             :     // Adjust days value to be relative to 0000-03-01.
     329    10640481 :     daysSinceEpoch += kEpochOffsetDays;
     330             : 
     331             :     // Compute the 400-year Gregorian cycle in which the given day resides.
     332    10640481 :     uint32_t cycle = daysSinceEpoch / kDaysPerCycle;
     333             : 
     334             :     // Compute the relative day within the cycle.
     335    10640481 :     uint32_t dayOfCycle = daysSinceEpoch - (cycle * kDaysPerCycle);
     336             : 
     337             :     // Compute the relative year within the cycle, adjusting for leap-years.
     338    10640481 :     uint16_t yearOfCycle =
     339    10640481 :         static_cast<uint16_t>((dayOfCycle - dayOfCycle / 1460 + dayOfCycle / 36524 - dayOfCycle / 146096) / kDaysPerStandardYear);
     340             : 
     341             :     // Compute the relative day with the year.
     342    10640481 :     uint16_t dayOfYear = static_cast<uint16_t>(
     343    10640481 :         dayOfCycle - (yearOfCycle * kDaysPerStandardYear + yearOfCycle / kLeapYearInterval - yearOfCycle / kYearsPerCentury));
     344             : 
     345             :     // Compute a March-based month number (i.e. 0=March...11=February) from the day of year.
     346    10640481 :     month = MarchBasedDayOfYearToMonth(dayOfYear);
     347             : 
     348             :     // Compute the days from March 1st to the start of the corresponding month.
     349    10640481 :     uint16_t daysFromMarch1ToStartOfMonth = MarchBasedMonthToDayOfYear(month);
     350             : 
     351             :     // Compute the day of month in standard form (1=1st, 2=2nd, etc.).
     352    10640481 :     dayOfMonth = static_cast<uint8_t>(dayOfYear - daysFromMarch1ToStartOfMonth + 1);
     353             : 
     354             :     // Convert the month number to standard form (1=January...12=December).
     355    10640481 :     month = static_cast<uint8_t>(month + (month < 10 ? 3 : -9));
     356             : 
     357             :     // Compute the year, adjusting for the standard start of year (January).
     358    10640481 :     year = static_cast<uint16_t>(yearOfCycle + cycle * kYearsPerCycle);
     359    10640481 :     if (month <= kFebruary)
     360     1724993 :         year++;
     361    10640481 :     return true;
     362             : }
     363             : 
     364             : /**
     365             :  *  @def AdjustCalendarDate
     366             :  *
     367             :  *  @brief
     368             :  *    Adjust a calendar date by a given number of days (positive or negative).
     369             :  *
     370             :  *  @param year
     371             :  *    [INPUT/OUTPUT] Gregorian calendar year.
     372             :  *
     373             :  *  @param month
     374             :  *    [INPUT/OUTPUT] Month in standard form (1=January ... 12=December).
     375             :  *
     376             :  *  @param dayOfMonth
     377             :  *    [INPUT/OUTPUT] Day-of-month in standard form (1=1st, 2=2nd, etc.).
     378             :  *
     379             :  *  @param relativeDays
     380             :  *    Number of days to add/subtract from given calendar date.
     381             :  *
     382             :  *  @return
     383             :  *    True if the adjustment succeeded.  False if the adjustment would put us
     384             :  *    outside the representable date range.
     385             :  *
     386             :  *  @note
     387             :  *    Given date must be equal to or greater than 1970-01-01.
     388             :  */
     389           0 : bool AdjustCalendarDate(uint16_t & year, uint8_t & month, uint8_t & dayOfMonth, int32_t relativeDays)
     390             : {
     391             :     uint32_t daysSinceEpoch;
     392           0 :     if (!CalendarDateToDaysSinceUnixEpoch(year, month, dayOfMonth, daysSinceEpoch))
     393             :     {
     394           0 :         return false;
     395             :     }
     396             : 
     397             :     // Make sure we can do our additions without overflowing.
     398           0 :     int64_t adjustedDays = static_cast<int64_t>(daysSinceEpoch) + relativeDays;
     399           0 :     if (!CanCastTo<uint32_t>(adjustedDays))
     400             :     {
     401           0 :         return false;
     402             :     }
     403             : 
     404           0 :     return DaysSinceUnixEpochToCalendarDate(static_cast<uint32_t>(adjustedDays), year, month, dayOfMonth);
     405             : }
     406             : 
     407             : /**
     408             :  *  @def CalendarTimeToSecondsSinceUnixEpoch
     409             :  *
     410             :  *  @brief
     411             :  *    Convert a calendar date and time to the number of seconds since 1970-01-01 00:00:00 UTC.
     412             :  *
     413             :  *  @details
     414             :  *    This function is roughly equivalent to the POSIX gmtime() function with the exception
     415             :  *    that the output time value is limited to positive values up to 2^32-1.  This limits the
     416             :  *    representable date range to the year 2105.
     417             :  *
     418             :  *  @note
     419             :  *    This function makes no attempt to verify the correct range of any arguments other than year.
     420             :  *    Therefore callers must make sure the supplied values are valid prior to invocation.
     421             :  *
     422             :  *  @param secondsSinceEpoch
     423             :  *    Number of seconds since 1970-01-01 00:00:00 UTC.  Note: this value is compatible with
     424             :  *    *positive* values of the POSIX time_t value up to the year 2105.
     425             :  *
     426             :  *  @param year
     427             :  *    Gregorian calendar year in the range 1970 to 2105.
     428             :  *
     429             :  *  @param month
     430             :  *    Month in standard form (1=January ... 12=December).
     431             :  *
     432             :  *  @param dayOfMonth
     433             :  *    Day-of-month in standard form (1=1st, 2=2nd, etc.).
     434             :  *
     435             :  *  @param hour
     436             :  *    Hour (0-23).
     437             :  *
     438             :  *  @param minute
     439             :  *    Minute (0-59).
     440             :  *
     441             :  *  @param second
     442             :  *    Second (0-59).
     443             :  *
     444             :  *  @return
     445             :  *    True if the date/time was converted successfully.  False if the given year falls outside the
     446             :  *    representable range.
     447             :  */
     448      496840 : bool CalendarTimeToSecondsSinceUnixEpoch(uint16_t year, uint8_t month, uint8_t dayOfMonth, uint8_t hour, uint8_t minute,
     449             :                                          uint8_t second, uint32_t & secondsSinceEpoch)
     450             : {
     451             :     uint32_t daysSinceEpoch;
     452             : 
     453             :     // Return immediately if the year is out of range.
     454      496840 :     if (year < kUnixEpochYear || year > kMaxYearInSecondsSinceUnixEpoch32)
     455             :     {
     456           0 :         secondsSinceEpoch = UINT32_MAX;
     457           0 :         return false;
     458             :     }
     459             : 
     460      496840 :     CalendarDateToDaysSinceUnixEpoch(year, month, dayOfMonth, daysSinceEpoch);
     461             : 
     462      496840 :     secondsSinceEpoch = (daysSinceEpoch * kSecondsPerDay) + (hour * kSecondsPerHour) + (minute * kSecondsPerMinute) + second;
     463             : 
     464      496840 :     return true;
     465             : }
     466             : /**
     467             :  *  @brief
     468             :  *    Convert the number of seconds since 1970-01-01 00:00:00 UTC to a calendar date and time.
     469             :  *
     470             :  *  @note
     471             :  *    If secondsSinceEpoch is large enough this function will generate bad result. The way it is
     472             :  *    used in this file the generated result should be valid. Specifically, the largest
     473             :  *    possible value of secondsSinceEpoch input is (UINT32_MAX + kChipEpochSecondsSinceUnixEpoch),
     474             :  *    when it is called from ChipEpochToCalendarTime().
     475             :  */
     476     1032046 : static void SecondsSinceUnixEpochToCalendarTime(uint64_t secondsSinceEpoch, uint16_t & year, uint8_t & month, uint8_t & dayOfMonth,
     477             :                                                 uint8_t & hour, uint8_t & minute, uint8_t & second)
     478             : {
     479     1032046 :     uint32_t daysSinceEpoch = static_cast<uint32_t>(secondsSinceEpoch / kSecondsPerDay);
     480             :     static_assert((static_cast<uint64_t>(UINT32_MAX) + kChipEpochSecondsSinceUnixEpoch) / kSecondsPerDay <=
     481             :                       std::numeric_limits<decltype(daysSinceEpoch)>::max(),
     482             :                   "daysSinceEpoch would overflow");
     483     1032046 :     uint32_t timeOfDay = static_cast<uint32_t>(secondsSinceEpoch - (daysSinceEpoch * kSecondsPerDay));
     484             : 
     485             :     // Note: This call to DaysSinceUnixEpochToCalendarDate can't fail, because we
     486             :     // can't overflow a uint16_t year with a muximum possible value of the
     487             :     // secondsSinceEpoch input.
     488             :     static_assert((static_cast<uint64_t>(UINT32_MAX) + kChipEpochSecondsSinceUnixEpoch) / (kDaysPerStandardYear * kSecondsPerDay) +
     489             :                           1 <=
     490             :                       std::numeric_limits<std::remove_reference<decltype(year)>::type>::max(),
     491             :                   "What happened to our year or day lengths?");
     492     1032046 :     DaysSinceUnixEpochToCalendarDate(daysSinceEpoch, year, month, dayOfMonth);
     493             : 
     494     1032046 :     hour = static_cast<uint8_t>(timeOfDay / kSecondsPerHour);
     495     1032046 :     timeOfDay -= (hour * kSecondsPerHour);
     496     1032046 :     minute = static_cast<uint8_t>(timeOfDay / kSecondsPerMinute);
     497     1032046 :     timeOfDay -= (minute * kSecondsPerMinute);
     498     1032046 :     second = static_cast<uint8_t>(timeOfDay);
     499     1032046 : }
     500             : 
     501             : /**
     502             :  *  @def SecondsSinceUnixEpochToCalendarTime
     503             :  *
     504             :  *  @brief
     505             :  *    Convert the number of seconds since 1970-01-01 00:00:00 UTC to a calendar date and time.
     506             :  *
     507             :  *  @details
     508             :  *    This function is roughly equivalent to the POSIX mktime() function, with the following
     509             :  *    exceptions:
     510             :  *
     511             :  *    - Input time values are limited to positive values up to 2^32-1.  This limits the
     512             :  *    representable date range to the year 2105.
     513             :  *
     514             :  *    - The output time is always UTC (unlike mktime() which outputs time in the process's
     515             :  *    configured timezone).
     516             :  *
     517             :  *  @param secondsSinceEpoch
     518             :  *    Number of seconds since 1970-01-01 00:00:00 UTC.  Note: this value is compatible with
     519             :  *    *positive* values of the POSIX time_t value up to the year 2105.
     520             :  *
     521             :  *  @param year
     522             :  *    [OUTPUT] Gregorian calendar year.
     523             :  *
     524             :  *  @param month
     525             :  *    [OUTPUT] Month in standard form (1=January ... 12=December).
     526             :  *
     527             :  *  @param dayOfMonth
     528             :  *    [OUTPUT] Day-of-month in standard form (1=1st, 2=2nd, etc.).
     529             :  *
     530             :  *  @param hour
     531             :  *    [OUTPUT] Hour (0-23).
     532             :  *
     533             :  *  @param minute
     534             :  *    [OUTPUT] Minute (0-59).
     535             :  *
     536             :  *  @param second
     537             :  *    [OUTPUT] Second (0-59).
     538             :  */
     539      496730 : void SecondsSinceUnixEpochToCalendarTime(uint32_t secondsSinceEpoch, uint16_t & year, uint8_t & month, uint8_t & dayOfMonth,
     540             :                                          uint8_t & hour, uint8_t & minute, uint8_t & second)
     541             : {
     542      496730 :     SecondsSinceUnixEpochToCalendarTime(static_cast<uint64_t>(secondsSinceEpoch), year, month, dayOfMonth, hour, minute, second);
     543      496730 : }
     544             : 
     545      497106 : bool CalendarToChipEpochTime(uint16_t year, uint8_t month, uint8_t dayOfMonth, uint8_t hour, uint8_t minute, uint8_t second,
     546             :                              uint32_t & chipEpochTime)
     547             : {
     548      497106 :     VerifyOrReturnError(year >= kChipEpochBaseYear && year <= kChipEpochMaxYear, false);
     549             : 
     550             :     uint32_t daysSinceUnixEpoch;
     551      497106 :     CalendarDateToDaysSinceUnixEpoch(year, month, dayOfMonth, daysSinceUnixEpoch);
     552             : 
     553      497106 :     chipEpochTime = ((daysSinceUnixEpoch - kChipEpochDaysSinceUnixEpoch) * kSecondsPerDay) + (hour * kSecondsPerHour) +
     554      497106 :         (minute * kSecondsPerMinute) + second;
     555             : 
     556      497106 :     return true;
     557             : }
     558             : 
     559      535316 : void ChipEpochToCalendarTime(uint32_t chipEpochTime, uint16_t & year, uint8_t & month, uint8_t & dayOfMonth, uint8_t & hour,
     560             :                              uint8_t & minute, uint8_t & second)
     561             : {
     562      535316 :     SecondsSinceUnixEpochToCalendarTime(static_cast<uint64_t>(chipEpochTime) + kChipEpochSecondsSinceUnixEpoch, year, month,
     563             :                                         dayOfMonth, hour, minute, second);
     564      535316 : }
     565             : 
     566           0 : bool ChipEpochToUnixEpochMicros(uint64_t chipEpochTimeMicros, uint64_t & outUnixEpochTimeMicros)
     567             : {
     568           0 :     if ((chipEpochTimeMicros + kChipEpochUsSinceUnixEpoch) < kChipEpochUsSinceUnixEpoch)
     569             :     {
     570           0 :         return false;
     571             :     }
     572             : 
     573           0 :     outUnixEpochTimeMicros = chipEpochTimeMicros + kChipEpochUsSinceUnixEpoch;
     574           0 :     return true;
     575             : }
     576             : 
     577           0 : bool UnixEpochToChipEpochMicros(uint64_t unixEpochTimeMicros, uint64_t & outChipEpochTimeMicros)
     578             : {
     579           0 :     VerifyOrReturnValue(unixEpochTimeMicros >= kChipEpochUsSinceUnixEpoch, false);
     580           0 :     outChipEpochTimeMicros = unixEpochTimeMicros - kChipEpochUsSinceUnixEpoch;
     581             : 
     582           0 :     return true;
     583             : }
     584             : 
     585          15 : bool UnixEpochToChipEpochTime(uint32_t unixEpochTimeSeconds, uint32_t & outChipEpochTimeSeconds)
     586             : {
     587          15 :     VerifyOrReturnError(unixEpochTimeSeconds >= kChipEpochSecondsSinceUnixEpoch, false);
     588             : 
     589          15 :     outChipEpochTimeSeconds = unixEpochTimeSeconds - kChipEpochSecondsSinceUnixEpoch;
     590             : 
     591          15 :     return true;
     592             : }
     593             : 
     594             : } // namespace chip

Generated by: LCOV version 1.14