1 //*****************************************************************************
2 //
3 //! @file am_util_time.c
4 //!
5 //! @brief Functions useful for RTC, calendar, time, etc. computations.
6 //!
7 //! @addtogroup time Time - RTC Time Computations
8 //! @ingroup utils
9 //! @{
10 //
11 //*****************************************************************************
12
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision release_sdk_4_4_0-3c5977e664 of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 #include <stdint.h>
48 #include <stdbool.h>
49 #include "am_util_time.h"
50
51 //*****************************************************************************
52 //
53 //! @brief Calculate whether passed in year is a leap year
54 //!
55 //! @param year - year to check for leap year
56 //
57 //*****************************************************************************
58 #define AM_UTIL_TIME_IS_LEAP_YEAR(year) \
59 (year % 4 == 0 && ((year % 100 != 0) || (year % 400 != 0)))
60
61 //*****************************************************************************
62 //
63 // Local variables.
64 //
65 //*****************************************************************************
66
67 //*****************************************************************************
68 //
69 //! Numer of days in each month in a standard year.
70 //
71 //*****************************************************************************
72 const static uint32_t g_iDaysPerMonth[] =
73 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
74
75 //*****************************************************************************
76 //
77 //! Weekday drift numbers for each month.
78 //
79 //*****************************************************************************
80 const static int g_iMonthOffsets[] =
81 {4, 0, 0, 3, 5, 1, 3, 6, 2, 4, 0, 2};
82
83 //*****************************************************************************
84 //
85 // Compute the day of the week given the month, day, and year.
86 //
87 //*****************************************************************************
88 int
am_util_time_computeDayofWeek(int iYear,int iMonth,int iDay)89 am_util_time_computeDayofWeek(int iYear, int iMonth, int iDay)
90 {
91 bool bInvalidDay;
92 int iYearOffset;
93 int iMonthOffset;
94 int iWeekday;
95
96 int iLeapYearOffset = 0;
97
98 //
99 // Validate inputs. Return 7 if any are out-of-bounds.
100 //
101 if ( (iMonth < 1) || (iMonth > 12) || (iYear < 0) || (iDay < 1) )
102 {
103 return 7;
104 }
105
106 //
107 // Make sure this day actually exists in this month. Make sure to include
108 // an exception for leap years.
109 //
110 if (iDay > g_iDaysPerMonth[iMonth - 1])
111 {
112 if (iMonth == 2 && AM_UTIL_TIME_IS_LEAP_YEAR(iYear) && iDay == 29)
113 {
114 bInvalidDay = false;
115 }
116 else
117 {
118 bInvalidDay = true;
119 }
120 }
121 else
122 {
123 bInvalidDay = false;
124 }
125
126 if (bInvalidDay)
127 {
128 return 7;
129 }
130
131 iYearOffset = 2 + iYear + iYear / 4 - iYear / 100 + iYear / 400;
132 iMonthOffset = g_iMonthOffsets[iMonth - 1];
133
134 if (AM_UTIL_TIME_IS_LEAP_YEAR(iYear) && (iMonth < 3))
135 {
136 iLeapYearOffset = -1;
137 }
138
139 iWeekday = iDay + iYearOffset + iMonthOffset + iLeapYearOffset;
140
141 return iWeekday % 7;
142 }
143
144 //*****************************************************************************
145 //
146 // End Doxygen group.
147 //! @}
148 //
149 //*****************************************************************************
150
151