1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9 #include <time.h>
10 #include <rtthread.h>
11
12 /* days per month -- nonleap! */
13 const short __spm[13] =
14 { 0,
15 (31),
16 (31+28),
17 (31+28+31),
18 (31+28+31+30),
19 (31+28+31+30+31),
20 (31+28+31+30+31+30),
21 (31+28+31+30+31+30+31),
22 (31+28+31+30+31+30+31+31),
23 (31+28+31+30+31+30+31+31+30),
24 (31+28+31+30+31+30+31+31+30+31),
25 (31+28+31+30+31+30+31+31+30+31+30),
26 (31+28+31+30+31+30+31+31+30+31+30+31),
27 };
28 static long int timezone;
29 static const char days[] = "Sun Mon Tue Wed Thu Fri Sat ";
30 static const char months[] = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ";
31
32 /* seconds per day */
33 #define SPD 24*60*60
34
__isleap(int year)35 int __isleap(int year)
36 {
37 /* every fourth year is a leap year except for century years that are
38 * not divisible by 400. */
39 /* return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); */
40 return (!(year % 4) && ((year % 100) || !(year % 400)));
41 }
42
gmtime_r(const time_t * timep,struct tm * r)43 struct tm *gmtime_r(const time_t *timep, struct tm *r)
44 {
45 time_t i;
46 register time_t work = *timep % (SPD);
47 r->tm_sec = work % 60;
48 work /= 60;
49 r->tm_min = work % 60;
50 r->tm_hour = work / 60;
51 work = *timep / (SPD);
52 r->tm_wday = (4 + work) % 7;
53 for (i = 1970;; ++i)
54 {
55 register time_t k = __isleap(i) ? 366 : 365;
56 if (work >= k)
57 work -= k;
58 else
59 break;
60 }
61 r->tm_year = i - 1900;
62 r->tm_yday = work;
63
64 r->tm_mday = 1;
65 if (__isleap(i) && (work > 58))
66 {
67 if (work == 59)
68 r->tm_mday = 2; /* 29.2. */
69 work -= 1;
70 }
71
72 for (i = 11; i && (__spm[i] > work); --i)
73 ;
74 r->tm_mon = i;
75 r->tm_mday += work - __spm[i];
76 return r;
77 }
78
localtime_r(const time_t * t,struct tm * r)79 struct tm* localtime_r(const time_t* t, struct tm* r)
80 {
81 time_t tmp;
82 struct timezone tz = {0};
83 gettimeofday(0, &tz);
84 timezone = tz.tz_minuteswest * 60L;
85 tmp = *t + timezone;
86 return gmtime_r(&tmp, r);
87 }
88
localtime(const time_t * t)89 struct tm* localtime(const time_t* t)
90 {
91 static struct tm tmp;
92 return localtime_r(t, &tmp);
93 }
94
mktime(struct tm * const t)95 time_t mktime(struct tm * const t)
96 {
97 register time_t day;
98 register time_t i;
99 register time_t years = t->tm_year - 70;
100
101 if (t->tm_sec > 60)
102 {
103 t->tm_min += t->tm_sec / 60;
104 t->tm_sec %= 60;
105 }
106 if (t->tm_min > 60)
107 {
108 t->tm_hour += t->tm_min / 60;
109 t->tm_min %= 60;
110 }
111 if (t->tm_hour > 24)
112 {
113 t->tm_mday += t->tm_hour / 24;
114 t->tm_hour %= 24;
115 }
116 if (t->tm_mon > 12)
117 {
118 t->tm_year += t->tm_mon / 12;
119 t->tm_mon %= 12;
120 }
121 while (t->tm_mday > __spm[1 + t->tm_mon])
122 {
123 if (t->tm_mon == 1 && __isleap(t->tm_year + 1900))
124 {
125 --t->tm_mday;
126 }
127 t->tm_mday -= __spm[t->tm_mon];
128 ++t->tm_mon;
129 if (t->tm_mon > 11)
130 {
131 t->tm_mon = 0;
132 ++t->tm_year;
133 }
134 }
135
136 if (t->tm_year < 70)
137 return (time_t) -1;
138
139 /* Days since 1970 is 365 * number of years + number of leap years since 1970 */
140 day = years * 365 + (years + 1) / 4;
141
142 /* After 2100 we have to substract 3 leap years for every 400 years
143 This is not intuitive. Most mktime implementations do not support
144 dates after 2059, anyway, so we might leave this out for it's
145 bloat. */
146 if (years >= 131)
147 {
148 years -= 131;
149 years /= 100;
150 day -= (years >> 2) * 3 + 1;
151 if ((years &= 3) == 3)
152 years--;
153 day -= years;
154 }
155
156 day += t->tm_yday = __spm[t->tm_mon] + t->tm_mday - 1 +
157 (__isleap(t->tm_year + 1900) & (t->tm_mon > 1));
158
159 /* day is now the number of days since 'Jan 1 1970' */
160 i = 7;
161 t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */
162
163 i = 24;
164 day *= i;
165 i = 60;
166 return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec;
167 }
168
num2str(char * c,int i)169 static void num2str(char *c, int i)
170 {
171 c[0] = i / 10 + '0';
172 c[1] = i % 10 + '0';
173 }
174
asctime_r(const struct tm * t,char * buf)175 char *asctime_r(const struct tm *t, char *buf)
176 {
177 /* "Wed Jun 30 21:49:08 1993\n" */
178 *(int*) buf = *(int*) (days + (t->tm_wday << 2));
179 *(int*) (buf + 4) = *(int*) (months + (t->tm_mon << 2));
180 num2str(buf + 8, t->tm_mday);
181 if (buf[8] == '0')
182 buf[8] = ' ';
183 buf[10] = ' ';
184 num2str(buf + 11, t->tm_hour);
185 buf[13] = ':';
186 num2str(buf + 14, t->tm_min);
187 buf[16] = ':';
188 num2str(buf + 17, t->tm_sec);
189 buf[19] = ' ';
190 num2str(buf + 20, (t->tm_year + 1900) / 100);
191 num2str(buf + 22, (t->tm_year + 1900) % 100);
192 buf[24] = '\n';
193 return buf;
194 }
195
asctime(const struct tm * timeptr)196 char *asctime(const struct tm *timeptr)
197 {
198 static char buf[25];
199 return asctime_r(timeptr, buf);
200 }
201
ctime(const time_t * timep)202 char *ctime(const time_t *timep)
203 {
204 return asctime(localtime(timep));
205 }
206
207 #ifdef RT_USING_DEVICE
gettimeofday(struct timeval * tp,void * ignore)208 int gettimeofday(struct timeval *tp, void *ignore)
209 {
210 time_t time;
211 rt_device_t device;
212
213 device = rt_device_find("rtc");
214 if (device != RT_NULL)
215 {
216 rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time);
217 if (tp != RT_NULL)
218 {
219 tp->tv_sec = time;
220 tp->tv_usec = 0;
221 }
222
223 return time;
224 }
225
226 return 0;
227 }
228 #endif
229
230 #ifndef _gettimeofday
231 /* Dummy function when hardware do not have RTC */
_gettimeofday(struct timeval * tv,void * ignore)232 int _gettimeofday( struct timeval *tv, void *ignore)
233 {
234 tv->tv_sec = 0; // convert to seconds
235 tv->tv_usec = 0; // get remaining microseconds
236 return 0; // return non-zero for error
237 }
238 #endif
239
240 /**
241 * Returns the current time.
242 *
243 * @param time_t * t the timestamp pointer, if not used, keep NULL.
244 *
245 * @return time_t return timestamp current.
246 *
247 */
248 /* for IAR 6.2 later Compiler */
249 #if defined (__IAR_SYSTEMS_ICC__) && (__VER__) >= 6020000
250 #pragma module_name = "?time"
time_t(__time32)251 time_t (__time32)(time_t *t) /* Only supports 32-bit timestamp */
252 #else
253 time_t time(time_t *t)
254 #endif
255 {
256 time_t time_now = 0;
257
258 #ifdef RT_USING_RTC
259 static rt_device_t device = RT_NULL;
260
261 /* optimization: find rtc device only first. */
262 if (device == RT_NULL)
263 {
264 device = rt_device_find("rtc");
265 }
266
267 /* read timestamp from RTC device. */
268 if (device != RT_NULL)
269 {
270 if (rt_device_open(device, 0) == RT_EOK)
271 {
272 rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time_now);
273 rt_device_close(device);
274 }
275 }
276 #endif /* RT_USING_RTC */
277
278 /* if t is not NULL, write timestamp to *t */
279 if (t != RT_NULL)
280 {
281 *t = time_now;
282 }
283
284 return time_now;
285 }
286
clock(void)287 RT_WEAK clock_t clock(void)
288 {
289 return rt_tick_get();
290 }
291