Arduino-RTC
Real-Time Clock (RTC) library for Arduino
gmtime_r.cpp
Go to the documentation of this file.
1 /*
2  * (C)2012 Michael Duane Rice All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer. Redistributions in binary
10  * form must reproduce the above copyright notice, this list of conditions
11  * and the following disclaimer in the documentation and/or other materials
12  * provided with the distribution. Neither the name of the copyright holders
13  * nor the names of contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "time.h"
30 #include <stdlib.h>
31 
32 struct tm*
33 gmtime_r(const time_t * timer, struct tm * timeptr)
34 {
35  int32_t fract;
36  ldiv_t lresult;
37  div_t result;
38  uint16_t days, n, leapyear, years;
39 
40  // Break down timer into whole and fractional parts of 1 day
41  days = *timer / 86400UL;
42  fract = *timer % 86400UL;
43 
44  // Extract hour, minute, and second from the fractional day
45  lresult = ldiv(fract, 60L);
46  timeptr->tm_sec = lresult.rem;
47  result = div(lresult.quot, 60);
48  timeptr->tm_min = result.rem;
49  timeptr->tm_hour = result.quot;
50 
51  // Determine day of week (the epoch was a Saturday)
52  n = days + SATURDAY;
53  n %= 7;
54  timeptr->tm_wday = n;
55 
56  /*
57  * Our epoch year has the property of being at the conjunction of
58  * all three 'leap cycles', 4, 100, and 400 years ( though we can
59  * ignore the 400 year cycle in this library). Using this property,
60  * we can easily 'map' the time stamp into the leap cycles, quickly
61  * deriving the year and day of year, along with the fact of whether
62  * it is a leap year.
63  */
64 
65  // Map into a 100 year cycle
66  lresult = ldiv((long) days, 36525L);
67  years = 100 * lresult.quot;
68 
69  // Map into a 4 year cycle
70  lresult = ldiv(lresult.rem, 1461L);
71  years += 4 * lresult.quot;
72  days = lresult.rem;
73  if (years > 100) days++;
74 
75  /*
76  * 'years' is now at the first year of a 4 year leap cycle, which
77  * will always be a leap year, unless it is 100. 'days' is now an
78  * index into that cycle.
79  */
80  leapyear = 1;
81  if (years == 100) leapyear = 0;
82 
83  // Compute length, in days, of first year of this cycle
84  n = 364 + leapyear;
85 
86  /*
87  * If the number of days remaining is greater than the length of the
88  * first year, we make one more division.
89  */
90  if (days > n) {
91  days -= leapyear;
92  leapyear = 0;
93  result = div(days, 365);
94  years += result.quot;
95  days = result.rem;
96  }
97  timeptr->tm_year = 100 + years;
98  timeptr->tm_yday = days;
99 
100  /*
101  * Given the year, day of year, and leap year indicator, we can
102  * break down the month and day of month. If the day of year is less
103  * than 59 (or 60 if a leap year), then we handle the Jan/Feb month
104  * pair as an exception.
105  */
106  n = 59 + leapyear;
107  if (days < n) {
108  /* special case: Jan/Feb month pair */
109  result = div(days, 31);
110  timeptr->tm_mon = result.quot;
111  timeptr->tm_mday = result.rem;
112  }
113  else {
114  /*
115  * The remaining 10 months form a regular pattern of 31 day months
116  * alternating with 30 day months, with a 'phase change' between
117  * July and August (153 days after March 1). We proceed by mapping
118  * our position into either March-July or August-December.
119  */
120  days -= n;
121  result = div(days, 153);
122  timeptr->tm_mon = 2 + result.quot * 5;
123 
124  // Map into a 61 day pair of months
125  result = div(result.rem, 61);
126  timeptr->tm_mon += result.quot * 2;
127 
128  // Map into a month/
129  result = div(result.rem, 31);
130  timeptr->tm_mon += result.quot;
131  timeptr->tm_mday = result.rem;
132  }
133 
134  // Cleanup and return
135  timeptr->tm_isdst = 0;
136  timeptr->tm_mday++;
137 
138  return (timeptr);
139 }
int8_t tm_mday
Day in Month [1-31].
Definition: time.h:40
int8_t tm_min
Minutes [0-59].
Definition: time.h:38
int16_t tm_yday
days since January 1 [0-365].
Definition: time.h:44
int16_t tm_isdst
Daylight Saving Time flag [-1/0/1].
Definition: time.h:45
struct tm * gmtime_r(const time_t *timer, struct tm *timeptr)
Definition: gmtime_r.cpp:33
int16_t tm_year
Years since 1900.
Definition: time.h:43
int8_t tm_sec
Seconds [0-60].
Definition: time.h:37
uint32_t time_t
Definition: time.h:30
int8_t tm_hour
Hours [0-23].
Definition: time.h:39
Definition: time.h:74
int8_t tm_wday
Days since Sunday [0-6].
Definition: time.h:41
Definition: time.h:36
int8_t tm_mon
0-11 Months since January [0-11].
Definition: time.h:42