msvcrt: Remove MSVCRT_ prefix from string.c functions.
[wine.git] / dlls / msvcrt / time.c
blob4e071563a6c3bf9d4c1c421a201d485f774c2111
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 <stdlib.h>
26 #include <time.h>
27 #include <sys/timeb.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 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 = 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 = strtol(tz, &tz, 10)*3600;
131 if(*tz == ':') {
132 MSVCRT___timezone += strtol(tz+1, &tz, 10)*60;
133 if(*tz == ':')
134 MSVCRT___timezone += 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 __time64_t mktime_helper(struct tm *mstm, BOOL local)
224 SYSTEMTIME st;
225 FILETIME ft;
226 __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 *_errno() = 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 *_errno() = EINVAL;
249 return -1;
252 ret = ((__time64_t)ft.dwHighDateTime<<32)+ft.dwLowDateTime;
253 ret += (__time64_t)mstm->tm_sec*TICKSPERSEC;
254 ret += (__time64_t)mstm->tm_min*60*TICKSPERSEC;
255 ret += (__time64_t)mstm->tm_hour*60*60*TICKSPERSEC;
256 ret += (__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 += (__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 -= (__time64_t)MSVCRT__dstbias*TICKSPERSEC;
282 ft.dwLowDateTime = ret & 0xffffffff;
283 ft.dwHighDateTime = ret >> 32;
284 FileTimeToSystemTime(&ft, &st);
285 ret += (__time64_t)MSVCRT__dstbias*TICKSPERSEC;
287 ret += (__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 *_errno() = EINVAL;
304 return -1;
306 ret = (ret-TICKS_1601_TO_1970)/TICKSPERSEC;
307 return ret;
310 /**********************************************************************
311 * _mktime64 (MSVCRT.@)
313 __time64_t CDECL MSVCRT__mktime64(struct tm *mstm)
315 return mktime_helper(mstm, TRUE);
318 /**********************************************************************
319 * _mktime32 (MSVCRT.@)
321 __time32_t CDECL MSVCRT__mktime32(struct tm *mstm)
323 __time64_t ret = MSVCRT__mktime64( mstm );
324 return ret == (__time32_t)ret ? ret : -1;
327 /**********************************************************************
328 * mktime (MSVCRT.@)
330 #ifdef _WIN64
331 __time64_t CDECL MSVCRT_mktime(struct tm *mstm)
333 return MSVCRT__mktime64( mstm );
335 #else
336 __time32_t CDECL MSVCRT_mktime(struct tm *mstm)
338 return MSVCRT__mktime32( mstm );
340 #endif
342 /**********************************************************************
343 * _mkgmtime64 (MSVCRT.@)
345 * time->tm_isdst value is ignored
347 __time64_t CDECL MSVCRT__mkgmtime64(struct tm *time)
349 return mktime_helper(time, FALSE);
352 /**********************************************************************
353 * _mkgmtime32 (MSVCRT.@)
355 __time32_t CDECL MSVCRT__mkgmtime32(struct tm *time)
357 __time64_t ret = MSVCRT__mkgmtime64(time);
358 return ret == (__time32_t)ret ? ret : -1;
361 /**********************************************************************
362 * _mkgmtime (MSVCRT.@)
364 #ifdef _WIN64
365 __time64_t CDECL MSVCRT__mkgmtime(struct tm *time)
367 return MSVCRT__mkgmtime64(time);
369 #else
370 __time32_t CDECL MSVCRT__mkgmtime(struct tm *time)
372 return MSVCRT__mkgmtime32(time);
374 #endif
376 /*********************************************************************
377 * _localtime64_s (MSVCRT.@)
379 int CDECL _localtime64_s(struct tm *res, const __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 *_errno() = EINVAL;
392 return 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 tm* CDECL MSVCRT__localtime64(const __time64_t* secs)
429 thread_data_t *data = msvcrt_get_thread_data();
431 if(!data->time_buffer)
432 data->time_buffer = malloc(sizeof(struct tm));
434 if(_localtime64_s(data->time_buffer, secs))
435 return NULL;
436 return data->time_buffer;
439 /*********************************************************************
440 * _localtime32 (MSVCRT.@)
442 struct tm* CDECL MSVCRT__localtime32(const __time32_t* secs)
444 __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 tm *time, const __time32_t *secs)
458 __time64_t secs64;
460 if (!time || !secs || *secs < 0)
462 if (time)
463 write_invalid_msvcrt_tm(time);
465 *_errno() = EINVAL;
466 return EINVAL;
469 secs64 = *secs;
470 return _localtime64_s(time, &secs64);
473 /*********************************************************************
474 * localtime (MSVCRT.@)
476 #ifdef _WIN64
477 struct tm* CDECL MSVCRT_localtime(const __time64_t* secs)
479 return MSVCRT__localtime64( secs );
481 #else
482 struct tm* CDECL MSVCRT_localtime(const __time32_t* secs)
484 return MSVCRT__localtime32( secs );
486 #endif
488 /*********************************************************************
489 * _gmtime64 (MSVCRT.@)
491 int CDECL MSVCRT__gmtime64_s(struct tm *res, const __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 *_errno() = EINVAL;
504 return 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 tm* CDECL MSVCRT__gmtime64(const __time64_t *secs)
536 thread_data_t * const data = msvcrt_get_thread_data();
538 if(!data->time_buffer)
539 data->time_buffer = malloc(sizeof(struct 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 tm *res, const __time32_t *secs)
551 __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 tm* CDECL MSVCRT__gmtime32(const __time32_t* secs)
565 __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 tm* CDECL MSVCRT_gmtime(const __time64_t* secs)
580 return MSVCRT__gmtime64( secs );
582 #else
583 struct tm* CDECL MSVCRT_gmtime(const __time32_t* secs)
585 return MSVCRT__gmtime32( secs );
587 #endif
589 /**********************************************************************
590 * _strdate (MSVCRT.@)
592 char* CDECL MSVCRT__strdate(char* date)
594 GetDateFormatA(LOCALE_NEUTRAL, 0, NULL, "MM'/'dd'/'yy", date, 9);
595 return date;
598 /**********************************************************************
599 * _strdate_s (MSVCRT.@)
601 int CDECL _strdate_s(char* date, size_t size)
603 if(date && size)
604 date[0] = '\0';
606 if(!date) {
607 *_errno() = EINVAL;
608 return EINVAL;
611 if(size < 9) {
612 *_errno() = ERANGE;
613 return ERANGE;
616 MSVCRT__strdate(date);
617 return 0;
620 /**********************************************************************
621 * _wstrdate (MSVCRT.@)
623 wchar_t* CDECL MSVCRT__wstrdate(wchar_t* date)
625 GetDateFormatW(LOCALE_NEUTRAL, 0, NULL, L"MM'/'dd'/'yy", date, 9);
626 return date;
629 /**********************************************************************
630 * _wstrdate_s (MSVCRT.@)
632 int CDECL _wstrdate_s(wchar_t* date, size_t size)
634 if(date && size)
635 date[0] = '\0';
637 if(!date) {
638 *_errno() = EINVAL;
639 return EINVAL;
642 if(size < 9) {
643 *_errno() = ERANGE;
644 return ERANGE;
647 MSVCRT__wstrdate(date);
648 return 0;
651 /*********************************************************************
652 * _strtime (MSVCRT.@)
654 char* CDECL MSVCRT__strtime(char* time)
656 GetTimeFormatA(LOCALE_NEUTRAL, 0, NULL, "HH':'mm':'ss", time, 9);
657 return time;
660 /*********************************************************************
661 * _strtime_s (MSVCRT.@)
663 int CDECL _strtime_s(char* time, size_t size)
665 if(time && size)
666 time[0] = '\0';
668 if(!time) {
669 *_errno() = EINVAL;
670 return EINVAL;
673 if(size < 9) {
674 *_errno() = ERANGE;
675 return ERANGE;
678 MSVCRT__strtime(time);
679 return 0;
682 /*********************************************************************
683 * _wstrtime (MSVCRT.@)
685 wchar_t* CDECL MSVCRT__wstrtime(wchar_t* time)
687 GetTimeFormatW(LOCALE_NEUTRAL, 0, NULL, L"HH':'mm':'ss", time, 9);
688 return time;
691 /*********************************************************************
692 * _wstrtime_s (MSVCRT.@)
694 int CDECL _wstrtime_s(wchar_t* time, size_t size)
696 if(time && size)
697 time[0] = '\0';
699 if(!time) {
700 *_errno() = EINVAL;
701 return EINVAL;
704 if(size < 9) {
705 *_errno() = ERANGE;
706 return ERANGE;
709 MSVCRT__wstrtime(time);
710 return 0;
713 /*********************************************************************
714 * clock (MSVCRT.@)
716 clock_t CDECL MSVCRT_clock(void)
718 LARGE_INTEGER systime;
720 NtQuerySystemTime(&systime);
721 return (systime.QuadPart - init_time) / (TICKSPERSEC / MSVCRT_CLOCKS_PER_SEC);
724 /*********************************************************************
725 * _difftime64 (MSVCRT.@)
727 double CDECL MSVCRT__difftime64(__time64_t time1, __time64_t time2)
729 return (double)(time1 - time2);
732 /*********************************************************************
733 * _difftime32 (MSVCRT.@)
735 double CDECL MSVCRT__difftime32(__time32_t time1, __time32_t time2)
737 return (double)(time1 - time2);
740 /*********************************************************************
741 * difftime (MSVCRT.@)
743 #ifdef _WIN64
744 double CDECL MSVCRT_difftime(__time64_t time1, __time64_t time2)
746 return MSVCRT__difftime64( time1, time2 );
748 #else
749 double CDECL MSVCRT_difftime(__time32_t time1, __time32_t time2)
751 return MSVCRT__difftime32( time1, time2 );
753 #endif
755 /*********************************************************************
756 * _ftime64 (MSVCRT.@)
758 void CDECL MSVCRT__ftime64(struct __timeb64 *buf)
760 FILETIME ft;
761 ULONGLONG time;
763 _tzset_init();
765 GetSystemTimeAsFileTime(&ft);
767 time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
769 buf->time = time / TICKSPERSEC - SECS_1601_TO_1970;
770 buf->millitm = (time % TICKSPERSEC) / TICKSPERMSEC;
771 buf->timezone = MSVCRT___timezone / 60;
772 buf->dstflag = GetDaylightFlag();
775 /*********************************************************************
776 * _ftime64_s (MSVCRT.@)
778 int CDECL MSVCRT__ftime64_s(struct __timeb64 *buf)
780 if (!MSVCRT_CHECK_PMT( buf != NULL )) return EINVAL;
781 MSVCRT__ftime64(buf);
782 return 0;
785 /*********************************************************************
786 * _ftime32 (MSVCRT.@)
788 void CDECL MSVCRT__ftime32(struct __timeb32 *buf)
790 struct __timeb64 buf64;
792 MSVCRT__ftime64( &buf64 );
793 buf->time = buf64.time;
794 buf->millitm = buf64.millitm;
795 buf->timezone = buf64.timezone;
796 buf->dstflag = buf64.dstflag;
799 /*********************************************************************
800 * _ftime32_s (MSVCRT.@)
802 int CDECL MSVCRT__ftime32_s(struct __timeb32 *buf)
804 if (!MSVCRT_CHECK_PMT( buf != NULL )) return EINVAL;
805 MSVCRT__ftime32(buf);
806 return 0;
809 /*********************************************************************
810 * _ftime (MSVCRT.@)
812 #ifdef _WIN64
813 void CDECL MSVCRT__ftime(struct __timeb64 *buf)
815 MSVCRT__ftime64( buf );
817 #else
818 void CDECL MSVCRT__ftime(struct __timeb32 *buf)
820 MSVCRT__ftime32( buf );
822 #endif
824 /*********************************************************************
825 * _time64 (MSVCRT.@)
827 __time64_t CDECL MSVCRT__time64(__time64_t *buf)
829 __time64_t curtime;
830 struct __timeb64 tb;
832 MSVCRT__ftime64(&tb);
834 curtime = tb.time;
835 return buf ? *buf = curtime : curtime;
838 /*********************************************************************
839 * _time32 (MSVCRT.@)
841 __time32_t CDECL MSVCRT__time32(__time32_t *buf)
843 __time32_t curtime;
844 struct __timeb64 tb;
846 MSVCRT__ftime64(&tb);
848 curtime = tb.time;
849 return buf ? *buf = curtime : curtime;
852 /*********************************************************************
853 * time (MSVCRT.@)
855 #ifdef _WIN64
856 __time64_t CDECL MSVCRT_time(__time64_t* buf)
858 return MSVCRT__time64( buf );
860 #else
861 __time32_t CDECL MSVCRT_time(__time32_t* buf)
863 return MSVCRT__time32( buf );
865 #endif
867 /*********************************************************************
868 * __p__daylight (MSVCRT.@)
870 int * CDECL MSVCRT___p__daylight(void)
872 return &MSVCRT___daylight;
875 /*********************************************************************
876 * __p__dstbias (MSVCRT.@)
878 int * CDECL MSVCRT___p__dstbias(void)
880 return &MSVCRT__dstbias;
883 #if _MSVCR_VER >= 80
884 /*********************************************************************
885 * _get_dstbias (MSVCR80.@)
887 int CDECL MSVCRT__get_dstbias(int *seconds)
889 if (!MSVCRT_CHECK_PMT(seconds != NULL)) return EINVAL;
890 *seconds = MSVCRT__dstbias;
891 return 0;
893 #endif
895 /*********************************************************************
896 * __p__timezone (MSVCRT.@)
898 __msvcrt_long * CDECL MSVCRT___p__timezone(void)
900 return &MSVCRT___timezone;
903 /*********************************************************************
904 * _get_tzname (MSVCRT.@)
906 int CDECL MSVCRT__get_tzname(size_t *ret, char *buf, size_t bufsize, int index)
908 char *timezone;
910 switch(index)
912 case 0:
913 timezone = tzname_std;
914 break;
915 case 1:
916 timezone = tzname_dst;
917 break;
918 default:
919 *_errno() = EINVAL;
920 return EINVAL;
923 if(!ret || (!buf && bufsize > 0) || (buf && !bufsize))
925 *_errno() = EINVAL;
926 return EINVAL;
929 *ret = strlen(timezone)+1;
930 if(!buf && !bufsize)
931 return 0;
932 if(*ret > bufsize)
934 buf[0] = 0;
935 return ERANGE;
938 strcpy(buf, timezone);
939 return 0;
942 /*********************************************************************
943 * __p_tzname (MSVCRT.@)
945 char ** CDECL __p__tzname(void)
947 return MSVCRT__tzname;
950 #if _MSVCR_VER <= 90
951 #define STRFTIME_CHAR char
952 #define STRFTIME_TD(td, name) td->str.names.name
953 #else
954 #define STRFTIME_CHAR wchar_t
955 #define STRFTIME_TD(td, name) td->wstr.names.name
956 #endif
958 #define strftime_str(a,b,c,d) strftime_nstr(a,b,c,d,SIZE_MAX)
959 static inline BOOL strftime_nstr(STRFTIME_CHAR *str, size_t *pos,
960 size_t max, const STRFTIME_CHAR *src, size_t len)
962 while(*src && len)
964 if(*pos >= max) {
965 *str = 0;
966 *_errno() = ERANGE;
967 return FALSE;
970 str[*pos] = *src;
971 src++;
972 *pos += 1;
973 len--;
975 return TRUE;
978 static inline BOOL strftime_int(STRFTIME_CHAR *str, size_t *pos, size_t max,
979 int src, int prec, int l, int h)
981 size_t len;
983 if(!MSVCRT_CHECK_PMT(src>=l && src<=h)) {
984 *str = 0;
985 return FALSE;
988 #if _MSVCR_VER <= 90
989 len = MSVCRT__snprintf(str+*pos, max-*pos, "%0*d", prec, src);
990 #else
991 len = MSVCRT__snwprintf(str+*pos, max-*pos, L"%0*d", prec, src);
992 #endif
993 if(len == -1) {
994 *str = 0;
995 *_errno() = ERANGE;
996 return FALSE;
999 *pos += len;
1000 return TRUE;
1003 static inline BOOL strftime_format(STRFTIME_CHAR *str, size_t *pos, size_t max,
1004 const struct tm *mstm, __lc_time_data *time_data, const STRFTIME_CHAR *format)
1006 size_t count;
1007 BOOL ret = TRUE;
1009 while(*format && ret)
1011 count = 1;
1012 while(format[0] == format[count]) count++;
1014 switch(*format) {
1015 case '\'':
1016 if(count % 2 == 0) break;
1018 format += count;
1019 count = 0;
1020 while(format[count] && format[count] != '\'') count++;
1022 ret = strftime_nstr(str, pos, max, format, count);
1023 if(!ret) return FALSE;
1024 if(format[count] == '\'') count++;
1025 break;
1026 case 'd':
1027 if(count > 2)
1029 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1031 *str = 0;
1032 return FALSE;
1035 switch(count) {
1036 case 1:
1037 case 2:
1038 ret = strftime_int(str, pos, max, mstm->tm_mday, count==1 ? 0 : 2, 1, 31);
1039 break;
1040 case 3:
1041 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, short_wday)[mstm->tm_wday]);
1042 break;
1043 default:
1044 ret = strftime_nstr(str, pos, max, format, count-4);
1045 if(ret)
1046 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, wday)[mstm->tm_wday]);
1047 break;
1049 break;
1050 case 'M':
1051 if(count > 2)
1053 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
1055 *str = 0;
1056 return FALSE;
1059 switch(count) {
1060 case 1:
1061 case 2:
1062 ret = strftime_int(str, pos, max, mstm->tm_mon+1, count==1 ? 0 : 2, 1, 12);
1063 break;
1064 case 3:
1065 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, short_mon)[mstm->tm_mon]);
1066 break;
1067 default:
1068 ret = strftime_nstr(str, pos, max, format, count-4);
1069 if(ret)
1070 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, mon)[mstm->tm_mon]);
1071 break;
1073 break;
1074 case 'y':
1075 if(count > 1)
1077 #if _MSVCR_VER>=140
1078 if(!MSVCRT_CHECK_PMT(mstm->tm_year >= -1900 && mstm->tm_year <= 8099))
1079 #else
1080 if(!MSVCRT_CHECK_PMT(mstm->tm_year >= 0))
1081 #endif
1083 *str = 0;
1084 return FALSE;
1088 switch(count) {
1089 case 1:
1090 ret = strftime_nstr(str, pos, max, format, 1);
1091 break;
1092 case 2:
1093 case 3:
1094 ret = strftime_nstr(str, pos, max, format, count-2);
1095 if(ret)
1096 ret = strftime_int(str, pos, max, (mstm->tm_year+1900)%100, 2, 0, 99);
1097 break;
1098 default:
1099 ret = strftime_nstr(str, pos, max, format, count-4);
1100 if(ret)
1101 ret = strftime_int(str, pos, max, mstm->tm_year+1900, 4, 0, 9999);
1102 break;
1104 break;
1105 case 'h':
1106 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1108 *str = 0;
1109 return FALSE;
1111 if(count > 2)
1112 ret = strftime_nstr(str, pos, max, format, count-2);
1113 if(ret)
1114 ret = strftime_int(str, pos, max, (mstm->tm_hour + 11) % 12 + 1,
1115 count == 1 ? 0 : 2, 1, 12);
1116 break;
1117 case 'H':
1118 if(count > 2)
1119 ret = strftime_nstr(str, pos, max, format, count-2);
1120 if(ret)
1121 ret = strftime_int(str, pos, max, mstm->tm_hour, count == 1 ? 0 : 2, 0, 23);
1122 break;
1123 case 'm':
1124 if(count > 2)
1125 ret = strftime_nstr(str, pos, max, format, count-2);
1126 if(ret)
1127 ret = strftime_int(str, pos, max, mstm->tm_min, count == 1 ? 0 : 2, 0, 59);
1128 break;
1129 case 's':
1130 if(count > 2)
1131 ret = strftime_nstr(str, pos, max, format, count-2);
1132 if(ret)
1133 ret = strftime_int(str, pos, max, mstm->tm_sec, count == 1 ? 0 : 2, 0, MAX_SECONDS);
1134 break;
1135 case 'a':
1136 case 'A':
1137 case 't':
1138 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1140 *str = 0;
1141 return FALSE;
1143 ret = strftime_nstr(str, pos, max,
1144 mstm->tm_hour < 12 ? STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm),
1145 (*format == 't' && count == 1) ? 1 : SIZE_MAX);
1146 break;
1147 default:
1148 ret = strftime_nstr(str, pos, max, format, count);
1149 break;
1151 format += count;
1154 return ret;
1157 #if _MSVCR_VER>=140
1158 static inline BOOL strftime_tzdiff(STRFTIME_CHAR *str, size_t *pos, size_t max, BOOL is_dst)
1160 __msvcrt_long tz = MSVCRT___timezone + (is_dst ? MSVCRT__dstbias : 0);
1161 char sign;
1163 if(tz < 0) {
1164 sign = '+';
1165 tz = -tz;
1166 }else {
1167 sign = '-';
1170 if(*pos < max)
1171 str[(*pos)++] = sign;
1172 if(!strftime_int(str, pos, max, tz/60/60, 2, 0, 99))
1173 return FALSE;
1174 return strftime_int(str, pos, max, tz/60%60, 2, 0, 59);
1176 #endif
1178 static size_t strftime_impl(STRFTIME_CHAR *str, size_t max,
1179 const STRFTIME_CHAR *format, const struct tm *mstm,
1180 __lc_time_data *time_data, _locale_t loc)
1182 size_t ret, tmp;
1183 BOOL alternate;
1184 int year = mstm ? mstm->tm_year + 1900 : -1;
1186 if(!str || !format) {
1187 if(str && max)
1188 *str = 0;
1189 *_errno() = EINVAL;
1190 return 0;
1193 if(!time_data)
1194 time_data = loc ? loc->locinfo->lc_time_curr : get_locinfo()->lc_time_curr;
1196 for(ret=0; *format && ret<max; format++) {
1197 if(*format != '%') {
1198 if(_isleadbyte_l((unsigned char)*format, loc)) {
1199 str[ret++] = *(format++);
1200 if(ret == max) continue;
1201 if(!MSVCRT_CHECK_PMT(str[ret]))
1202 goto einval_error;
1204 str[ret++] = *format;
1205 continue;
1208 format++;
1209 if(*format == '#') {
1210 alternate = TRUE;
1211 format++;
1212 }else {
1213 alternate = FALSE;
1216 if(!MSVCRT_CHECK_PMT(mstm))
1217 goto einval_error;
1219 switch(*format) {
1220 case 'c':
1221 #if _MSVCR_VER>=140
1222 if(time_data == &cloc_time_data && !alternate)
1224 tmp = strftime_impl(str+ret, max-ret, L"%a %b %e %T %Y", mstm, time_data, loc);
1225 if(!tmp)
1226 return 0;
1227 ret += tmp;
1228 break;
1230 #endif
1231 if(!strftime_format(str, &ret, max, mstm, time_data,
1232 alternate ? STRFTIME_TD(time_data, date) : STRFTIME_TD(time_data, short_date)))
1233 return 0;
1234 if(ret < max)
1235 str[ret++] = ' ';
1236 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1237 return 0;
1238 break;
1239 case 'x':
1240 if(!strftime_format(str, &ret, max, mstm, time_data,
1241 alternate ? STRFTIME_TD(time_data, date) : STRFTIME_TD(time_data, short_date)))
1242 return 0;
1243 break;
1244 case 'X':
1245 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1246 return 0;
1247 break;
1248 case 'a':
1249 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1250 goto einval_error;
1251 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, short_wday)[mstm->tm_wday]))
1252 return 0;
1253 break;
1254 case 'A':
1255 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1256 goto einval_error;
1257 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, wday)[mstm->tm_wday]))
1258 return 0;
1259 break;
1260 case 'b':
1261 #if _MSVCR_VER>=140
1262 case 'h':
1263 #endif
1264 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
1265 goto einval_error;
1266 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, short_mon)[mstm->tm_mon]))
1267 return 0;
1268 break;
1269 case 'B':
1270 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
1271 goto einval_error;
1272 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, mon)[mstm->tm_mon]))
1273 return 0;
1274 break;
1275 #if _MSVCR_VER>=140
1276 case 'C':
1277 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1278 goto einval_error;
1279 if(!strftime_int(str, &ret, max, year/100, alternate ? 0 : 2, 0, 99))
1280 return 0;
1281 break;
1282 #endif
1283 case 'd':
1284 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1285 return 0;
1286 break;
1287 #if _MSVCR_VER>=140
1288 case 'D':
1289 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1290 goto einval_error;
1291 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1292 return 0;
1293 if(ret < max)
1294 str[ret++] = '/';
1295 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1296 return 0;
1297 if(ret < max)
1298 str[ret++] = '/';
1299 if(!strftime_int(str, &ret, max, year%100, alternate ? 0 : 2, 0, 99))
1300 return 0;
1301 break;
1302 case 'e':
1303 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1304 return 0;
1305 if(!alternate && str[ret-2] == '0')
1306 str[ret-2] = ' ';
1307 break;
1308 case 'F':
1309 if(!strftime_int(str, &ret, max, year, alternate ? 0 : 4, 0, 9999))
1310 return 0;
1311 if(ret < max)
1312 str[ret++] = '-';
1313 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1314 return 0;
1315 if(ret < max)
1316 str[ret++] = '-';
1317 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1318 return 0;
1319 break;
1320 case 'g':
1321 case 'G':
1322 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1323 goto einval_error;
1324 /* fall through */
1325 case 'V':
1327 int iso_year = year;
1328 int iso_days = mstm->tm_yday - (mstm->tm_wday ? mstm->tm_wday : 7) + 4;
1329 if (iso_days < 0)
1330 iso_days += 365 + IsLeapYear(--iso_year);
1331 else if(iso_days >= 365 + IsLeapYear(iso_year))
1332 iso_days -= 365 + IsLeapYear(iso_year++);
1334 if(*format == 'G') {
1335 if(!strftime_int(str, &ret, max, iso_year, 4, 0, 9999))
1336 return 0;
1337 } else if(*format == 'g') {
1338 if(!strftime_int(str, &ret, max, iso_year%100, 2, 0, 99))
1339 return 0;
1340 } else {
1341 if(!strftime_int(str, &ret, max, iso_days/7 + 1, alternate ? 0 : 2, 0, 53))
1342 return 0;
1344 break;
1346 #endif
1347 case 'H':
1348 if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1349 return 0;
1350 break;
1351 case 'I':
1352 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1353 goto einval_error;
1354 if(!strftime_int(str, &ret, max, (mstm->tm_hour + 11) % 12 + 1,
1355 alternate ? 0 : 2, 1, 12))
1356 return 0;
1357 break;
1358 case 'j':
1359 if(!strftime_int(str, &ret, max, mstm->tm_yday+1, alternate ? 0 : 3, 1, 366))
1360 return 0;
1361 break;
1362 case 'm':
1363 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1364 return 0;
1365 break;
1366 case 'M':
1367 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1368 return 0;
1369 break;
1370 #if _MSVCR_VER>=140
1371 case 'n':
1372 str[ret++] = '\n';
1373 break;
1374 #endif
1375 case 'p':
1376 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1377 goto einval_error;
1378 if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ?
1379 STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm)))
1380 return 0;
1381 break;
1382 #if _MSVCR_VER>=140
1383 case 'r':
1384 if(time_data == &cloc_time_data)
1386 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1387 goto einval_error;
1388 if(!strftime_int(str, &ret, max, (mstm->tm_hour + 11) % 12 + 1,
1389 alternate ? 0 : 2, 1, 12))
1390 return 0;
1391 if(ret < max)
1392 str[ret++] = ':';
1393 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1394 return 0;
1395 if(ret < max)
1396 str[ret++] = ':';
1397 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1398 return 0;
1399 if(ret < max)
1400 str[ret++] = ' ';
1401 if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ?
1402 STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm)))
1403 return 0;
1405 else
1407 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1408 return 0;
1410 break;
1411 case 'R':
1412 if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1413 return 0;
1414 if(ret < max)
1415 str[ret++] = ':';
1416 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1417 return 0;
1418 break;
1419 #endif
1420 case 'S':
1421 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1422 return 0;
1423 break;
1424 #if _MSVCR_VER>=140
1425 case 't':
1426 str[ret++] = '\t';
1427 break;
1428 case 'T':
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 if(ret < max)
1436 str[ret++] = ':';
1437 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1438 return 0;
1439 break;
1440 case 'u':
1441 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1442 goto einval_error;
1443 tmp = mstm->tm_wday ? mstm->tm_wday : 7;
1444 if(!strftime_int(str, &ret, max, tmp, 0, 1, 7))
1445 return 0;
1446 break;
1447 #endif
1448 case 'w':
1449 if(!strftime_int(str, &ret, max, mstm->tm_wday, 0, 0, 6))
1450 return 0;
1451 break;
1452 case 'y':
1453 #if _MSVCR_VER>=140
1454 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1455 #else
1456 if(!MSVCRT_CHECK_PMT(year>=1900))
1457 #endif
1458 goto einval_error;
1459 if(!strftime_int(str, &ret, max, year%100, alternate ? 0 : 2, 0, 99))
1460 return 0;
1461 break;
1462 case 'Y':
1463 if(!strftime_int(str, &ret, max, year, alternate ? 0 : 4, 0, 9999))
1464 return 0;
1465 break;
1466 case 'z':
1467 #if _MSVCR_VER>=140
1468 MSVCRT__tzset();
1469 if(!strftime_tzdiff(str, &ret, max, mstm->tm_isdst))
1470 return 0;
1471 break;
1472 #endif
1473 case 'Z':
1474 MSVCRT__tzset();
1475 #if _MSVCR_VER <= 90
1476 if(MSVCRT__get_tzname(&tmp, str+ret, max-ret, mstm->tm_isdst ? 1 : 0))
1477 return 0;
1478 #else
1479 if(_mbstowcs_s_l(&tmp, str+ret, max-ret,
1480 mstm->tm_isdst ? tzname_dst : tzname_std,
1481 MSVCRT__TRUNCATE, loc) == STRUNCATE)
1482 ret = max;
1483 #endif
1484 ret += tmp-1;
1485 break;
1486 case 'U':
1487 case 'W':
1488 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1489 goto einval_error;
1490 if(!MSVCRT_CHECK_PMT(mstm->tm_yday>=0 && mstm->tm_yday<=365))
1491 goto einval_error;
1492 if(*format == 'U')
1493 tmp = mstm->tm_wday;
1494 else if(!mstm->tm_wday)
1495 tmp = 6;
1496 else
1497 tmp = mstm->tm_wday-1;
1499 tmp = mstm->tm_yday/7 + (tmp<=mstm->tm_yday%7);
1500 if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 0, 53))
1501 return 0;
1502 break;
1503 case '%':
1504 str[ret++] = '%';
1505 break;
1506 default:
1507 WARN("unknown format %c\n", *format);
1508 MSVCRT_INVALID_PMT("unknown format", EINVAL);
1509 goto einval_error;
1513 if(ret == max) {
1514 if(max)
1515 *str = 0;
1516 *_errno() = ERANGE;
1517 return 0;
1520 str[ret] = 0;
1521 return ret;
1523 einval_error:
1524 *str = 0;
1525 return 0;
1528 static size_t strftime_helper(char *str, size_t max, const char *format,
1529 const struct tm *mstm, __lc_time_data *time_data, _locale_t loc)
1531 #if _MSVCR_VER <= 90
1532 TRACE("(%p %Iu %s %p %p %p)\n", str, max, format, mstm, time_data, loc);
1533 return strftime_impl(str, max, format, mstm, time_data, loc);
1534 #else
1535 wchar_t *s, *fmt;
1536 size_t len;
1538 TRACE("(%p %Iu %s %p %p %p)\n", str, max, format, mstm, time_data, loc);
1540 if (!MSVCRT_CHECK_PMT(str != NULL)) return 0;
1541 if (!MSVCRT_CHECK_PMT(max != 0)) return 0;
1542 *str = 0;
1543 if (!MSVCRT_CHECK_PMT(format != NULL)) return 0;
1545 len = _mbstowcs_l( NULL, format, 0, loc ) + 1;
1546 if (!len || !(fmt = malloc( len*sizeof(wchar_t) ))) return 0;
1547 _mbstowcs_l(fmt, format, len, loc);
1549 if ((s = malloc( max*sizeof(wchar_t) )))
1551 len = strftime_impl( s, max, fmt, mstm, time_data, loc );
1552 if (len)
1553 len = MSVCRT__wcstombs_l( str, s, max, loc );
1554 free( s );
1556 else len = 0;
1558 free( fmt );
1559 return len;
1560 #endif
1563 #if _MSVCR_VER >= 80
1564 /********************************************************************
1565 * _strftime_l (MSVCR80.@)
1567 size_t CDECL MSVCRT__strftime_l( char *str, size_t max, const char *format,
1568 const struct tm *mstm, _locale_t loc )
1570 return strftime_helper(str, max, format, mstm, NULL, loc);
1572 #endif
1574 /*********************************************************************
1575 * _Strftime (MSVCRT.@)
1577 size_t CDECL _Strftime(char *str, size_t max, const char *format,
1578 const struct tm *mstm, __lc_time_data *time_data)
1580 return strftime_helper(str, max, format, mstm, time_data, NULL);
1583 /*********************************************************************
1584 * strftime (MSVCRT.@)
1586 size_t CDECL MSVCRT_strftime( char *str, size_t max, const char *format,
1587 const struct tm *mstm )
1589 return strftime_helper(str, max, format, mstm, NULL, NULL);
1592 static size_t wcsftime_helper( wchar_t *str, size_t max,
1593 const wchar_t *format, const struct tm *mstm,
1594 __lc_time_data *time_data, _locale_t loc )
1596 #if _MSVCR_VER <= 90
1597 char *s, *fmt;
1598 size_t len;
1600 TRACE("%p %Iu %s %p %p %p\n", str, max, debugstr_w(format), mstm, time_data, loc);
1602 len = MSVCRT__wcstombs_l( NULL, format, 0, loc ) + 1;
1603 if (!(fmt = malloc( len ))) return 0;
1604 MSVCRT__wcstombs_l(fmt, format, len, loc);
1606 if ((s = malloc( max*4 )))
1608 if (!strftime_impl( s, max*4, fmt, mstm, time_data, loc )) s[0] = 0;
1609 len = _mbstowcs_l( str, s, max, loc );
1610 free( s );
1612 else len = 0;
1614 free( fmt );
1615 return len;
1616 #else
1617 TRACE("%p %Iu %s %p %p %p\n", str, max, debugstr_w(format), mstm, time_data, loc);
1618 return strftime_impl(str, max, format, mstm, time_data, loc);
1619 #endif
1622 /*********************************************************************
1623 * _wcsftime_l (MSVCRT.@)
1625 size_t CDECL MSVCRT__wcsftime_l( wchar_t *str, size_t max,
1626 const wchar_t *format, const struct tm *mstm, _locale_t loc )
1628 return wcsftime_helper(str, max, format, mstm, NULL, loc);
1631 /*********************************************************************
1632 * wcsftime (MSVCRT.@)
1634 size_t CDECL MSVCRT_wcsftime( wchar_t *str, size_t max,
1635 const wchar_t *format, const struct tm *mstm )
1637 return wcsftime_helper(str, max, format, mstm, NULL, NULL);
1640 #if _MSVCR_VER >= 110
1641 /*********************************************************************
1642 * _Wcsftime (MSVCR110.@)
1644 size_t CDECL _Wcsftime(wchar_t *str, size_t max,
1645 const wchar_t *format, const struct tm *mstm,
1646 __lc_time_data *time_data)
1648 return wcsftime_helper(str, max, format, mstm, time_data, NULL);
1650 #endif
1652 static char* asctime_buf(char *buf, const struct tm *mstm)
1654 static const char wday[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
1655 static const char month[12][4] = {"Jan", "Feb", "Mar", "Apr", "May",
1656 "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1658 if (!mstm || mstm->tm_sec<0 || mstm->tm_sec>59
1659 || mstm->tm_min<0 || mstm->tm_min>59
1660 || mstm->tm_hour<0 || mstm->tm_hour>23
1661 || mstm->tm_mon<0 || mstm->tm_mon>11
1662 || mstm->tm_wday<0 || mstm->tm_wday>6
1663 || mstm->tm_year<0 || mstm->tm_mday<0
1664 || mstm->tm_mday>MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon]) {
1665 *_errno() = EINVAL;
1666 return NULL;
1669 #if _MSVCR_VER>=140
1670 /* C89 (4.12.3.1) uses space-padding for day of month. */
1671 MSVCRT__snprintf(buf, 26, "%s %s %2d %02d:%02d:%02d %c%03d\n", wday[mstm->tm_wday],
1672 month[mstm->tm_mon], mstm->tm_mday, mstm->tm_hour, mstm->tm_min,
1673 mstm->tm_sec, '1'+(mstm->tm_year+900)/1000, (900+mstm->tm_year)%1000);
1674 #else
1675 MSVCRT__snprintf(buf, 26, "%s %s %02d %02d:%02d:%02d %c%03d\n", wday[mstm->tm_wday],
1676 month[mstm->tm_mon], mstm->tm_mday, mstm->tm_hour, mstm->tm_min,
1677 mstm->tm_sec, '1'+(mstm->tm_year+900)/1000, (900+mstm->tm_year)%1000);
1678 #endif
1679 return buf;
1682 /*********************************************************************
1683 * asctime (MSVCRT.@)
1685 char * CDECL MSVCRT_asctime(const struct tm *mstm)
1687 thread_data_t *data = msvcrt_get_thread_data();
1689 /* asctime returns date in format that always has exactly 26 characters */
1690 if (!data->asctime_buffer) {
1691 data->asctime_buffer = malloc(26);
1692 if (!data->asctime_buffer) {
1693 *_errno() = ENOMEM;
1694 return NULL;
1698 return asctime_buf(data->asctime_buffer, mstm);
1701 /*********************************************************************
1702 * asctime_s (MSVCRT.@)
1704 int CDECL MSVCRT_asctime_s(char* time, size_t size, const struct tm *mstm)
1706 if (!MSVCRT_CHECK_PMT(time != NULL)) return EINVAL;
1707 if (size) time[0] = 0;
1708 if (!MSVCRT_CHECK_PMT(size >= 26)) return EINVAL;
1709 if (!MSVCRT_CHECK_PMT(mstm != NULL)) return EINVAL;
1710 if (!MSVCRT_CHECK_PMT(mstm->tm_sec >= 0 && mstm->tm_sec < 60)) return EINVAL;
1711 if (!MSVCRT_CHECK_PMT(mstm->tm_min >= 0 && mstm->tm_min < 60)) return EINVAL;
1712 if (!MSVCRT_CHECK_PMT(mstm->tm_hour >= 0 && mstm->tm_hour < 24)) return EINVAL;
1713 if (!MSVCRT_CHECK_PMT(mstm->tm_mon >= 0 && mstm->tm_mon < 12)) return EINVAL;
1714 if (!MSVCRT_CHECK_PMT(mstm->tm_wday >= 0 && mstm->tm_wday < 7)) return EINVAL;
1715 if (!MSVCRT_CHECK_PMT(mstm->tm_year >= 0)) return EINVAL;
1716 if (!MSVCRT_CHECK_PMT(mstm->tm_mday >= 0)) return EINVAL;
1717 if (!MSVCRT_CHECK_PMT(mstm->tm_mday <= MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon])) return EINVAL;
1719 asctime_buf(time, mstm);
1720 return 0;
1723 /*********************************************************************
1724 * _wasctime (MSVCRT.@)
1726 wchar_t * CDECL MSVCRT__wasctime(const struct tm *mstm)
1728 thread_data_t *data = msvcrt_get_thread_data();
1729 char buffer[26];
1731 if(!data->wasctime_buffer) {
1732 data->wasctime_buffer = malloc(26*sizeof(wchar_t));
1733 if(!data->wasctime_buffer) {
1734 *_errno() = ENOMEM;
1735 return NULL;
1739 if(!asctime_buf(buffer, mstm))
1740 return NULL;
1742 MultiByteToWideChar(CP_ACP, 0, buffer, -1, data->wasctime_buffer, 26);
1743 return data->wasctime_buffer;
1746 /*********************************************************************
1747 * _wasctime_s (MSVCRT.@)
1749 int CDECL MSVCRT__wasctime_s(wchar_t* time, size_t size, const struct tm *mstm)
1751 char buffer[26];
1752 int ret;
1754 if (!MSVCRT_CHECK_PMT(time != NULL)) return EINVAL;
1755 if (size) time[0] = 0;
1756 if (!MSVCRT_CHECK_PMT(size >= 26)) return EINVAL;
1757 if (!MSVCRT_CHECK_PMT(mstm != NULL)) return EINVAL;
1759 ret = MSVCRT_asctime_s(buffer, sizeof(buffer), mstm);
1760 if(ret)
1761 return ret;
1762 MultiByteToWideChar(CP_ACP, 0, buffer, -1, time, size);
1763 return 0;
1766 /*********************************************************************
1767 * _ctime64 (MSVCRT.@)
1769 char * CDECL MSVCRT__ctime64(const __time64_t *time)
1771 struct tm *t;
1772 t = MSVCRT__localtime64( time );
1773 if (!t) return NULL;
1774 return MSVCRT_asctime( t );
1777 /*********************************************************************
1778 * _ctime64_s (MSVCRT.@)
1780 int CDECL MSVCRT__ctime64_s(char *res, size_t len, const __time64_t *time)
1782 struct tm *t;
1784 if (!MSVCRT_CHECK_PMT( res != NULL )) return EINVAL;
1785 if (!MSVCRT_CHECK_PMT( len >= 26 )) return EINVAL;
1786 res[0] = '\0';
1787 if (!MSVCRT_CHECK_PMT( time != NULL )) return EINVAL;
1788 if (!MSVCRT_CHECK_PMT( *time > 0 )) return EINVAL;
1790 t = MSVCRT__localtime64( time );
1791 strcpy( res, MSVCRT_asctime( t ) );
1792 return 0;
1795 /*********************************************************************
1796 * _ctime32 (MSVCRT.@)
1798 char * CDECL MSVCRT__ctime32(const __time32_t *time)
1800 struct tm *t;
1801 t = MSVCRT__localtime32( time );
1802 if (!t) return NULL;
1803 return MSVCRT_asctime( t );
1806 /*********************************************************************
1807 * _ctime32_s (MSVCRT.@)
1809 int CDECL MSVCRT__ctime32_s(char *res, size_t len, const __time32_t *time)
1811 struct tm *t;
1813 if (!MSVCRT_CHECK_PMT( res != NULL )) return EINVAL;
1814 if (!MSVCRT_CHECK_PMT( len >= 26 )) return EINVAL;
1815 res[0] = '\0';
1816 if (!MSVCRT_CHECK_PMT( time != NULL )) return EINVAL;
1817 if (!MSVCRT_CHECK_PMT( *time > 0 )) return EINVAL;
1819 t = MSVCRT__localtime32( time );
1820 strcpy( res, MSVCRT_asctime( t ) );
1821 return 0;
1824 /*********************************************************************
1825 * ctime (MSVCRT.@)
1827 #ifdef _WIN64
1828 char * CDECL MSVCRT_ctime(const __time64_t *time)
1830 return MSVCRT__ctime64( time );
1832 #else
1833 char * CDECL MSVCRT_ctime(const __time32_t *time)
1835 return MSVCRT__ctime32( time );
1837 #endif
1839 /*********************************************************************
1840 * _wctime64 (MSVCRT.@)
1842 wchar_t * CDECL MSVCRT__wctime64(const __time64_t *time)
1844 return MSVCRT__wasctime( MSVCRT__localtime64(time) );
1847 /*********************************************************************
1848 * _wctime32 (MSVCRT.@)
1850 wchar_t * CDECL MSVCRT__wctime32(const __time32_t *time)
1852 return MSVCRT__wasctime( MSVCRT__localtime32(time) );
1855 /*********************************************************************
1856 * _wctime (MSVCRT.@)
1858 #ifdef _WIN64
1859 wchar_t * CDECL MSVCRT__wctime(const __time64_t *time)
1861 return MSVCRT__wctime64( time );
1863 #else
1864 wchar_t * CDECL MSVCRT__wctime(const __time32_t *time)
1866 return MSVCRT__wctime32( time );
1868 #endif
1870 /*********************************************************************
1871 * _wctime64_s (MSVCRT.@)
1873 int CDECL MSVCRT__wctime64_s(wchar_t *buf,
1874 size_t size, const __time64_t *time)
1876 struct tm tm;
1877 int ret;
1879 if(!MSVCRT_CHECK_PMT(buf != NULL)) return EINVAL;
1880 if(!MSVCRT_CHECK_PMT(size != 0)) return EINVAL;
1881 buf[0] = 0;
1882 if(!MSVCRT_CHECK_PMT(time != NULL)) return EINVAL;
1883 if(!MSVCRT_CHECK_PMT(*time >= 0)) return EINVAL;
1884 if(!MSVCRT_CHECK_PMT(*time <= _MAX__TIME64_T)) return EINVAL;
1886 ret = _localtime64_s(&tm, time);
1887 if(ret != 0)
1888 return ret;
1890 return MSVCRT__wasctime_s(buf, size, &tm);
1893 /*********************************************************************
1894 * _wctime32_s (MSVCRT.@)
1896 int CDECL MSVCRT__wctime32_s(wchar_t *buf, size_t size,
1897 const __time32_t *time)
1899 struct tm tm;
1900 int ret;
1902 if(!MSVCRT_CHECK_PMT(buf != NULL)) return EINVAL;
1903 if(!MSVCRT_CHECK_PMT(size != 0)) return EINVAL;
1904 buf[0] = 0;
1905 if(!MSVCRT_CHECK_PMT(time != NULL)) return EINVAL;
1906 if(!MSVCRT_CHECK_PMT(*time >= 0)) return EINVAL;
1908 ret = _localtime32_s(&tm, time);
1909 if(ret != 0)
1910 return ret;
1912 return MSVCRT__wasctime_s(buf, size, &tm);
1915 #if _MSVCR_VER >= 80
1917 /*********************************************************************
1918 * _get_timezone (MSVCR80.@)
1920 int CDECL _get_timezone(LONG *timezone)
1922 if(!MSVCRT_CHECK_PMT(timezone != NULL)) return EINVAL;
1924 *timezone = MSVCRT___timezone;
1925 return 0;
1928 /*********************************************************************
1929 * _get_daylight (MSVCR80.@)
1931 int CDECL _get_daylight(int *hours)
1933 if(!MSVCRT_CHECK_PMT(hours != NULL)) return EINVAL;
1935 *hours = MSVCRT___daylight;
1936 return 0;
1939 #endif /* _MSVCR_VER >= 80 */
1941 #if _MSVCR_VER >= 140
1943 #define TIME_UTC 1
1945 struct _timespec32
1947 __time32_t tv_sec;
1948 LONG tv_nsec;
1951 struct _timespec64
1953 __time64_t tv_sec;
1954 LONG tv_nsec;
1957 /*********************************************************************
1958 * _timespec64_get (UCRTBASE.@)
1960 int CDECL _timespec64_get(struct _timespec64 *ts, int base)
1962 ULONGLONG time;
1963 FILETIME ft;
1965 if(!MSVCRT_CHECK_PMT(ts != NULL)) return 0;
1966 if(base != TIME_UTC) return 0;
1968 GetSystemTimePreciseAsFileTime(&ft);
1969 time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
1971 ts->tv_sec = time / TICKSPERSEC - SECS_1601_TO_1970;
1972 ts->tv_nsec = time % TICKSPERSEC * 100;
1973 return base;
1976 /*********************************************************************
1977 * _timespec32_get (UCRTBASE.@)
1979 int CDECL _timespec32_get(struct _timespec32 *ts, int base)
1981 struct _timespec64 ts64;
1983 if(!MSVCRT_CHECK_PMT(ts != NULL)) return 0;
1984 if(base != TIME_UTC) return 0;
1986 if(_timespec64_get(&ts64, base) != base)
1987 return 0;
1988 if(ts64.tv_sec != (__time32_t)ts64.tv_sec)
1989 return 0;
1991 ts->tv_sec = ts64.tv_sec;
1992 ts->tv_nsec = ts64.tv_nsec;
1993 return base;
1995 #endif /* _MSVCR_VER >= 140 */