1 /*
2 Low Level Interface Library
3 Copyright 1983-2007 Green Hills Software,Inc.
4
5 * This program is the property of Green Hills Software, Inc,
6 * its contents are proprietary information and no part of it
7 * is to be disclosed to anyone except employees of Green Hills
8 * Software, Inc., or as agreed in writing signed by the President
9 * of Green Hills Software, Inc.
10 */
11 /* ind_gmtm.c: ANSI gmtime() facility. */
12
13 #include <limits.h>
14 #include "indos.h"
15 #include "ind_thrd.h"
16
17 #if defined(CROSSUNIX) || !defined(ANYUNIX)
18
19 static const char mons[]={31,28,31,30,31,30,31,31,30,31,30};
20 /******************************************************************************/
21 /* #include <time.h> */
22 /* struct tm *gmtime(const time_t *timer); */
23 /* */
24 /* gmtime returns a structure containing the current Greenwich Mean Time */
25 /* broken down into tm_year (current year - 1900), tm_mon (current month */
26 /* January=0), tm_mday (current day of month), tm_hour (current hour 24 hour */
27 /* time), tm_min (current minute), and tm_sec (current second). */
28 /* */
29 /* timer is a pointer to a long containing the number of seconds since the */
30 /* Epoch (as set by time()). */
31 /* */
32 /* Return 0 if no time of day can be returned */
33 /* */
34 /* NOT REENTRANT because it returns the address of a static buffer */
35 /* could be made reentrant if every call to gmtime allocated a new structure */
36 /******************************************************************************/
37
38 #define SECS_IN_MIN ((time_t)60)
39 #define MINS_IN_HOUR ((time_t)60)
40 #define SECS_IN_HOUR (MINS_IN_HOUR * SECS_IN_MIN)
41 #define HOURS_IN_DAY ((time_t)24)
42 #define SECS_IN_DAY (HOURS_IN_DAY * SECS_IN_HOUR)
43 #define DAYS_IN_WEEK ((time_t)7)
44
45 #define DAYS_IN_COMMON_YEAR ((time_t)365)
46 #define DAYS_IN_400_YEARS (DAYS_IN_COMMON_YEAR * 400 + 97)
47
gmtime_r(const time_t * timer,struct tm * result)48 struct tm *gmtime_r(const time_t *timer, struct tm *result) {
49 /* If no other implementation provided, assume Epoch is 00:00:00 January 1,1970
50 as is true in UNIX.
51 */
52 time_t time_v = *timer;
53 int i, m, islpyr;
54 time_t y, t, s;
55
56 if (time_v == (time_t)-1)
57 return NULL;
58
59 #if defined(MSW) || defined(MSDOS)
60 time_v -= 2209075200L; /* convert to Epoch from MS-DOS */
61 #endif
62
63 result->tm_isdst = 0;
64 /* Compute t as a Julian day number, where the Epoch is 0 */
65 /* and compute s as the seconds within the day */
66 t = time_v / SECS_IN_DAY;
67 s = time_v % SECS_IN_DAY;
68 if (s < 0) {
69 s += SECS_IN_DAY;
70 t--;
71 }
72
73 /* hour, minute, second */
74 result->tm_hour = s / SECS_IN_HOUR;
75 s %= SECS_IN_HOUR;
76 result->tm_min = s / SECS_IN_MIN;
77 result->tm_sec = s % SECS_IN_MIN;
78
79 /* January 1, 1970 was a Thursday. */
80 s = (t + 4) % DAYS_IN_WEEK;
81 if (s < 0) {
82 s += DAYS_IN_WEEK;
83 }
84 result->tm_wday = s;
85
86 /* If 1900 does not fall within range, things are very simple because */
87 /* every 4 years is a leap year. */
88 if (DAYS_IN_COMMON_YEAR * 69 > LONG_MAX / SECS_IN_DAY) {
89 /* Adjust so that 0 is Dec 31, 1899, which is as though 0 is */
90 /* Jan 1, 1900 and 1900 is a leap year. This ensures that t is */
91 /* positive and makes it as though every 4 years is a leap year. */
92 /* (since t will not *actually* fall within 1900, we're fine) */
93
94 /* Thus, note that there were 17 leap days between Jan 1, 1900 and */
95 /* Jan 1, 1970 */
96 t += DAYS_IN_COMMON_YEAR * 70 + 18;
97
98 /* Compute y as the year, and t as the day within the year */
99 y = t / (DAYS_IN_COMMON_YEAR * 4 + 1) * 4;
100 t = t % (DAYS_IN_COMMON_YEAR * 4 + 1);
101 if (t >= DAYS_IN_COMMON_YEAR + 1) {
102 y += (t - 1) / DAYS_IN_COMMON_YEAR;
103 t = (t - 1) % DAYS_IN_COMMON_YEAR;
104 }
105 islpyr = (y & 3) == 0;
106 /* Note that we already adjusted so that 1900 is zero. */
107 } else {
108 time_t century;
109 /* Adjust to the beginning of a 400 year cycle, the year 2000 */
110 /* There were 7 leap days between Jan 1, 1970 and Jan 1, 2000 */
111 t -= DAYS_IN_COMMON_YEAR * 30 + 7;
112
113 /* Compute the century except for the low 2 bits, where 0 is 2000 */
114 /* e.g., -4 is 1600 to 1999, 0 is 2000 to 2399, etc. */
115 /* Adjust t so that the beginning of the 400 year cycle is 0 */
116 century = t / DAYS_IN_400_YEARS * 4;
117 t %= DAYS_IN_400_YEARS;
118 if (t < 0) {
119 t += DAYS_IN_400_YEARS;
120 century -= 4;
121 }
122
123 /* Add in the low 2 bits of the century and adjust t so that the */
124 /* beginning of the century is 0, and so that all 4 year cycles have */
125 /* an extra day in the first year. That is, 366 is always the start */
126 /* of the second year in the century, but some centuries have no day */
127 /* 365. */
128 if (t >= DAYS_IN_COMMON_YEAR * 100 + 25) {
129 century += (t - 1) / (DAYS_IN_COMMON_YEAR * 100 + 24);
130 t = (t - 1) % (DAYS_IN_COMMON_YEAR * 100 + 24);
131 if (t >= DAYS_IN_COMMON_YEAR) {
132 t++;
133 }
134 }
135
136 /* Compute y as the year within the century, and t as the day within */
137 /* the year */
138 y = t / (DAYS_IN_COMMON_YEAR * 4 + 1) * 4;
139 t = t % (DAYS_IN_COMMON_YEAR * 4 + 1);
140 if (t >= DAYS_IN_COMMON_YEAR + 1) {
141 y += (t - 1) / DAYS_IN_COMMON_YEAR;
142 t = (t - 1) % DAYS_IN_COMMON_YEAR;
143 }
144
145 islpyr = (y & 3) == 0 && (y != 0 || (century & 3) == 0);
146 /* Right now 2000 is 0, but we must return 1900 as 0. */
147 y += (century + 1) * 100;
148 /* If time_t is 64-bit, the year might not fit in an int, and we */
149 /* must return NULL. */
150 if (y != (int)y) {
151 return NULL;
152 }
153 }
154 result->tm_year = y;
155 result->tm_yday = t;
156
157 /* Increment to return an mday in the 1 to 31 range. */
158 t++;
159 for (i = 0; i < 11; i++) {
160 m = mons[i];
161 if (i == 1 && islpyr) {
162 m++;
163 }
164 if (t <= m)
165 break;
166 t -= m;
167 }
168
169 result->tm_mon = i;
170 result->tm_mday = t; /* we incremented the mday above */
171 return result;
172 }
173
174 struct tm __ghs_static_gmtime_temp;
gmtime(const time_t * timer)175 struct tm *gmtime(const time_t *timer)
176 {
177
178 struct tm *tmp = __ghs_GetThreadLocalStorageItem(__ghs_TLS_gmtime_temp);
179 if (tmp == NULL)
180 tmp = &__ghs_static_gmtime_temp;
181 return(gmtime_r(timer, tmp));
182 }
183 #else
184 int _J_empty_file_illegal;
185 #endif /* CROSSUNIX or !ANYUNIX */
186