3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2013-2017 Nest Labs, Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * Various utility functions for dealing with time and dates.
26 #ifndef __STDC_LIMIT_MACROS
27 #define __STDC_LIMIT_MACROS
31 #include <type_traits>
33 #include <core/CHIPCore.h>
34 #include <support/SafeInt.h>
36 #include "TimeUtils.h"
42 // Number of days during the invariant part of the year (after the leap day).
43 kDaysFromMarch1ToDecember31 = 306,
45 // Number of years in a Gregorian "cycle", where a cycle is the 400-year period
46 // over which the Gregorian calendar repeats.
49 // Total number of days within cycle.
50 kDaysPerCycle = 146097,
52 // Total number of days between 0000/03/01 and 1970/01/01.
53 kEpochOffsetDays = 719468
56 /* Returns the number of days between January 1st and March 1st for a given year.
58 static inline uint8_t DaysToMarch1(uint16_t year)
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.).
67 * NOTE: This is based on the math described in http://howardhinnant.github.io/date_algorithms.html.
69 static uint16_t MarchBasedMonthToDayOfYear(uint8_t month)
71 return static_cast<uint16_t>((153 * month + 2) / 5);
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.).
76 static uint8_t MarchBasedDayOfYearToMonth(uint16_t dayOfYear)
78 // This assumes dayOfYear is not using the full uint16_t range, so the cast
79 // to uint8_t doesn't overflow.
80 return static_cast<uint8_t>((5 * dayOfYear + 2) / 153);
87 * Returns true if the given year is a leap year according to the Gregorian calendar.
90 * Gregorian calendar year.
93 bool IsLeapYear(uint16_t year)
95 return (year % kLeapYearInterval) == 0 && ((year % kYearsPerCentury) != 0 || (year % kYearsPerCycle) == 0);
102 * Returns the number of days in the given month/year.
105 * Gregorian calendar year.
108 * Month in standard form (1=January ... 12=December).
111 * Number of days in the given month.
113 uint8_t DaysInMonth(uint16_t year, uint8_t month)
115 static const uint8_t daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
117 if (month == kFebruary && IsLeapYear(year))
119 if (month >= kJanuary && month <= kDecember)
120 return daysInMonth[month - 1];
125 * @def FirstWeekdayOfYear
128 * Returns the day of the week for January 1st of the given year.
131 * Gregorian calendar year.
134 * The day-of-week (0=Sunday...6=Saturday).
136 uint8_t FirstWeekdayOfYear(uint16_t year)
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 (1 + 5 * ((year - 1) % kLeapYearInterval) + 4 * ((year - 1) % kYearsPerCentury) + 6 * ((year - 1) % kYearsPerCycle)) %
145 * @def OrdinalDateToCalendarDate
148 * Convert an ordinal date (year/day-of-year) to a calendar date.
151 * Gregorian calendar year.
154 * Ordinal day of year, base 1 (1=January 1st, 2=January 2nd, etc.).
157 * [OUTPUT] Corresponding month in standard form (1=January ... 12=December).
160 * [OUTPUT] Corresponding day-of-month in standard form (1=1st, 2=2nd, etc.).
163 void OrdinalDateToCalendarDate(uint16_t year, uint16_t dayOfYear, uint8_t & month, uint8_t & dayOfMonth)
165 uint8_t daysToMarch1 = DaysToMarch1(year);
167 // Make dayOfYear base 0.
168 dayOfYear = static_cast<uint16_t>(dayOfYear - 1);
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 if (dayOfYear < daysToMarch1)
174 dayOfYear = static_cast<uint16_t>(dayOfYear + kDaysFromMarch1ToDecember31);
176 dayOfYear = static_cast<uint16_t>(dayOfYear - daysToMarch1);
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 month = MarchBasedDayOfYearToMonth(dayOfYear);
182 // Compute the days from March 1st to the start of the corresponding month.
183 uint16_t daysFromMarch1ToStartOfMonth = MarchBasedMonthToDayOfYear(month);
185 // Compute the day of month in standard form (1=1st, 2=2nd, etc.).
186 dayOfMonth = static_cast<uint8_t>(dayOfYear - daysFromMarch1ToStartOfMonth + 1);
188 // Convert the month number to standard form (1=January...12=December).
189 month = static_cast<uint8_t>(month + (month < 10 ? 3 : -9));
193 * @def CalendarDateToOrdinalDate
196 * Convert an calendar date to ordinal form (year/day-of-year).
199 * Gregorian calendar year.
202 * Month in standard form (1=January ... 12=December).
205 * Day-of-month in standard form (1=1st, 2=2nd, etc.).
208 * [OUTPUT] Ordinal day of year, base 1 (1=January 1st, 2=January 2nd, etc.).
211 void CalendarDateToOrdinalDate(uint16_t year, uint8_t month, uint8_t dayOfMonth, uint16_t & dayOfYear)
213 // Convert month to a March-based month number (i.e. 0=March, 1=April, ...11=February).
214 month = static_cast<uint8_t>(month + (month > kFebruary ? -3 : 9));
216 // Compute the days from March 1st to the start of the corresponding month.
217 dayOfYear = MarchBasedMonthToDayOfYear(month);
219 // Adjust dayOfYear to be January-based (0=January 1st, 1=January 2nd...).
220 if (dayOfYear < kDaysFromMarch1ToDecember31)
221 dayOfYear = static_cast<uint16_t>(dayOfYear + DaysToMarch1(year));
223 dayOfYear = static_cast<uint16_t>(dayOfYear - kDaysFromMarch1ToDecember31);
225 // Add in day of month, converting to base 1 in the process.
226 dayOfYear = static_cast<uint16_t>(dayOfYear + dayOfMonth);
230 * @def CalendarDateToDaysSinceEpoch
233 * Convert a calendar date to the number of days since 1970-01-01.
236 * Gregorian calendar year in the range 1970 to 28276.
239 * Month in standard form (1=January ... 12=December).
242 * Day-of-month in standard form (1=1st, 2=2nd, etc.).
244 * @param daysSinceEpoch
245 * [OUTPUT] Number of days since 1970-01-01.
248 * True if the date was converted successfully. False if the given year falls outside the
249 * representable range.
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.
255 bool CalendarDateToDaysSinceEpoch(uint16_t year, uint8_t month, uint8_t dayOfMonth, uint32_t & daysSinceEpoch)
257 // NOTE: This algorithm is based on the logic described in http://howardhinnant.github.io/date_algorithms.html.
259 // Return immediately if the year is out of range.
260 if (year < kEpochYear || year > kMaxYearInDaysSinceEpoch32)
262 daysSinceEpoch = UINT32_MAX;
266 // Adjust the year and month to be March-based (i.e. 0=March, 1=April, ...11=February).
267 if (month <= kFebruary)
270 month = static_cast<uint8_t>(month + 9);
273 month = static_cast<uint8_t>(month - 3);
275 // Compute the days from March 1st to the start of the specified day.
276 uint16_t dayOfYear = static_cast<uint16_t>(MarchBasedMonthToDayOfYear(month) + (dayOfMonth - 1));
278 // Compute the 400-year Gregorian "cycle" within which the given year falls.
279 uint16_t cycle = static_cast<uint16_t>(year / kYearsPerCycle);
281 // Compute the relative year within the cycle.
282 uint32_t yearOfCycle = year - (cycle * kYearsPerCycle);
284 // Compute the relative day within the cycle, accounting for leap-years.
285 uint32_t dayOfCycle =
286 (yearOfCycle * kDaysPerStandardYear) + dayOfYear - (yearOfCycle / kYearsPerCentury) + (yearOfCycle / kLeapYearInterval);
288 // Compute the total number of days since the start of the logical calendar (0000-03-01).
289 uint32_t daysSinceCalendarStart = (cycle * kDaysPerCycle) + dayOfCycle;
291 // Adjust the days value to be days since 1970-01-01.
292 daysSinceEpoch = daysSinceCalendarStart - kEpochOffsetDays;
298 * @def DaysSinceEpochToCalendarDate
301 * Convert the number of days since 1970-01-01 to a calendar date.
303 * @param daysSinceEpoch
304 * Number of days since 1970-01-01.
307 * [OUTPUT] Gregorian calendar year.
310 * [OUTPUT] Month in standard form (1=January ... 12=December).
313 * [OUTPUT] Day-of-month in standard form (1=1st, 2=2nd, etc.).
316 * True if the conversion was successful. False if the year would not fit
319 bool DaysSinceEpochToCalendarDate(uint32_t daysSinceEpoch, uint16_t & year, uint8_t & month, uint8_t & dayOfMonth)
321 // NOTE: This algorithm is based on the logic described in http://howardhinnant.github.io/date_algorithms.html.
322 if (daysSinceEpoch / kDaysPerStandardYear + 1 > std::numeric_limits<std::remove_reference<decltype(year)>::type>::max())
324 // Our year calculation will likely overflow.
328 // Adjust days value to be relative to 0000-03-01.
329 daysSinceEpoch += kEpochOffsetDays;
331 // Compute the 400-year Gregorian cycle in which the given day resides.
332 uint32_t cycle = daysSinceEpoch / kDaysPerCycle;
334 // Compute the relative day within the cycle.
335 uint32_t dayOfCycle = daysSinceEpoch - (cycle * kDaysPerCycle);
337 // Compute the relative year within the cycle, adjusting for leap-years.
338 uint16_t yearOfCycle =
339 static_cast<uint16_t>((dayOfCycle - dayOfCycle / 1460 + dayOfCycle / 36524 - dayOfCycle / 146096) / kDaysPerStandardYear);
341 // Compute the relative day with the year.
342 uint16_t dayOfYear = static_cast<uint16_t>(
343 dayOfCycle - (yearOfCycle * kDaysPerStandardYear + yearOfCycle / kLeapYearInterval - yearOfCycle / kYearsPerCentury));
345 // Compute a March-based month number (i.e. 0=March...11=February) from the day of year.
346 month = MarchBasedDayOfYearToMonth(dayOfYear);
348 // Compute the days from March 1st to the start of the corresponding month.
349 uint16_t daysFromMarch1ToStartOfMonth = MarchBasedMonthToDayOfYear(month);
351 // Compute the day of month in standard form (1=1st, 2=2nd, etc.).
352 dayOfMonth = static_cast<uint8_t>(dayOfYear - daysFromMarch1ToStartOfMonth + 1);
354 // Convert the month number to standard form (1=January...12=December).
355 month = static_cast<uint8_t>(month + (month < 10 ? 3 : -9));
357 // Compute the year, adjusting for the standard start of year (January).
358 year = static_cast<uint16_t>(yearOfCycle + cycle * kYearsPerCycle);
359 if (month <= kFebruary)
365 * @def AdjustCalendarDate
368 * Adjust a calendar date by a given number of days (positive or negative).
371 * [INPUT/OUTPUT] Gregorian calendar year.
374 * [INPUT/OUTPUT] Month in standard form (1=January ... 12=December).
377 * [INPUT/OUTPUT] Day-of-month in standard form (1=1st, 2=2nd, etc.).
379 * @param relativeDays
380 * Number of days to add/subtract from given calendar date.
383 * True if the adjustment succeeded. False if the adjustment would put us
384 * outside the representable date range.
387 * Given date must be equal to or greater than 1970-01-01.
389 bool AdjustCalendarDate(uint16_t & year, uint8_t & month, uint8_t & dayOfMonth, int32_t relativeDays)
391 uint32_t daysSinceEpoch;
392 if (!CalendarDateToDaysSinceEpoch(year, month, dayOfMonth, daysSinceEpoch))
397 // Make sure we can do our additions without overflowing.
398 int64_t adjustedDays = static_cast<int64_t>(daysSinceEpoch) + relativeDays;
399 if (!CanCastTo<uint32_t>(adjustedDays))
404 return DaysSinceEpochToCalendarDate(static_cast<uint32_t>(adjustedDays), year, month, dayOfMonth);
408 * @def CalendarTimeToSecondsSinceEpoch
411 * Convert a calendar date and time to the number of seconds since 1970-01-01 00:00:00 UTC.
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.
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.
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.
427 * Gregorian calendar year in the range 1970 to 2105.
430 * Month in standard form (1=January ... 12=December).
433 * Day-of-month in standard form (1=1st, 2=2nd, etc.).
445 * True if the date/time was converted successfully. False if the given year falls outside the
446 * representable range.
448 bool CalendarTimeToSecondsSinceEpoch(uint16_t year, uint8_t month, uint8_t dayOfMonth, uint8_t hour, uint8_t minute, uint8_t second,
449 uint32_t & secondsSinceEpoch)
451 uint32_t daysSinceEpoch;
453 // Return immediately if the year is out of range.
454 if (year < kEpochYear || year > kMaxYearInSecondsSinceEpoch32)
456 secondsSinceEpoch = UINT32_MAX;
460 CalendarDateToDaysSinceEpoch(year, month, dayOfMonth, daysSinceEpoch);
462 secondsSinceEpoch = (daysSinceEpoch * kSecondsPerDay) + (hour * kSecondsPerHour) + (minute * kSecondsPerMinute) + second;
468 * Convert the number of seconds since 1970-01-01 00:00:00 UTC to a calendar date and time.
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().
476 static void SecondsSinceEpochToCalendarTime(uint64_t secondsSinceEpoch, uint16_t & year, uint8_t & month, uint8_t & dayOfMonth,
477 uint8_t & hour, uint8_t & minute, uint8_t & second)
479 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 uint32_t timeOfDay = static_cast<uint32_t>(secondsSinceEpoch - (daysSinceEpoch * kSecondsPerDay));
485 // Note: This call to DaysSinceEpochToCalendarDate 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) +
490 std::numeric_limits<std::remove_reference<decltype(year)>::type>::max(),
491 "What happened to our year or day lengths?");
492 DaysSinceEpochToCalendarDate(daysSinceEpoch, year, month, dayOfMonth);
494 hour = static_cast<uint8_t>(timeOfDay / kSecondsPerHour);
495 timeOfDay -= (hour * kSecondsPerHour);
496 minute = static_cast<uint8_t>(timeOfDay / kSecondsPerMinute);
497 timeOfDay -= (minute * kSecondsPerMinute);
498 second = static_cast<uint8_t>(timeOfDay);
502 * @def SecondsSinceEpochToCalendarTime
505 * Convert the number of seconds since 1970-01-01 00:00:00 UTC to a calendar date and time.
508 * This function is roughly equivalent to the POSIX mktime() function, with the following
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.
514 * - The output time is always UTC (unlike mktime() which outputs time in the process's
515 * configured timezone).
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.
522 * [OUTPUT] Gregorian calendar year.
525 * [OUTPUT] Month in standard form (1=January ... 12=December).
528 * [OUTPUT] Day-of-month in standard form (1=1st, 2=2nd, etc.).
531 * [OUTPUT] Hour (0-23).
534 * [OUTPUT] Minute (0-59).
537 * [OUTPUT] Second (0-59).
539 void SecondsSinceEpochToCalendarTime(uint32_t secondsSinceEpoch, uint16_t & year, uint8_t & month, uint8_t & dayOfMonth,
540 uint8_t & hour, uint8_t & minute, uint8_t & second)
542 SecondsSinceEpochToCalendarTime(static_cast<uint64_t>(secondsSinceEpoch), year, month, dayOfMonth, hour, minute, second);
545 bool CalendarToChipEpochTime(uint16_t year, uint8_t month, uint8_t dayOfMonth, uint8_t hour, uint8_t minute, uint8_t second,
546 uint32_t & chipEpochTime)
549 uint32_t daysSinceUnixEpoch;
551 VerifyOrExit(year >= kChipEpochBaseYear && year <= kChipEpochMaxYear, res = false);
553 CalendarDateToDaysSinceEpoch(year, month, dayOfMonth, daysSinceUnixEpoch);
555 chipEpochTime = ((daysSinceUnixEpoch - kChipEpochDaysSinceUnixEpoch) * kSecondsPerDay) + (hour * kSecondsPerHour) +
556 (minute * kSecondsPerMinute) + second;
562 void ChipEpochToCalendarTime(uint32_t chipEpochTime, uint16_t & year, uint8_t & month, uint8_t & dayOfMonth, uint8_t & hour,
563 uint8_t & minute, uint8_t & second)
565 SecondsSinceEpochToCalendarTime(static_cast<uint64_t>(chipEpochTime) + kChipEpochSecondsSinceUnixEpoch, year, month, dayOfMonth,
566 hour, minute, second);
569 bool UnixEpochToChipEpochTime(uint32_t unixEpochTime, uint32_t & chipEpochTime)
573 VerifyOrExit(unixEpochTime >= kChipEpochSecondsSinceUnixEpoch, res = false);
575 chipEpochTime = unixEpochTime - kChipEpochSecondsSinceUnixEpoch;