msvcrt: Enable multi-thread locking by default.
[wine.git] / dlls / msvcrt / time.c
blobadf57104317a06b1d61abd67830d529abf07462f
1 /*
2 * msvcrt.dll date/time functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
8 * Copyright 2004 Hans Leidekker
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
27 #include <stdlib.h>
29 #include "msvcrt.h"
30 #include "mtdll.h"
31 #include "winbase.h"
32 #include "winnls.h"
33 #include "winternl.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
38 BOOL WINAPI GetDaylightFlag(void);
40 static LONGLONG init_time;
42 void msvcrt_init_clock(void)
44 LARGE_INTEGER systime;
46 NtQuerySystemTime(&systime);
47 init_time = systime.QuadPart;
50 static const int MonthLengths[2][12] =
52 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
53 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
56 #if _MSVCR_VER>=140
57 static const int MAX_SECONDS = 60;
58 #else
59 static const int MAX_SECONDS = 59;
60 #endif
62 static inline BOOL IsLeapYear(int Year)
64 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
67 static inline void write_invalid_msvcrt_tm( struct MSVCRT_tm *tm )
69 tm->tm_sec = -1;
70 tm->tm_min = -1;
71 tm->tm_hour = -1;
72 tm->tm_mday = -1;
73 tm->tm_mon = -1;
74 tm->tm_year = -1;
75 tm->tm_wday = -1;
76 tm->tm_yday = -1;
77 tm->tm_isdst = -1;
80 /*********************************************************************
81 * _daylight (MSVCRT.@)
83 int MSVCRT___daylight = 1;
85 /*********************************************************************
86 * _timezone (MSVCRT.@)
88 MSVCRT_long MSVCRT___timezone = 28800;
90 /*********************************************************************
91 * _dstbias (MSVCRT.@)
93 int MSVCRT__dstbias = -3600;
95 /*********************************************************************
96 * _tzname (MSVCRT.@)
97 * NOTES
98 * Some apps (notably Mozilla) insist on writing to these, so the buffer
99 * must be large enough.
101 static char tzname_std[64] = "PST";
102 static char tzname_dst[64] = "PDT";
103 char *MSVCRT__tzname[2] = { tzname_std, tzname_dst };
105 static TIME_ZONE_INFORMATION tzi = {0};
106 /*********************************************************************
107 * _tzset (MSVCRT.@)
109 void CDECL MSVCRT__tzset(void)
111 char *tz = MSVCRT_getenv("TZ");
112 BOOL error;
114 _lock(_TIME_LOCK);
115 if(tz && tz[0]) {
116 BOOL neg_zone = FALSE;
118 memset(&tzi, 0, sizeof(tzi));
120 /* Parse timezone information: tzn[+|-]hh[:mm[:ss]][dzn] */
121 lstrcpynA(MSVCRT__tzname[0], tz, 3);
122 tz += 3;
124 if(*tz == '-') {
125 neg_zone = TRUE;
126 tz++;
127 }else if(*tz == '+') {
128 tz++;
130 MSVCRT___timezone = MSVCRT_strtol(tz, &tz, 10)*3600;
131 if(*tz == ':') {
132 MSVCRT___timezone += MSVCRT_strtol(tz+1, &tz, 10)*60;
133 if(*tz == ':')
134 MSVCRT___timezone += MSVCRT_strtol(tz+1, &tz, 10);
136 if(neg_zone)
137 MSVCRT___timezone = -MSVCRT___timezone;
139 MSVCRT___daylight = *tz;
140 lstrcpynA(MSVCRT__tzname[1], tz, 3);
141 }else if(GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
142 MSVCRT___timezone = tzi.Bias*60;
143 if(tzi.StandardDate.wMonth)
144 MSVCRT___timezone += tzi.StandardBias*60;
146 if(tzi.DaylightDate.wMonth) {
147 MSVCRT___daylight = 1;
148 MSVCRT__dstbias = (tzi.DaylightBias-tzi.StandardBias)*60;
149 }else {
150 MSVCRT___daylight = 0;
151 MSVCRT__dstbias = 0;
154 if(!WideCharToMultiByte(CP_ACP, 0, tzi.StandardName, -1, MSVCRT__tzname[0],
155 sizeof(tzname_std), NULL, &error) || error)
156 *MSVCRT__tzname[0] = 0;
157 if(!WideCharToMultiByte(CP_ACP, 0, tzi.DaylightName, -1, MSVCRT__tzname[1],
158 sizeof(tzname_dst), NULL, &error) || error)
159 *MSVCRT__tzname[0] = 0;
161 _unlock(_TIME_LOCK);
164 static void _tzset_init(void)
166 static BOOL init = FALSE;
168 if(!init) {
169 _lock(_TIME_LOCK);
170 if(!init) {
171 MSVCRT__tzset();
172 init = TRUE;
174 _unlock(_TIME_LOCK);
178 static BOOL is_dst(const SYSTEMTIME *st)
180 TIME_ZONE_INFORMATION tmp;
181 SYSTEMTIME out;
183 if(!MSVCRT___daylight)
184 return FALSE;
186 if(tzi.DaylightDate.wMonth) {
187 tmp = tzi;
188 }else if(st->wYear >= 2007) {
189 memset(&tmp, 0, sizeof(tmp));
190 tmp.StandardDate.wMonth = 11;
191 tmp.StandardDate.wDay = 1;
192 tmp.StandardDate.wHour = 2;
193 tmp.DaylightDate.wMonth = 3;
194 tmp.DaylightDate.wDay = 2;
195 tmp.DaylightDate.wHour = 2;
196 }else {
197 memset(&tmp, 0, sizeof(tmp));
198 tmp.StandardDate.wMonth = 10;
199 tmp.StandardDate.wDay = 5;
200 tmp.StandardDate.wHour = 2;
201 tmp.DaylightDate.wMonth = 4;
202 tmp.DaylightDate.wDay = 1;
203 tmp.DaylightDate.wHour = 2;
206 tmp.Bias = 0;
207 tmp.StandardBias = 0;
208 tmp.DaylightBias = MSVCRT__dstbias/60;
209 if(!SystemTimeToTzSpecificLocalTime(&tmp, st, &out))
210 return FALSE;
212 return memcmp(st, &out, sizeof(SYSTEMTIME));
215 #define SECSPERDAY 86400
216 /* 1601 to 1970 is 369 years plus 89 leap days */
217 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
218 #define TICKSPERSEC 10000000
219 #define TICKSPERMSEC 10000
220 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
222 static MSVCRT___time64_t mktime_helper(struct MSVCRT_tm *mstm, BOOL local)
224 SYSTEMTIME st;
225 FILETIME ft;
226 MSVCRT___time64_t ret = 0;
227 int i;
228 BOOL use_dst = FALSE;
230 ret = mstm->tm_year + mstm->tm_mon/12;
231 mstm->tm_mon %= 12;
232 if(mstm->tm_mon < 0) {
233 mstm->tm_mon += 12;
234 ret--;
237 if(ret<70 || ret>1100) {
238 *MSVCRT__errno() = MSVCRT_EINVAL;
239 return -1;
242 memset(&st, 0, sizeof(SYSTEMTIME));
243 st.wDay = 1;
244 st.wMonth = mstm->tm_mon+1;
245 st.wYear = ret+1900;
247 if(!SystemTimeToFileTime(&st, &ft)) {
248 *MSVCRT__errno() = MSVCRT_EINVAL;
249 return -1;
252 ret = ((MSVCRT___time64_t)ft.dwHighDateTime<<32)+ft.dwLowDateTime;
253 ret += (MSVCRT___time64_t)mstm->tm_sec*TICKSPERSEC;
254 ret += (MSVCRT___time64_t)mstm->tm_min*60*TICKSPERSEC;
255 ret += (MSVCRT___time64_t)mstm->tm_hour*60*60*TICKSPERSEC;
256 ret += (MSVCRT___time64_t)(mstm->tm_mday-1)*SECSPERDAY*TICKSPERSEC;
258 ft.dwLowDateTime = ret & 0xffffffff;
259 ft.dwHighDateTime = ret >> 32;
260 FileTimeToSystemTime(&ft, &st);
262 if(local) {
263 _tzset_init();
264 use_dst = is_dst(&st);
265 if((mstm->tm_isdst<=-1 && use_dst) || (mstm->tm_isdst>=1)) {
266 SYSTEMTIME tmp;
268 ret += (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
270 ft.dwLowDateTime = ret & 0xffffffff;
271 ft.dwHighDateTime = ret >> 32;
272 FileTimeToSystemTime(&ft, &tmp);
274 if(!is_dst(&tmp)) {
275 st = tmp;
276 use_dst = FALSE;
277 }else {
278 use_dst = TRUE;
280 }else if(mstm->tm_isdst==0 && use_dst) {
281 ret -= (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
282 ft.dwLowDateTime = ret & 0xffffffff;
283 ft.dwHighDateTime = ret >> 32;
284 FileTimeToSystemTime(&ft, &st);
285 ret += (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
287 ret += (MSVCRT___time64_t)MSVCRT___timezone*TICKSPERSEC;
290 mstm->tm_sec = st.wSecond;
291 mstm->tm_min = st.wMinute;
292 mstm->tm_hour = st.wHour;
293 mstm->tm_mday = st.wDay;
294 mstm->tm_mon = st.wMonth-1;
295 mstm->tm_year = st.wYear-1900;
296 mstm->tm_wday = st.wDayOfWeek;
297 for(i=mstm->tm_yday=0; i<st.wMonth-1; i++)
298 mstm->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
299 mstm->tm_yday += st.wDay-1;
300 mstm->tm_isdst = use_dst ? 1 : 0;
302 if(ret < TICKS_1601_TO_1970) {
303 *MSVCRT__errno() = MSVCRT_EINVAL;
304 return -1;
306 ret = (ret-TICKS_1601_TO_1970)/TICKSPERSEC;
307 return ret;
310 /**********************************************************************
311 * _mktime64 (MSVCRT.@)
313 MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
315 return mktime_helper(mstm, TRUE);
318 /**********************************************************************
319 * _mktime32 (MSVCRT.@)
321 MSVCRT___time32_t CDECL MSVCRT__mktime32(struct MSVCRT_tm *mstm)
323 MSVCRT___time64_t ret = MSVCRT__mktime64( mstm );
324 return ret == (MSVCRT___time32_t)ret ? ret : -1;
327 /**********************************************************************
328 * mktime (MSVCRT.@)
330 #ifdef _WIN64
331 MSVCRT___time64_t CDECL MSVCRT_mktime(struct MSVCRT_tm *mstm)
333 return MSVCRT__mktime64( mstm );
335 #else
336 MSVCRT___time32_t CDECL MSVCRT_mktime(struct MSVCRT_tm *mstm)
338 return MSVCRT__mktime32( mstm );
340 #endif
342 /**********************************************************************
343 * _mkgmtime64 (MSVCRT.@)
345 * time->tm_isdst value is ignored
347 MSVCRT___time64_t CDECL MSVCRT__mkgmtime64(struct MSVCRT_tm *time)
349 return mktime_helper(time, FALSE);
352 /**********************************************************************
353 * _mkgmtime32 (MSVCRT.@)
355 MSVCRT___time32_t CDECL MSVCRT__mkgmtime32(struct MSVCRT_tm *time)
357 MSVCRT___time64_t ret = MSVCRT__mkgmtime64(time);
358 return ret == (MSVCRT___time32_t)ret ? ret : -1;
361 /**********************************************************************
362 * _mkgmtime (MSVCRT.@)
364 #ifdef _WIN64
365 MSVCRT___time64_t CDECL MSVCRT__mkgmtime(struct MSVCRT_tm *time)
367 return MSVCRT__mkgmtime64(time);
369 #else
370 MSVCRT___time32_t CDECL MSVCRT__mkgmtime(struct MSVCRT_tm *time)
372 return MSVCRT__mkgmtime32(time);
374 #endif
376 /*********************************************************************
377 * _localtime64_s (MSVCRT.@)
379 int CDECL _localtime64_s(struct MSVCRT_tm *res, const MSVCRT___time64_t *secs)
381 int i;
382 FILETIME ft;
383 SYSTEMTIME st;
384 ULONGLONG time;
386 if (!res || !secs || *secs < 0 || *secs > _MAX__TIME64_T)
388 if (res)
389 write_invalid_msvcrt_tm(res);
391 *MSVCRT__errno() = MSVCRT_EINVAL;
392 return MSVCRT_EINVAL;
395 _tzset_init();
396 time = (*secs - MSVCRT___timezone) * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
398 ft.dwHighDateTime = (UINT)(time >> 32);
399 ft.dwLowDateTime = (UINT)time;
400 FileTimeToSystemTime(&ft, &st);
402 res->tm_isdst = is_dst(&st) ? 1 : 0;
403 if(res->tm_isdst) {
404 time -= MSVCRT__dstbias * (ULONGLONG)TICKSPERSEC;
405 ft.dwHighDateTime = (UINT)(time >> 32);
406 ft.dwLowDateTime = (UINT)time;
407 FileTimeToSystemTime(&ft, &st);
410 res->tm_sec = st.wSecond;
411 res->tm_min = st.wMinute;
412 res->tm_hour = st.wHour;
413 res->tm_mday = st.wDay;
414 res->tm_year = st.wYear - 1900;
415 res->tm_mon = st.wMonth - 1;
416 res->tm_wday = st.wDayOfWeek;
417 for (i = res->tm_yday = 0; i < st.wMonth - 1; i++)
418 res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
419 res->tm_yday += st.wDay - 1;
421 return 0;
424 /*********************************************************************
425 * _localtime64 (MSVCRT.@)
427 struct MSVCRT_tm* CDECL MSVCRT__localtime64(const MSVCRT___time64_t* secs)
429 thread_data_t *data = msvcrt_get_thread_data();
431 if(!data->time_buffer)
432 data->time_buffer = MSVCRT_malloc(sizeof(struct MSVCRT_tm));
434 if(_localtime64_s(data->time_buffer, secs))
435 return NULL;
436 return data->time_buffer;
439 /*********************************************************************
440 * _localtime32 (MSVCRT.@)
442 struct MSVCRT_tm* CDECL MSVCRT__localtime32(const MSVCRT___time32_t* secs)
444 MSVCRT___time64_t secs64;
446 if(!secs)
447 return NULL;
449 secs64 = *secs;
450 return MSVCRT__localtime64( &secs64 );
453 /*********************************************************************
454 * _localtime32_s (MSVCRT.@)
456 int CDECL _localtime32_s(struct MSVCRT_tm *time, const MSVCRT___time32_t *secs)
458 MSVCRT___time64_t secs64;
460 if (!time || !secs || *secs < 0)
462 if (time)
463 write_invalid_msvcrt_tm(time);
465 *MSVCRT__errno() = MSVCRT_EINVAL;
466 return MSVCRT_EINVAL;
469 secs64 = *secs;
470 return _localtime64_s(time, &secs64);
473 /*********************************************************************
474 * localtime (MSVCRT.@)
476 #ifdef _WIN64
477 struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time64_t* secs)
479 return MSVCRT__localtime64( secs );
481 #else
482 struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time32_t* secs)
484 return MSVCRT__localtime32( secs );
486 #endif
488 /*********************************************************************
489 * _gmtime64 (MSVCRT.@)
491 int CDECL MSVCRT__gmtime64_s(struct MSVCRT_tm *res, const MSVCRT___time64_t *secs)
493 int i;
494 FILETIME ft;
495 SYSTEMTIME st;
496 ULONGLONG time;
498 if (!res || !secs || *secs < 0 || *secs > _MAX__TIME64_T) {
499 if (res) {
500 write_invalid_msvcrt_tm(res);
503 *MSVCRT__errno() = MSVCRT_EINVAL;
504 return MSVCRT_EINVAL;
507 time = *secs * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
509 ft.dwHighDateTime = (UINT)(time >> 32);
510 ft.dwLowDateTime = (UINT)time;
512 FileTimeToSystemTime(&ft, &st);
514 res->tm_sec = st.wSecond;
515 res->tm_min = st.wMinute;
516 res->tm_hour = st.wHour;
517 res->tm_mday = st.wDay;
518 res->tm_year = st.wYear - 1900;
519 res->tm_mon = st.wMonth - 1;
520 res->tm_wday = st.wDayOfWeek;
521 for (i = res->tm_yday = 0; i < st.wMonth - 1; i++) {
522 res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
525 res->tm_yday += st.wDay - 1;
526 res->tm_isdst = 0;
528 return 0;
531 /*********************************************************************
532 * _gmtime64 (MSVCRT.@)
534 struct MSVCRT_tm* CDECL MSVCRT__gmtime64(const MSVCRT___time64_t *secs)
536 thread_data_t * const data = msvcrt_get_thread_data();
538 if(!data->time_buffer)
539 data->time_buffer = MSVCRT_malloc(sizeof(struct MSVCRT_tm));
541 if(MSVCRT__gmtime64_s(data->time_buffer, secs))
542 return NULL;
543 return data->time_buffer;
546 /*********************************************************************
547 * _gmtime32_s (MSVCRT.@)
549 int CDECL MSVCRT__gmtime32_s(struct MSVCRT_tm *res, const MSVCRT___time32_t *secs)
551 MSVCRT___time64_t secs64;
553 if(secs) {
554 secs64 = *secs;
555 return MSVCRT__gmtime64_s(res, &secs64);
557 return MSVCRT__gmtime64_s(res, NULL);
560 /*********************************************************************
561 * _gmtime32 (MSVCRT.@)
563 struct MSVCRT_tm* CDECL MSVCRT__gmtime32(const MSVCRT___time32_t* secs)
565 MSVCRT___time64_t secs64;
567 if(!secs)
568 return NULL;
570 secs64 = *secs;
571 return MSVCRT__gmtime64( &secs64 );
574 /*********************************************************************
575 * gmtime (MSVCRT.@)
577 #ifdef _WIN64
578 struct MSVCRT_tm* CDECL MSVCRT_gmtime(const MSVCRT___time64_t* secs)
580 return MSVCRT__gmtime64( secs );
582 #else
583 struct MSVCRT_tm* CDECL MSVCRT_gmtime(const MSVCRT___time32_t* secs)
585 return MSVCRT__gmtime32( secs );
587 #endif
589 /**********************************************************************
590 * _strdate (MSVCRT.@)
592 char* CDECL MSVCRT__strdate(char* date)
594 static const char format[] = "MM'/'dd'/'yy";
596 GetDateFormatA(LOCALE_NEUTRAL, 0, NULL, format, date, 9);
598 return date;
601 /**********************************************************************
602 * _strdate_s (MSVCRT.@)
604 int CDECL _strdate_s(char* date, MSVCRT_size_t size)
606 if(date && size)
607 date[0] = '\0';
609 if(!date) {
610 *MSVCRT__errno() = MSVCRT_EINVAL;
611 return MSVCRT_EINVAL;
614 if(size < 9) {
615 *MSVCRT__errno() = MSVCRT_ERANGE;
616 return MSVCRT_ERANGE;
619 MSVCRT__strdate(date);
620 return 0;
623 /**********************************************************************
624 * _wstrdate (MSVCRT.@)
626 MSVCRT_wchar_t* CDECL MSVCRT__wstrdate(MSVCRT_wchar_t* date)
628 static const WCHAR format[] = { 'M','M','\'','/','\'','d','d','\'','/','\'','y','y',0 };
630 GetDateFormatW(LOCALE_NEUTRAL, 0, NULL, format, date, 9);
632 return date;
635 /**********************************************************************
636 * _wstrdate_s (MSVCRT.@)
638 int CDECL _wstrdate_s(MSVCRT_wchar_t* date, MSVCRT_size_t size)
640 if(date && size)
641 date[0] = '\0';
643 if(!date) {
644 *MSVCRT__errno() = MSVCRT_EINVAL;
645 return MSVCRT_EINVAL;
648 if(size < 9) {
649 *MSVCRT__errno() = MSVCRT_ERANGE;
650 return MSVCRT_ERANGE;
653 MSVCRT__wstrdate(date);
654 return 0;
657 /*********************************************************************
658 * _strtime (MSVCRT.@)
660 char* CDECL MSVCRT__strtime(char* time)
662 static const char format[] = "HH':'mm':'ss";
664 GetTimeFormatA(LOCALE_NEUTRAL, 0, NULL, format, time, 9);
666 return time;
669 /*********************************************************************
670 * _strtime_s (MSVCRT.@)
672 int CDECL _strtime_s(char* time, MSVCRT_size_t size)
674 if(time && size)
675 time[0] = '\0';
677 if(!time) {
678 *MSVCRT__errno() = MSVCRT_EINVAL;
679 return MSVCRT_EINVAL;
682 if(size < 9) {
683 *MSVCRT__errno() = MSVCRT_ERANGE;
684 return MSVCRT_ERANGE;
687 MSVCRT__strtime(time);
688 return 0;
691 /*********************************************************************
692 * _wstrtime (MSVCRT.@)
694 MSVCRT_wchar_t* CDECL MSVCRT__wstrtime(MSVCRT_wchar_t* time)
696 static const WCHAR format[] = { 'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0 };
698 GetTimeFormatW(LOCALE_NEUTRAL, 0, NULL, format, time, 9);
700 return time;
703 /*********************************************************************
704 * _wstrtime_s (MSVCRT.@)
706 int CDECL _wstrtime_s(MSVCRT_wchar_t* time, MSVCRT_size_t size)
708 if(time && size)
709 time[0] = '\0';
711 if(!time) {
712 *MSVCRT__errno() = MSVCRT_EINVAL;
713 return MSVCRT_EINVAL;
716 if(size < 9) {
717 *MSVCRT__errno() = MSVCRT_ERANGE;
718 return MSVCRT_ERANGE;
721 MSVCRT__wstrtime(time);
722 return 0;
725 /*********************************************************************
726 * clock (MSVCRT.@)
728 MSVCRT_clock_t CDECL MSVCRT_clock(void)
730 LARGE_INTEGER systime;
732 NtQuerySystemTime(&systime);
733 return (systime.QuadPart - init_time) / (TICKSPERSEC / MSVCRT_CLOCKS_PER_SEC);
736 /*********************************************************************
737 * _difftime64 (MSVCRT.@)
739 double CDECL MSVCRT__difftime64(MSVCRT___time64_t time1, MSVCRT___time64_t time2)
741 return (double)(time1 - time2);
744 /*********************************************************************
745 * _difftime32 (MSVCRT.@)
747 double CDECL MSVCRT__difftime32(MSVCRT___time32_t time1, MSVCRT___time32_t time2)
749 return (double)(time1 - time2);
752 /*********************************************************************
753 * difftime (MSVCRT.@)
755 #ifdef _WIN64
756 double CDECL MSVCRT_difftime(MSVCRT___time64_t time1, MSVCRT___time64_t time2)
758 return MSVCRT__difftime64( time1, time2 );
760 #else
761 double CDECL MSVCRT_difftime(MSVCRT___time32_t time1, MSVCRT___time32_t time2)
763 return MSVCRT__difftime32( time1, time2 );
765 #endif
767 /*********************************************************************
768 * _ftime64 (MSVCRT.@)
770 void CDECL MSVCRT__ftime64(struct MSVCRT___timeb64 *buf)
772 FILETIME ft;
773 ULONGLONG time;
775 _tzset_init();
777 GetSystemTimeAsFileTime(&ft);
779 time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
781 buf->time = time / TICKSPERSEC - SECS_1601_TO_1970;
782 buf->millitm = (time % TICKSPERSEC) / TICKSPERMSEC;
783 buf->timezone = MSVCRT___timezone / 60;
784 buf->dstflag = GetDaylightFlag();
787 /*********************************************************************
788 * _ftime64_s (MSVCRT.@)
790 int CDECL MSVCRT__ftime64_s(struct MSVCRT___timeb64 *buf)
792 if (!MSVCRT_CHECK_PMT( buf != NULL )) return MSVCRT_EINVAL;
793 MSVCRT__ftime64(buf);
794 return 0;
797 /*********************************************************************
798 * _ftime32 (MSVCRT.@)
800 void CDECL MSVCRT__ftime32(struct MSVCRT___timeb32 *buf)
802 struct MSVCRT___timeb64 buf64;
804 MSVCRT__ftime64( &buf64 );
805 buf->time = buf64.time;
806 buf->millitm = buf64.millitm;
807 buf->timezone = buf64.timezone;
808 buf->dstflag = buf64.dstflag;
811 /*********************************************************************
812 * _ftime32_s (MSVCRT.@)
814 int CDECL MSVCRT__ftime32_s(struct MSVCRT___timeb32 *buf)
816 if (!MSVCRT_CHECK_PMT( buf != NULL )) return MSVCRT_EINVAL;
817 MSVCRT__ftime32(buf);
818 return 0;
821 /*********************************************************************
822 * _ftime (MSVCRT.@)
824 #ifdef _WIN64
825 void CDECL MSVCRT__ftime(struct MSVCRT___timeb64 *buf)
827 MSVCRT__ftime64( buf );
829 #else
830 void CDECL MSVCRT__ftime(struct MSVCRT___timeb32 *buf)
832 MSVCRT__ftime32( buf );
834 #endif
836 /*********************************************************************
837 * _time64 (MSVCRT.@)
839 MSVCRT___time64_t CDECL MSVCRT__time64(MSVCRT___time64_t *buf)
841 MSVCRT___time64_t curtime;
842 struct MSVCRT___timeb64 tb;
844 MSVCRT__ftime64(&tb);
846 curtime = tb.time;
847 return buf ? *buf = curtime : curtime;
850 /*********************************************************************
851 * _time32 (MSVCRT.@)
853 MSVCRT___time32_t CDECL MSVCRT__time32(MSVCRT___time32_t *buf)
855 MSVCRT___time32_t curtime;
856 struct MSVCRT___timeb64 tb;
858 MSVCRT__ftime64(&tb);
860 curtime = tb.time;
861 return buf ? *buf = curtime : curtime;
864 /*********************************************************************
865 * time (MSVCRT.@)
867 #ifdef _WIN64
868 MSVCRT___time64_t CDECL MSVCRT_time(MSVCRT___time64_t* buf)
870 return MSVCRT__time64( buf );
872 #else
873 MSVCRT___time32_t CDECL MSVCRT_time(MSVCRT___time32_t* buf)
875 return MSVCRT__time32( buf );
877 #endif
879 /*********************************************************************
880 * __p__daylight (MSVCRT.@)
882 int * CDECL MSVCRT___p__daylight(void)
884 return &MSVCRT___daylight;
887 /*********************************************************************
888 * __p__dstbias (MSVCRT.@)
890 int * CDECL MSVCRT___p__dstbias(void)
892 return &MSVCRT__dstbias;
895 #if _MSVCR_VER >= 80
896 /*********************************************************************
897 * _get_dstbias (MSVCR80.@)
899 int CDECL MSVCRT__get_dstbias(int *seconds)
901 if (!MSVCRT_CHECK_PMT(seconds != NULL)) return MSVCRT_EINVAL;
902 *seconds = MSVCRT__dstbias;
903 return 0;
905 #endif
907 /*********************************************************************
908 * __p__timezone (MSVCRT.@)
910 MSVCRT_long * CDECL MSVCRT___p__timezone(void)
912 return &MSVCRT___timezone;
915 /*********************************************************************
916 * _get_tzname (MSVCRT.@)
918 int CDECL MSVCRT__get_tzname(MSVCRT_size_t *ret, char *buf, MSVCRT_size_t bufsize, int index)
920 char *timezone;
922 switch(index)
924 case 0:
925 timezone = tzname_std;
926 break;
927 case 1:
928 timezone = tzname_dst;
929 break;
930 default:
931 *MSVCRT__errno() = MSVCRT_EINVAL;
932 return MSVCRT_EINVAL;
935 if(!ret || (!buf && bufsize > 0) || (buf && !bufsize))
937 *MSVCRT__errno() = MSVCRT_EINVAL;
938 return MSVCRT_EINVAL;
941 *ret = strlen(timezone)+1;
942 if(!buf && !bufsize)
943 return 0;
944 if(*ret > bufsize)
946 buf[0] = 0;
947 return MSVCRT_ERANGE;
950 strcpy(buf, timezone);
951 return 0;
954 /*********************************************************************
955 * __p_tzname (MSVCRT.@)
957 char ** CDECL __p__tzname(void)
959 return MSVCRT__tzname;
962 #if _MSVCR_VER <= 90
963 #define STRFTIME_CHAR char
964 #define STRFTIME_TD(td, name) td->str.names.name
965 #else
966 #define STRFTIME_CHAR MSVCRT_wchar_t
967 #define STRFTIME_TD(td, name) td->wstr.names.name
968 #endif
970 #define strftime_str(a,b,c,d) strftime_nstr(a,b,c,d,MSVCRT_SIZE_MAX)
971 static inline BOOL strftime_nstr(STRFTIME_CHAR *str, MSVCRT_size_t *pos,
972 MSVCRT_size_t max, const STRFTIME_CHAR *src, MSVCRT_size_t len)
974 while(*src && len)
976 if(*pos >= max) {
977 *str = 0;
978 *MSVCRT__errno() = MSVCRT_ERANGE;
979 return FALSE;
982 str[*pos] = *src;
983 src++;
984 *pos += 1;
985 len--;
987 return TRUE;
990 static inline BOOL strftime_int(STRFTIME_CHAR *str, MSVCRT_size_t *pos, MSVCRT_size_t max,
991 int src, int prec, int l, int h)
993 #if _MSVCR_VER > 90
994 static const WCHAR fmt[] = {'%','0','*','d',0};
995 #endif
996 MSVCRT_size_t len;
998 if(!MSVCRT_CHECK_PMT(src>=l && src<=h)) {
999 *str = 0;
1000 return FALSE;
1003 #if _MSVCR_VER <= 90
1004 len = MSVCRT__snprintf(str+*pos, max-*pos, "%0*d", prec, src);
1005 #else
1006 len = MSVCRT__snwprintf(str+*pos, max-*pos, fmt, prec, src);
1007 #endif
1008 if(len == -1) {
1009 *str = 0;
1010 *MSVCRT__errno() = MSVCRT_ERANGE;
1011 return FALSE;
1014 *pos += len;
1015 return TRUE;
1018 static inline BOOL strftime_format(STRFTIME_CHAR *str, MSVCRT_size_t *pos, MSVCRT_size_t max,
1019 const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data, const STRFTIME_CHAR *format)
1021 MSVCRT_size_t count;
1022 BOOL ret = TRUE;
1024 while(*format && ret)
1026 count = 1;
1027 while(format[0] == format[count]) count++;
1029 switch(*format) {
1030 case '\'':
1031 if(count % 2 == 0) break;
1033 format += count;
1034 count = 0;
1035 while(format[count] && format[count] != '\'') count++;
1037 ret = strftime_nstr(str, pos, max, format, count);
1038 if(!ret) return FALSE;
1039 if(format[count] == '\'') count++;
1040 break;
1041 case 'd':
1042 if(count > 2)
1044 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1046 *str = 0;
1047 return FALSE;
1050 switch(count) {
1051 case 1:
1052 case 2:
1053 ret = strftime_int(str, pos, max, mstm->tm_mday, count==1 ? 0 : 2, 1, 31);
1054 break;
1055 case 3:
1056 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, short_wday)[mstm->tm_wday]);
1057 break;
1058 default:
1059 ret = strftime_nstr(str, pos, max, format, count-4);
1060 if(ret)
1061 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, wday)[mstm->tm_wday]);
1062 break;
1064 break;
1065 case 'M':
1066 if(count > 2)
1068 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
1070 *str = 0;
1071 return FALSE;
1074 switch(count) {
1075 case 1:
1076 case 2:
1077 ret = strftime_int(str, pos, max, mstm->tm_mon+1, count==1 ? 0 : 2, 1, 12);
1078 break;
1079 case 3:
1080 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, short_mon)[mstm->tm_mon]);
1081 break;
1082 default:
1083 ret = strftime_nstr(str, pos, max, format, count-4);
1084 if(ret)
1085 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, mon)[mstm->tm_mon]);
1086 break;
1088 break;
1089 case 'y':
1090 if(count > 1)
1092 #if _MSVCR_VER>=140
1093 if(!MSVCRT_CHECK_PMT(mstm->tm_year >= -1900 && mstm->tm_year <= 8099))
1094 #else
1095 if(!MSVCRT_CHECK_PMT(mstm->tm_year >= 0))
1096 #endif
1098 *str = 0;
1099 return FALSE;
1103 switch(count) {
1104 case 1:
1105 ret = strftime_nstr(str, pos, max, format, 1);
1106 break;
1107 case 2:
1108 case 3:
1109 ret = strftime_nstr(str, pos, max, format, count-2);
1110 if(ret)
1111 ret = strftime_int(str, pos, max, (mstm->tm_year+1900)%100, 2, 0, 99);
1112 break;
1113 default:
1114 ret = strftime_nstr(str, pos, max, format, count-4);
1115 if(ret)
1116 ret = strftime_int(str, pos, max, mstm->tm_year+1900, 4, 0, 9999);
1117 break;
1119 break;
1120 case 'h':
1121 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1123 *str = 0;
1124 return FALSE;
1126 if(count > 2)
1127 ret = strftime_nstr(str, pos, max, format, count-2);
1128 if(ret)
1129 ret = strftime_int(str, pos, max, (mstm->tm_hour + 11) % 12 + 1,
1130 count == 1 ? 0 : 2, 1, 12);
1131 break;
1132 case 'H':
1133 if(count > 2)
1134 ret = strftime_nstr(str, pos, max, format, count-2);
1135 if(ret)
1136 ret = strftime_int(str, pos, max, mstm->tm_hour, count == 1 ? 0 : 2, 0, 23);
1137 break;
1138 case 'm':
1139 if(count > 2)
1140 ret = strftime_nstr(str, pos, max, format, count-2);
1141 if(ret)
1142 ret = strftime_int(str, pos, max, mstm->tm_min, count == 1 ? 0 : 2, 0, 59);
1143 break;
1144 case 's':
1145 if(count > 2)
1146 ret = strftime_nstr(str, pos, max, format, count-2);
1147 if(ret)
1148 ret = strftime_int(str, pos, max, mstm->tm_sec, count == 1 ? 0 : 2, 0, MAX_SECONDS);
1149 break;
1150 case 'a':
1151 case 'A':
1152 case 't':
1153 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1155 *str = 0;
1156 return FALSE;
1158 ret = strftime_nstr(str, pos, max,
1159 mstm->tm_hour < 12 ? STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm),
1160 (*format == 't' && count == 1) ? 1 : MSVCRT_SIZE_MAX);
1161 break;
1162 default:
1163 ret = strftime_nstr(str, pos, max, format, count);
1164 break;
1166 format += count;
1169 return ret;
1172 #if _MSVCR_VER>=140
1173 static inline BOOL strftime_tzdiff(STRFTIME_CHAR *str, MSVCRT_size_t *pos, MSVCRT_size_t max, BOOL is_dst)
1175 MSVCRT_long tz = MSVCRT___timezone + (is_dst ? MSVCRT__dstbias : 0);
1176 char sign;
1178 if(tz < 0) {
1179 sign = '+';
1180 tz = -tz;
1181 }else {
1182 sign = '-';
1185 if(*pos < max)
1186 str[(*pos)++] = sign;
1187 if(!strftime_int(str, pos, max, tz/60/60, 2, 0, 99))
1188 return FALSE;
1189 return strftime_int(str, pos, max, tz/60%60, 2, 0, 59);
1191 #endif
1193 static MSVCRT_size_t strftime_impl(STRFTIME_CHAR *str, MSVCRT_size_t max,
1194 const STRFTIME_CHAR *format, const struct MSVCRT_tm *mstm,
1195 MSVCRT___lc_time_data *time_data, MSVCRT__locale_t loc)
1197 MSVCRT_size_t ret, tmp;
1198 BOOL alternate;
1199 int year = mstm ? mstm->tm_year + 1900 : -1;
1201 if(!str || !format) {
1202 if(str && max)
1203 *str = 0;
1204 *MSVCRT__errno() = MSVCRT_EINVAL;
1205 return 0;
1208 if(!time_data)
1209 time_data = loc ? loc->locinfo->lc_time_curr : get_locinfo()->lc_time_curr;
1211 for(ret=0; *format && ret<max; format++) {
1212 if(*format != '%') {
1213 if(MSVCRT__isleadbyte_l((unsigned char)*format, loc)) {
1214 str[ret++] = *(format++);
1215 if(ret == max) continue;
1216 if(!MSVCRT_CHECK_PMT(str[ret]))
1217 goto einval_error;
1219 str[ret++] = *format;
1220 continue;
1223 format++;
1224 if(*format == '#') {
1225 alternate = TRUE;
1226 format++;
1227 }else {
1228 alternate = FALSE;
1231 if(!MSVCRT_CHECK_PMT(mstm))
1232 goto einval_error;
1234 switch(*format) {
1235 case 'c':
1236 #if _MSVCR_VER>=140
1237 if(time_data == &cloc_time_data && !alternate)
1239 static const WCHAR datetime_format[] =
1240 { '%','a',' ','%','b',' ','%','e',' ','%','T',' ','%','Y',0 };
1241 tmp = strftime_impl(str+ret, max-ret, datetime_format, mstm, time_data, loc);
1242 if(!tmp)
1243 return 0;
1244 ret += tmp;
1245 break;
1247 #endif
1248 if(!strftime_format(str, &ret, max, mstm, time_data,
1249 alternate ? STRFTIME_TD(time_data, date) : STRFTIME_TD(time_data, short_date)))
1250 return 0;
1251 if(ret < max)
1252 str[ret++] = ' ';
1253 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1254 return 0;
1255 break;
1256 case 'x':
1257 if(!strftime_format(str, &ret, max, mstm, time_data,
1258 alternate ? STRFTIME_TD(time_data, date) : STRFTIME_TD(time_data, short_date)))
1259 return 0;
1260 break;
1261 case 'X':
1262 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1263 return 0;
1264 break;
1265 case 'a':
1266 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1267 goto einval_error;
1268 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, short_wday)[mstm->tm_wday]))
1269 return 0;
1270 break;
1271 case 'A':
1272 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1273 goto einval_error;
1274 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, wday)[mstm->tm_wday]))
1275 return 0;
1276 break;
1277 case 'b':
1278 #if _MSVCR_VER>=140
1279 case 'h':
1280 #endif
1281 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
1282 goto einval_error;
1283 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, short_mon)[mstm->tm_mon]))
1284 return 0;
1285 break;
1286 case 'B':
1287 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
1288 goto einval_error;
1289 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, mon)[mstm->tm_mon]))
1290 return 0;
1291 break;
1292 #if _MSVCR_VER>=140
1293 case 'C':
1294 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1295 goto einval_error;
1296 if(!strftime_int(str, &ret, max, year/100, alternate ? 0 : 2, 0, 99))
1297 return 0;
1298 break;
1299 #endif
1300 case 'd':
1301 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1302 return 0;
1303 break;
1304 #if _MSVCR_VER>=140
1305 case 'D':
1306 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1307 goto einval_error;
1308 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1309 return 0;
1310 if(ret < max)
1311 str[ret++] = '/';
1312 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1313 return 0;
1314 if(ret < max)
1315 str[ret++] = '/';
1316 if(!strftime_int(str, &ret, max, year%100, alternate ? 0 : 2, 0, 99))
1317 return 0;
1318 break;
1319 case 'e':
1320 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1321 return 0;
1322 if(!alternate && str[ret-2] == '0')
1323 str[ret-2] = ' ';
1324 break;
1325 case 'F':
1326 if(!strftime_int(str, &ret, max, year, alternate ? 0 : 4, 0, 9999))
1327 return 0;
1328 if(ret < max)
1329 str[ret++] = '-';
1330 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1331 return 0;
1332 if(ret < max)
1333 str[ret++] = '-';
1334 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1335 return 0;
1336 break;
1337 case 'g':
1338 case 'G':
1339 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1340 goto einval_error;
1341 /* fall through */
1342 case 'V':
1344 int iso_year = year;
1345 int iso_days = mstm->tm_yday - (mstm->tm_wday ? mstm->tm_wday : 7) + 4;
1346 if (iso_days < 0)
1347 iso_days += 365 + IsLeapYear(--iso_year);
1348 else if(iso_days >= 365 + IsLeapYear(iso_year))
1349 iso_days -= 365 + IsLeapYear(iso_year++);
1351 if(*format == 'G') {
1352 if(!strftime_int(str, &ret, max, iso_year, 4, 0, 9999))
1353 return 0;
1354 } else if(*format == 'g') {
1355 if(!strftime_int(str, &ret, max, iso_year%100, 2, 0, 99))
1356 return 0;
1357 } else {
1358 if(!strftime_int(str, &ret, max, iso_days/7 + 1, alternate ? 0 : 2, 0, 53))
1359 return 0;
1361 break;
1363 #endif
1364 case 'H':
1365 if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1366 return 0;
1367 break;
1368 case 'I':
1369 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1370 goto einval_error;
1371 if(!strftime_int(str, &ret, max, (mstm->tm_hour + 11) % 12 + 1,
1372 alternate ? 0 : 2, 1, 12))
1373 return 0;
1374 break;
1375 case 'j':
1376 if(!strftime_int(str, &ret, max, mstm->tm_yday+1, alternate ? 0 : 3, 1, 366))
1377 return 0;
1378 break;
1379 case 'm':
1380 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1381 return 0;
1382 break;
1383 case 'M':
1384 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1385 return 0;
1386 break;
1387 #if _MSVCR_VER>=140
1388 case 'n':
1389 str[ret++] = '\n';
1390 break;
1391 #endif
1392 case 'p':
1393 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1394 goto einval_error;
1395 if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ?
1396 STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm)))
1397 return 0;
1398 break;
1399 #if _MSVCR_VER>=140
1400 case 'r':
1401 if(time_data == &cloc_time_data)
1403 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1404 goto einval_error;
1405 if(!strftime_int(str, &ret, max, (mstm->tm_hour + 11) % 12 + 1,
1406 alternate ? 0 : 2, 1, 12))
1407 return 0;
1408 if(ret < max)
1409 str[ret++] = ':';
1410 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1411 return 0;
1412 if(ret < max)
1413 str[ret++] = ':';
1414 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1415 return 0;
1416 if(ret < max)
1417 str[ret++] = ' ';
1418 if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ?
1419 STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm)))
1420 return 0;
1422 else
1424 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1425 return 0;
1427 break;
1428 case 'R':
1429 if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1430 return 0;
1431 if(ret < max)
1432 str[ret++] = ':';
1433 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1434 return 0;
1435 break;
1436 #endif
1437 case 'S':
1438 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1439 return 0;
1440 break;
1441 #if _MSVCR_VER>=140
1442 case 't':
1443 str[ret++] = '\t';
1444 break;
1445 case 'T':
1446 if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1447 return 0;
1448 if(ret < max)
1449 str[ret++] = ':';
1450 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1451 return 0;
1452 if(ret < max)
1453 str[ret++] = ':';
1454 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1455 return 0;
1456 break;
1457 case 'u':
1458 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1459 goto einval_error;
1460 tmp = mstm->tm_wday ? mstm->tm_wday : 7;
1461 if(!strftime_int(str, &ret, max, tmp, 0, 1, 7))
1462 return 0;
1463 break;
1464 #endif
1465 case 'w':
1466 if(!strftime_int(str, &ret, max, mstm->tm_wday, 0, 0, 6))
1467 return 0;
1468 break;
1469 case 'y':
1470 #if _MSVCR_VER>=140
1471 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1472 #else
1473 if(!MSVCRT_CHECK_PMT(year>=1900))
1474 #endif
1475 goto einval_error;
1476 if(!strftime_int(str, &ret, max, year%100, alternate ? 0 : 2, 0, 99))
1477 return 0;
1478 break;
1479 case 'Y':
1480 if(!strftime_int(str, &ret, max, year, alternate ? 0 : 4, 0, 9999))
1481 return 0;
1482 break;
1483 case 'z':
1484 #if _MSVCR_VER>=140
1485 MSVCRT__tzset();
1486 if(!strftime_tzdiff(str, &ret, max, mstm->tm_isdst))
1487 return 0;
1488 break;
1489 #endif
1490 case 'Z':
1491 MSVCRT__tzset();
1492 #if _MSVCR_VER <= 90
1493 if(MSVCRT__get_tzname(&tmp, str+ret, max-ret, mstm->tm_isdst ? 1 : 0))
1494 return 0;
1495 #else
1496 if(MSVCRT__mbstowcs_s_l(&tmp, str+ret, max-ret,
1497 mstm->tm_isdst ? tzname_dst : tzname_std,
1498 MSVCRT__TRUNCATE, loc) == MSVCRT_STRUNCATE)
1499 ret = max;
1500 #endif
1501 ret += tmp-1;
1502 break;
1503 case 'U':
1504 case 'W':
1505 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1506 goto einval_error;
1507 if(!MSVCRT_CHECK_PMT(mstm->tm_yday>=0 && mstm->tm_yday<=365))
1508 goto einval_error;
1509 if(*format == 'U')
1510 tmp = mstm->tm_wday;
1511 else if(!mstm->tm_wday)
1512 tmp = 6;
1513 else
1514 tmp = mstm->tm_wday-1;
1516 tmp = mstm->tm_yday/7 + (tmp<=mstm->tm_yday%7);
1517 if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 0, 53))
1518 return 0;
1519 break;
1520 case '%':
1521 str[ret++] = '%';
1522 break;
1523 default:
1524 WARN("unknown format %c\n", *format);
1525 MSVCRT_INVALID_PMT("unknown format", MSVCRT_EINVAL);
1526 goto einval_error;
1530 if(ret == max) {
1531 if(max)
1532 *str = 0;
1533 *MSVCRT__errno() = MSVCRT_ERANGE;
1534 return 0;
1537 str[ret] = 0;
1538 return ret;
1540 einval_error:
1541 *str = 0;
1542 return 0;
1545 static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *format,
1546 const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data, MSVCRT__locale_t loc)
1548 #if _MSVCR_VER <= 90
1549 TRACE("(%p %ld %s %p %p %p)\n", str, max, format, mstm, time_data, loc);
1550 return strftime_impl(str, max, format, mstm, time_data, loc);
1551 #else
1552 MSVCRT_wchar_t *s, *fmt;
1553 MSVCRT_size_t len;
1555 TRACE("(%p %ld %s %p %p %p)\n", str, max, format, mstm, time_data, loc);
1557 if (!MSVCRT_CHECK_PMT(str != NULL)) return 0;
1558 if (!MSVCRT_CHECK_PMT(max != 0)) return 0;
1559 *str = 0;
1560 if (!MSVCRT_CHECK_PMT(format != NULL)) return 0;
1562 len = MSVCRT__mbstowcs_l( NULL, format, 0, loc ) + 1;
1563 if (!len || !(fmt = MSVCRT_malloc( len*sizeof(MSVCRT_wchar_t) ))) return 0;
1564 MSVCRT__mbstowcs_l(fmt, format, len, loc);
1566 if ((s = MSVCRT_malloc( max*sizeof(MSVCRT_wchar_t) )))
1568 len = strftime_impl( s, max, fmt, mstm, time_data, loc );
1569 if (len)
1570 len = MSVCRT__wcstombs_l( str, s, max, loc );
1571 MSVCRT_free( s );
1573 else len = 0;
1575 MSVCRT_free( fmt );
1576 return len;
1577 #endif
1580 #if _MSVCR_VER >= 80
1581 /********************************************************************
1582 * _strftime_l (MSVCR80.@)
1584 MSVCRT_size_t CDECL MSVCRT__strftime_l( char *str, MSVCRT_size_t max, const char *format,
1585 const struct MSVCRT_tm *mstm, MSVCRT__locale_t loc )
1587 return strftime_helper(str, max, format, mstm, NULL, loc);
1589 #endif
1591 /*********************************************************************
1592 * _Strftime (MSVCRT.@)
1594 MSVCRT_size_t CDECL _Strftime(char *str, MSVCRT_size_t max, const char *format,
1595 const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data)
1597 return strftime_helper(str, max, format, mstm, time_data, NULL);
1600 /*********************************************************************
1601 * strftime (MSVCRT.@)
1603 MSVCRT_size_t CDECL MSVCRT_strftime( char *str, MSVCRT_size_t max, const char *format,
1604 const struct MSVCRT_tm *mstm )
1606 return strftime_helper(str, max, format, mstm, NULL, NULL);
1609 static MSVCRT_size_t wcsftime_helper( MSVCRT_wchar_t *str, MSVCRT_size_t max,
1610 const MSVCRT_wchar_t *format, const struct MSVCRT_tm *mstm,
1611 MSVCRT___lc_time_data *time_data, MSVCRT__locale_t loc )
1613 #if _MSVCR_VER <= 90
1614 char *s, *fmt;
1615 MSVCRT_size_t len;
1617 TRACE("%p %ld %s %p %p %p\n", str, max, debugstr_w(format), mstm, time_data, loc);
1619 len = MSVCRT__wcstombs_l( NULL, format, 0, loc ) + 1;
1620 if (!(fmt = MSVCRT_malloc( len ))) return 0;
1621 MSVCRT__wcstombs_l(fmt, format, len, loc);
1623 if ((s = MSVCRT_malloc( max*4 )))
1625 if (!strftime_impl( s, max*4, fmt, mstm, time_data, loc )) s[0] = 0;
1626 len = MSVCRT__mbstowcs_l( str, s, max, loc );
1627 MSVCRT_free( s );
1629 else len = 0;
1631 MSVCRT_free( fmt );
1632 return len;
1633 #else
1634 TRACE("%p %ld %s %p %p %p\n", str, max, debugstr_w(format), mstm, time_data, loc);
1635 return strftime_impl(str, max, format, mstm, time_data, loc);
1636 #endif
1639 /*********************************************************************
1640 * _wcsftime_l (MSVCRT.@)
1642 MSVCRT_size_t CDECL MSVCRT__wcsftime_l( MSVCRT_wchar_t *str, MSVCRT_size_t max,
1643 const MSVCRT_wchar_t *format, const struct MSVCRT_tm *mstm, MSVCRT__locale_t loc )
1645 return wcsftime_helper(str, max, format, mstm, NULL, loc);
1648 /*********************************************************************
1649 * wcsftime (MSVCRT.@)
1651 MSVCRT_size_t CDECL MSVCRT_wcsftime( MSVCRT_wchar_t *str, MSVCRT_size_t max,
1652 const MSVCRT_wchar_t *format, const struct MSVCRT_tm *mstm )
1654 return wcsftime_helper(str, max, format, mstm, NULL, NULL);
1657 #if _MSVCR_VER >= 110
1658 /*********************************************************************
1659 * _Wcsftime (MSVCR110.@)
1661 MSVCRT_size_t CDECL _Wcsftime(MSVCRT_wchar_t *str, MSVCRT_size_t max,
1662 const MSVCRT_wchar_t *format, const struct MSVCRT_tm *mstm,
1663 MSVCRT___lc_time_data *time_data)
1665 return wcsftime_helper(str, max, format, mstm, time_data, NULL);
1667 #endif
1669 static char* asctime_buf(char *buf, const struct MSVCRT_tm *mstm)
1671 static const char wday[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
1672 static const char month[12][4] = {"Jan", "Feb", "Mar", "Apr", "May",
1673 "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1675 if (!mstm || mstm->tm_sec<0 || mstm->tm_sec>59
1676 || mstm->tm_min<0 || mstm->tm_min>59
1677 || mstm->tm_hour<0 || mstm->tm_hour>23
1678 || mstm->tm_mon<0 || mstm->tm_mon>11
1679 || mstm->tm_wday<0 || mstm->tm_wday>6
1680 || mstm->tm_year<0 || mstm->tm_mday<0
1681 || mstm->tm_mday>MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon]) {
1682 *MSVCRT__errno() = MSVCRT_EINVAL;
1683 return NULL;
1686 #if _MSVCR_VER>=140
1687 /* C89 (4.12.3.1) uses space-padding for day of month. */
1688 MSVCRT__snprintf(buf, 26, "%s %s %2d %02d:%02d:%02d %c%03d\n", wday[mstm->tm_wday],
1689 month[mstm->tm_mon], mstm->tm_mday, mstm->tm_hour, mstm->tm_min,
1690 mstm->tm_sec, '1'+(mstm->tm_year+900)/1000, (900+mstm->tm_year)%1000);
1691 #else
1692 MSVCRT__snprintf(buf, 26, "%s %s %02d %02d:%02d:%02d %c%03d\n", wday[mstm->tm_wday],
1693 month[mstm->tm_mon], mstm->tm_mday, mstm->tm_hour, mstm->tm_min,
1694 mstm->tm_sec, '1'+(mstm->tm_year+900)/1000, (900+mstm->tm_year)%1000);
1695 #endif
1696 return buf;
1699 /*********************************************************************
1700 * asctime (MSVCRT.@)
1702 char * CDECL MSVCRT_asctime(const struct MSVCRT_tm *mstm)
1704 thread_data_t *data = msvcrt_get_thread_data();
1706 /* asctime returns date in format that always has exactly 26 characters */
1707 if (!data->asctime_buffer) {
1708 data->asctime_buffer = MSVCRT_malloc(26);
1709 if (!data->asctime_buffer) {
1710 *MSVCRT__errno() = MSVCRT_ENOMEM;
1711 return NULL;
1715 return asctime_buf(data->asctime_buffer, mstm);
1718 /*********************************************************************
1719 * asctime_s (MSVCRT.@)
1721 int CDECL MSVCRT_asctime_s(char* time, MSVCRT_size_t size, const struct MSVCRT_tm *mstm)
1723 if (!MSVCRT_CHECK_PMT(time != NULL)) return MSVCRT_EINVAL;
1724 if (size) time[0] = 0;
1725 if (!MSVCRT_CHECK_PMT(size >= 26)) return MSVCRT_EINVAL;
1726 if (!MSVCRT_CHECK_PMT(mstm != NULL)) return MSVCRT_EINVAL;
1727 if (!MSVCRT_CHECK_PMT(mstm->tm_sec >= 0 && mstm->tm_sec < 60)) return MSVCRT_EINVAL;
1728 if (!MSVCRT_CHECK_PMT(mstm->tm_min >= 0 && mstm->tm_min < 60)) return MSVCRT_EINVAL;
1729 if (!MSVCRT_CHECK_PMT(mstm->tm_hour >= 0 && mstm->tm_hour < 24)) return MSVCRT_EINVAL;
1730 if (!MSVCRT_CHECK_PMT(mstm->tm_mon >= 0 && mstm->tm_mon < 12)) return MSVCRT_EINVAL;
1731 if (!MSVCRT_CHECK_PMT(mstm->tm_wday >= 0 && mstm->tm_wday < 7)) return MSVCRT_EINVAL;
1732 if (!MSVCRT_CHECK_PMT(mstm->tm_year >= 0)) return MSVCRT_EINVAL;
1733 if (!MSVCRT_CHECK_PMT(mstm->tm_mday >= 0)) return MSVCRT_EINVAL;
1734 if (!MSVCRT_CHECK_PMT(mstm->tm_mday <= MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon])) return MSVCRT_EINVAL;
1736 asctime_buf(time, mstm);
1737 return 0;
1740 /*********************************************************************
1741 * _wasctime (MSVCRT.@)
1743 MSVCRT_wchar_t * CDECL MSVCRT__wasctime(const struct MSVCRT_tm *mstm)
1745 thread_data_t *data = msvcrt_get_thread_data();
1746 char buffer[26];
1748 if(!data->wasctime_buffer) {
1749 data->wasctime_buffer = MSVCRT_malloc(26*sizeof(MSVCRT_wchar_t));
1750 if(!data->wasctime_buffer) {
1751 *MSVCRT__errno() = MSVCRT_ENOMEM;
1752 return NULL;
1756 if(!asctime_buf(buffer, mstm))
1757 return NULL;
1759 MultiByteToWideChar(CP_ACP, 0, buffer, -1, data->wasctime_buffer, 26);
1760 return data->wasctime_buffer;
1763 /*********************************************************************
1764 * _wasctime_s (MSVCRT.@)
1766 int CDECL MSVCRT__wasctime_s(MSVCRT_wchar_t* time, MSVCRT_size_t size, const struct MSVCRT_tm *mstm)
1768 char buffer[26];
1769 int ret;
1771 if (!MSVCRT_CHECK_PMT(time != NULL)) return MSVCRT_EINVAL;
1772 if (size) time[0] = 0;
1773 if (!MSVCRT_CHECK_PMT(size >= 26)) return MSVCRT_EINVAL;
1774 if (!MSVCRT_CHECK_PMT(mstm != NULL)) return MSVCRT_EINVAL;
1776 ret = MSVCRT_asctime_s(buffer, sizeof(buffer), mstm);
1777 if(ret)
1778 return ret;
1779 MultiByteToWideChar(CP_ACP, 0, buffer, -1, time, size);
1780 return 0;
1783 /*********************************************************************
1784 * _ctime64 (MSVCRT.@)
1786 char * CDECL MSVCRT__ctime64(const MSVCRT___time64_t *time)
1788 struct MSVCRT_tm *t;
1789 t = MSVCRT__localtime64( time );
1790 if (!t) return NULL;
1791 return MSVCRT_asctime( t );
1794 /*********************************************************************
1795 * _ctime64_s (MSVCRT.@)
1797 int CDECL MSVCRT__ctime64_s(char *res, MSVCRT_size_t len, const MSVCRT___time64_t *time)
1799 struct MSVCRT_tm *t;
1801 if (!MSVCRT_CHECK_PMT( res != NULL )) return MSVCRT_EINVAL;
1802 if (!MSVCRT_CHECK_PMT( len >= 26 )) return MSVCRT_EINVAL;
1803 res[0] = '\0';
1804 if (!MSVCRT_CHECK_PMT( time != NULL )) return MSVCRT_EINVAL;
1805 if (!MSVCRT_CHECK_PMT( *time > 0 )) return MSVCRT_EINVAL;
1807 t = MSVCRT__localtime64( time );
1808 strcpy( res, MSVCRT_asctime( t ) );
1809 return 0;
1812 /*********************************************************************
1813 * _ctime32 (MSVCRT.@)
1815 char * CDECL MSVCRT__ctime32(const MSVCRT___time32_t *time)
1817 struct MSVCRT_tm *t;
1818 t = MSVCRT__localtime32( time );
1819 if (!t) return NULL;
1820 return MSVCRT_asctime( t );
1823 /*********************************************************************
1824 * _ctime32_s (MSVCRT.@)
1826 int CDECL MSVCRT__ctime32_s(char *res, MSVCRT_size_t len, const MSVCRT___time32_t *time)
1828 struct MSVCRT_tm *t;
1830 if (!MSVCRT_CHECK_PMT( res != NULL )) return MSVCRT_EINVAL;
1831 if (!MSVCRT_CHECK_PMT( len >= 26 )) return MSVCRT_EINVAL;
1832 res[0] = '\0';
1833 if (!MSVCRT_CHECK_PMT( time != NULL )) return MSVCRT_EINVAL;
1834 if (!MSVCRT_CHECK_PMT( *time > 0 )) return MSVCRT_EINVAL;
1836 t = MSVCRT__localtime32( time );
1837 strcpy( res, MSVCRT_asctime( t ) );
1838 return 0;
1841 /*********************************************************************
1842 * ctime (MSVCRT.@)
1844 #ifdef _WIN64
1845 char * CDECL MSVCRT_ctime(const MSVCRT___time64_t *time)
1847 return MSVCRT__ctime64( time );
1849 #else
1850 char * CDECL MSVCRT_ctime(const MSVCRT___time32_t *time)
1852 return MSVCRT__ctime32( time );
1854 #endif
1856 /*********************************************************************
1857 * _wctime64 (MSVCRT.@)
1859 MSVCRT_wchar_t * CDECL MSVCRT__wctime64(const MSVCRT___time64_t *time)
1861 return MSVCRT__wasctime( MSVCRT__localtime64(time) );
1864 /*********************************************************************
1865 * _wctime32 (MSVCRT.@)
1867 MSVCRT_wchar_t * CDECL MSVCRT__wctime32(const MSVCRT___time32_t *time)
1869 return MSVCRT__wasctime( MSVCRT__localtime32(time) );
1872 /*********************************************************************
1873 * _wctime (MSVCRT.@)
1875 #ifdef _WIN64
1876 MSVCRT_wchar_t * CDECL MSVCRT__wctime(const MSVCRT___time64_t *time)
1878 return MSVCRT__wctime64( time );
1880 #else
1881 MSVCRT_wchar_t * CDECL MSVCRT__wctime(const MSVCRT___time32_t *time)
1883 return MSVCRT__wctime32( time );
1885 #endif
1887 /*********************************************************************
1888 * _wctime64_s (MSVCRT.@)
1890 int CDECL MSVCRT__wctime64_s(MSVCRT_wchar_t *buf,
1891 MSVCRT_size_t size, const MSVCRT___time64_t *time)
1893 struct MSVCRT_tm tm;
1894 int ret;
1896 if(!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1897 if(!MSVCRT_CHECK_PMT(size != 0)) return MSVCRT_EINVAL;
1898 buf[0] = 0;
1899 if(!MSVCRT_CHECK_PMT(time != NULL)) return MSVCRT_EINVAL;
1900 if(!MSVCRT_CHECK_PMT(*time >= 0)) return MSVCRT_EINVAL;
1901 if(!MSVCRT_CHECK_PMT(*time <= _MAX__TIME64_T)) return MSVCRT_EINVAL;
1903 ret = _localtime64_s(&tm, time);
1904 if(ret != 0)
1905 return ret;
1907 return MSVCRT__wasctime_s(buf, size, &tm);
1910 /*********************************************************************
1911 * _wctime32_s (MSVCRT.@)
1913 int CDECL MSVCRT__wctime32_s(MSVCRT_wchar_t *buf, MSVCRT_size_t size,
1914 const MSVCRT___time32_t *time)
1916 struct MSVCRT_tm tm;
1917 int ret;
1919 if(!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1920 if(!MSVCRT_CHECK_PMT(size != 0)) return MSVCRT_EINVAL;
1921 buf[0] = 0;
1922 if(!MSVCRT_CHECK_PMT(time != NULL)) return MSVCRT_EINVAL;
1923 if(!MSVCRT_CHECK_PMT(*time >= 0)) return MSVCRT_EINVAL;
1925 ret = _localtime32_s(&tm, time);
1926 if(ret != 0)
1927 return ret;
1929 return MSVCRT__wasctime_s(buf, size, &tm);
1932 #if _MSVCR_VER >= 80
1934 /*********************************************************************
1935 * _get_timezone (MSVCR80.@)
1937 int CDECL _get_timezone(LONG *timezone)
1939 if(!MSVCRT_CHECK_PMT(timezone != NULL)) return MSVCRT_EINVAL;
1941 *timezone = MSVCRT___timezone;
1942 return 0;
1945 /*********************************************************************
1946 * _get_daylight (MSVCR80.@)
1948 int CDECL _get_daylight(int *hours)
1950 if(!MSVCRT_CHECK_PMT(hours != NULL)) return MSVCRT_EINVAL;
1952 *hours = MSVCRT___daylight;
1953 return 0;
1956 #endif /* _MSVCR_VER >= 80 */
1958 #if _MSVCR_VER >= 140
1960 #define TIME_UTC 1
1962 struct _timespec32
1964 MSVCRT___time32_t tv_sec;
1965 LONG tv_nsec;
1968 struct _timespec64
1970 MSVCRT___time64_t tv_sec;
1971 LONG tv_nsec;
1974 /*********************************************************************
1975 * _timespec64_get (UCRTBASE.@)
1977 int CDECL _timespec64_get(struct _timespec64 *ts, int base)
1979 ULONGLONG time;
1980 FILETIME ft;
1982 if(!MSVCRT_CHECK_PMT(ts != NULL)) return 0;
1983 if(base != TIME_UTC) return 0;
1985 GetSystemTimePreciseAsFileTime(&ft);
1986 time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
1988 ts->tv_sec = time / TICKSPERSEC - SECS_1601_TO_1970;
1989 ts->tv_nsec = time % TICKSPERSEC * 100;
1990 return base;
1993 /*********************************************************************
1994 * _timespec32_get (UCRTBASE.@)
1996 int CDECL _timespec32_get(struct _timespec32 *ts, int base)
1998 struct _timespec64 ts64;
2000 if(!MSVCRT_CHECK_PMT(ts != NULL)) return 0;
2001 if(base != TIME_UTC) return 0;
2003 if(_timespec64_get(&ts64, base) != base)
2004 return 0;
2005 if(ts64.tv_sec != (MSVCRT___time32_t)ts64.tv_sec)
2006 return 0;
2008 ts->tv_sec = ts64.tv_sec;
2009 ts->tv_nsec = ts64.tv_nsec;
2010 return base;
2012 #endif /* _MSVCR_VER >= 140 */