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 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 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 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 89 struct tm* localtime(const time_t* t) 90 { 91 static struct tm tmp; 92 return localtime_r(t, &tmp); 93 } 94 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 169 static void num2str(char *c, int i) 170 { 171 c[0] = i / 10 + '0'; 172 c[1] = i % 10 + '0'; 173 } 174 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 196 char *asctime(const struct tm *timeptr) 197 { 198 static char buf[25]; 199 return asctime_r(timeptr, buf); 200 } 201 202 char *ctime(const time_t *timep) 203 { 204 return asctime(localtime(timep)); 205 } 206 207 #ifdef RT_USING_DEVICE 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 */ 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" 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 287 RT_WEAK clock_t clock(void) 288 { 289 return rt_tick_get(); 290 } 291