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