]>
Commit | Line | Data |
---|---|---|
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 | /* $Id: gmtime_r.c 2369 2013-04-28 14:19:35Z swfltek $ */ | |
30 | ||
31 | /* Re entrant version of gmtime(). */ | |
32 | ||
33 | #include <time.h> | |
34 | #include <stdlib.h> | |
35 | #include <inttypes.h> | |
36 | ||
37 | void | |
38 | gmtime_r(const time_t * timer, struct tm * timeptr) | |
39 | { | |
40 | int32_t fract; | |
41 | ldiv_t lresult; | |
42 | div_t result; | |
43 | uint16_t days, n, leapyear, years; | |
44 | ||
45 | /* break down timer into whole and fractional parts of 1 day */ | |
46 | days = *timer / 86400UL; | |
47 | fract = *timer % 86400UL; | |
48 | ||
49 | /* | |
50 | Extract hour, minute, and second from the fractional day | |
51 | */ | |
52 | lresult = ldiv(fract, 60L); | |
53 | timeptr->tm_sec = lresult.rem; | |
54 | result = div(lresult.quot, 60); | |
55 | timeptr->tm_min = result.rem; | |
56 | timeptr->tm_hour = result.quot; | |
57 | ||
58 | /* Determine day of week ( the epoch was a Saturday ) */ | |
59 | n = days + SATURDAY; | |
60 | n %= 7; | |
61 | timeptr->tm_wday = n; | |
62 | ||
63 | /* | |
64 | * Our epoch year has the property of being at the conjunction of all three 'leap cycles', | |
65 | * 4, 100, and 400 years ( though we can ignore the 400 year cycle in this library). | |
66 | * | |
67 | * Using this property, we can easily 'map' the time stamp into the leap cycles, quickly | |
68 | * deriving the year and day of year, along with the fact of whether it is a leap year. | |
69 | */ | |
70 | ||
71 | /* map into a 100 year cycle */ | |
72 | lresult = ldiv((long) days, 36525L); | |
73 | years = 100 * lresult.quot; | |
74 | ||
75 | /* map into a 4 year cycle */ | |
76 | lresult = ldiv(lresult.rem, 1461L); | |
77 | years += 4 * lresult.quot; | |
78 | days = lresult.rem; | |
79 | if (years > 100) | |
80 | days++; | |
81 | ||
82 | /* | |
83 | * 'years' is now at the first year of a 4 year leap cycle, which will always be a leap year, | |
84 | * unless it is 100. 'days' is now an index into that cycle. | |
85 | */ | |
86 | leapyear = 1; | |
87 | if (years == 100) | |
88 | leapyear = 0; | |
89 | ||
90 | /* compute length, in days, of first year of this cycle */ | |
91 | n = 364 + leapyear; | |
92 | ||
93 | /* | |
94 | * if the number of days remaining is greater than the length of the | |
95 | * first year, we make one more division. | |
96 | */ | |
97 | if (days > n) { | |
98 | days -= leapyear; | |
99 | leapyear = 0; | |
100 | result = div(days, 365); | |
101 | years += result.quot; | |
102 | days = result.rem; | |
103 | } | |
104 | timeptr->tm_year = 100 + years; | |
105 | timeptr->tm_yday = days; | |
106 | ||
107 | /* | |
108 | Given the year, day of year, and leap year indicator, we can break down the | |
109 | month and day of month. If the day of year is less than 59 (or 60 if a leap year), then | |
110 | we handle the Jan/Feb month pair as an exception. | |
111 | */ | |
112 | n = 59 + leapyear; | |
113 | if (days < n) { | |
114 | /* special case: Jan/Feb month pair */ | |
115 | result = div(days, 31); | |
116 | timeptr->tm_mon = result.quot; | |
117 | timeptr->tm_mday = result.rem; | |
118 | } else { | |
119 | /* | |
120 | The remaining 10 months form a regular pattern of 31 day months alternating with 30 day | |
121 | months, with a 'phase change' between July and August (153 days after March 1). | |
122 | We proceed by mapping our position into either March-July or August-December. | |
123 | */ | |
124 | days -= n; | |
125 | result = div(days, 153); | |
126 | timeptr->tm_mon = 2 + result.quot * 5; | |
127 | ||
128 | /* map into a 61 day pair of months */ | |
129 | result = div(result.rem, 61); | |
130 | timeptr->tm_mon += result.quot * 2; | |
131 | ||
132 | /* map into a month */ | |
133 | result = div(result.rem, 31); | |
134 | timeptr->tm_mon += result.quot; | |
135 | timeptr->tm_mday = result.rem; | |
136 | } | |
137 | ||
138 | /* | |
139 | Cleanup and return | |
140 | */ | |
141 | timeptr->tm_isdst = 0; /* gmt is never in DST */ | |
142 | timeptr->tm_mday++; /* tm_mday is 1 based */ | |
143 | ||
144 | } |