wined3d: Get rid of redundant DISCARD filtering.
[wine.git] / dlls / msvcrt / time.c
blob0e69bec9916f71bc1877afabb940e54773c9bbdd
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 #undef _ctime32
39 #undef _difftime32
40 #undef _gmtime32
41 #undef _localtime32
42 #undef _mktime32
43 #undef _time32
44 #undef _wctime32
46 BOOL WINAPI GetDaylightFlag(void);
48 static LONGLONG init_time;
50 void msvcrt_init_clock(void)
52 LARGE_INTEGER systime;
54 NtQuerySystemTime(&systime);
55 init_time = systime.QuadPart;
58 static const int MonthLengths[2][12] =
60 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
61 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
64 #if _MSVCR_VER>=140
65 static const int MAX_SECONDS = 60;
66 #else
67 static const int MAX_SECONDS = 59;
68 #endif
70 static inline BOOL IsLeapYear(int Year)
72 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
75 static inline void write_invalid_msvcrt_tm( struct tm *tm )
77 tm->tm_sec = -1;
78 tm->tm_min = -1;
79 tm->tm_hour = -1;
80 tm->tm_mday = -1;
81 tm->tm_mon = -1;
82 tm->tm_year = -1;
83 tm->tm_wday = -1;
84 tm->tm_yday = -1;
85 tm->tm_isdst = -1;
88 /*********************************************************************
89 * _daylight (MSVCRT.@)
91 int MSVCRT___daylight = 1;
93 /*********************************************************************
94 * _timezone (MSVCRT.@)
96 __msvcrt_long MSVCRT___timezone = 28800;
98 /*********************************************************************
99 * _dstbias (MSVCRT.@)
101 __msvcrt_long MSVCRT__dstbias = -3600;
103 /*********************************************************************
104 * _tzname (MSVCRT.@)
105 * NOTES
106 * Some apps (notably Mozilla) insist on writing to these, so the buffer
107 * must be large enough.
109 static char tzname_std[64] = "PST";
110 static char tzname_dst[64] = "PDT";
111 char *MSVCRT__tzname[2] = { tzname_std, tzname_dst };
113 static TIME_ZONE_INFORMATION tzi = {0};
114 /*********************************************************************
115 * _tzset (MSVCRT.@)
117 void CDECL _tzset(void)
119 char *tz = getenv("TZ");
120 BOOL error;
122 _lock(_TIME_LOCK);
123 if(tz && tz[0]) {
124 BOOL neg_zone = FALSE;
126 memset(&tzi, 0, sizeof(tzi));
128 /* Parse timezone information: tzn[+|-]hh[:mm[:ss]][dzn] */
129 lstrcpynA(MSVCRT__tzname[0], tz, 3);
130 tz += 3;
132 if(*tz == '-') {
133 neg_zone = TRUE;
134 tz++;
135 }else if(*tz == '+') {
136 tz++;
138 MSVCRT___timezone = strtol(tz, &tz, 10)*3600;
139 if(*tz == ':') {
140 MSVCRT___timezone += strtol(tz+1, &tz, 10)*60;
141 if(*tz == ':')
142 MSVCRT___timezone += strtol(tz+1, &tz, 10);
144 if(neg_zone)
145 MSVCRT___timezone = -MSVCRT___timezone;
147 MSVCRT___daylight = *tz;
148 lstrcpynA(MSVCRT__tzname[1], tz, 3);
149 }else if(GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
150 MSVCRT___timezone = tzi.Bias*60;
151 if(tzi.StandardDate.wMonth)
152 MSVCRT___timezone += tzi.StandardBias*60;
154 if(tzi.DaylightDate.wMonth) {
155 MSVCRT___daylight = 1;
156 MSVCRT__dstbias = (tzi.DaylightBias-tzi.StandardBias)*60;
157 }else {
158 MSVCRT___daylight = 0;
159 MSVCRT__dstbias = 0;
162 if(!WideCharToMultiByte(CP_ACP, 0, tzi.StandardName, -1, MSVCRT__tzname[0],
163 sizeof(tzname_std), NULL, &error) || error)
164 *MSVCRT__tzname[0] = 0;
165 if(!WideCharToMultiByte(CP_ACP, 0, tzi.DaylightName, -1, MSVCRT__tzname[1],
166 sizeof(tzname_dst), NULL, &error) || error)
167 *MSVCRT__tzname[0] = 0;
169 _unlock(_TIME_LOCK);
172 static void _tzset_init(void)
174 static BOOL init = FALSE;
176 if(!init) {
177 _lock(_TIME_LOCK);
178 if(!init) {
179 _tzset();
180 init = TRUE;
182 _unlock(_TIME_LOCK);
186 static BOOL is_dst(const SYSTEMTIME *st)
188 TIME_ZONE_INFORMATION tmp;
189 SYSTEMTIME out;
191 if(!MSVCRT___daylight)
192 return FALSE;
194 if(tzi.DaylightDate.wMonth) {
195 tmp = tzi;
196 }else if(st->wYear >= 2007) {
197 memset(&tmp, 0, sizeof(tmp));
198 tmp.StandardDate.wMonth = 11;
199 tmp.StandardDate.wDay = 1;
200 tmp.StandardDate.wHour = 2;
201 tmp.DaylightDate.wMonth = 3;
202 tmp.DaylightDate.wDay = 2;
203 tmp.DaylightDate.wHour = 2;
204 }else {
205 memset(&tmp, 0, sizeof(tmp));
206 tmp.StandardDate.wMonth = 10;
207 tmp.StandardDate.wDay = 5;
208 tmp.StandardDate.wHour = 2;
209 tmp.DaylightDate.wMonth = 4;
210 tmp.DaylightDate.wDay = 1;
211 tmp.DaylightDate.wHour = 2;
214 tmp.Bias = 0;
215 tmp.StandardBias = 0;
216 tmp.DaylightBias = MSVCRT__dstbias/60;
217 if(!SystemTimeToTzSpecificLocalTime(&tmp, st, &out))
218 return FALSE;
220 return memcmp(st, &out, sizeof(SYSTEMTIME));
223 #define SECSPERDAY 86400
224 /* 1601 to 1970 is 369 years plus 89 leap days */
225 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
226 #define TICKSPERSEC 10000000
227 #define TICKSPERMSEC 10000
228 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
230 static __time64_t mktime_helper(struct tm *mstm, BOOL local)
232 SYSTEMTIME st;
233 FILETIME ft;
234 __time64_t ret = 0;
235 int i;
236 BOOL use_dst = FALSE;
238 ret = mstm->tm_year + mstm->tm_mon/12;
239 mstm->tm_mon %= 12;
240 if(mstm->tm_mon < 0) {
241 mstm->tm_mon += 12;
242 ret--;
245 if(ret<70 || ret>1100) {
246 *_errno() = EINVAL;
247 return -1;
250 memset(&st, 0, sizeof(SYSTEMTIME));
251 st.wDay = 1;
252 st.wMonth = mstm->tm_mon+1;
253 st.wYear = ret+1900;
255 if(!SystemTimeToFileTime(&st, &ft)) {
256 *_errno() = EINVAL;
257 return -1;
260 ret = ((__time64_t)ft.dwHighDateTime<<32)+ft.dwLowDateTime;
261 ret += (__time64_t)mstm->tm_sec*TICKSPERSEC;
262 ret += (__time64_t)mstm->tm_min*60*TICKSPERSEC;
263 ret += (__time64_t)mstm->tm_hour*60*60*TICKSPERSEC;
264 ret += (__time64_t)(mstm->tm_mday-1)*SECSPERDAY*TICKSPERSEC;
266 ft.dwLowDateTime = ret & 0xffffffff;
267 ft.dwHighDateTime = ret >> 32;
268 FileTimeToSystemTime(&ft, &st);
270 if(local) {
271 _tzset_init();
272 use_dst = is_dst(&st);
273 if((mstm->tm_isdst<=-1 && use_dst) || (mstm->tm_isdst>=1)) {
274 SYSTEMTIME tmp;
276 ret += (__time64_t)MSVCRT__dstbias*TICKSPERSEC;
278 ft.dwLowDateTime = ret & 0xffffffff;
279 ft.dwHighDateTime = ret >> 32;
280 FileTimeToSystemTime(&ft, &tmp);
282 if(!is_dst(&tmp)) {
283 st = tmp;
284 use_dst = FALSE;
285 }else {
286 use_dst = TRUE;
288 }else if(mstm->tm_isdst==0 && use_dst) {
289 ret -= (__time64_t)MSVCRT__dstbias*TICKSPERSEC;
290 ft.dwLowDateTime = ret & 0xffffffff;
291 ft.dwHighDateTime = ret >> 32;
292 FileTimeToSystemTime(&ft, &st);
293 ret += (__time64_t)MSVCRT__dstbias*TICKSPERSEC;
295 ret += (__time64_t)MSVCRT___timezone*TICKSPERSEC;
298 mstm->tm_sec = st.wSecond;
299 mstm->tm_min = st.wMinute;
300 mstm->tm_hour = st.wHour;
301 mstm->tm_mday = st.wDay;
302 mstm->tm_mon = st.wMonth-1;
303 mstm->tm_year = st.wYear-1900;
304 mstm->tm_wday = st.wDayOfWeek;
305 for(i=mstm->tm_yday=0; i<st.wMonth-1; i++)
306 mstm->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
307 mstm->tm_yday += st.wDay-1;
308 mstm->tm_isdst = use_dst ? 1 : 0;
310 if(ret < TICKS_1601_TO_1970) {
311 *_errno() = EINVAL;
312 return -1;
314 ret = (ret-TICKS_1601_TO_1970)/TICKSPERSEC;
315 return ret;
318 /**********************************************************************
319 * _mktime64 (MSVCRT.@)
321 __time64_t CDECL _mktime64(struct tm *mstm)
323 return mktime_helper(mstm, TRUE);
326 /**********************************************************************
327 * _mktime32 (MSVCRT.@)
329 __time32_t CDECL _mktime32(struct tm *mstm)
331 __time64_t ret = _mktime64( mstm );
332 return ret == (__time32_t)ret ? ret : -1;
335 /**********************************************************************
336 * _mkgmtime64 (MSVCRT.@)
338 * time->tm_isdst value is ignored
340 __time64_t CDECL _mkgmtime64(struct tm *time)
342 return mktime_helper(time, FALSE);
345 /**********************************************************************
346 * _mkgmtime32 (MSVCRT.@)
348 __time32_t CDECL _mkgmtime32(struct tm *time)
350 __time64_t ret = _mkgmtime64(time);
351 return ret == (__time32_t)ret ? ret : -1;
354 /*********************************************************************
355 * _localtime64_s (MSVCRT.@)
357 int CDECL _localtime64_s(struct tm *res, const __time64_t *secs)
359 int i;
360 FILETIME ft;
361 SYSTEMTIME st;
362 ULONGLONG time;
364 if (!res || !secs || *secs < 0 || *secs > _MAX__TIME64_T)
366 if (res)
367 write_invalid_msvcrt_tm(res);
369 *_errno() = EINVAL;
370 return EINVAL;
373 _tzset_init();
374 time = (*secs - MSVCRT___timezone) * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
376 ft.dwHighDateTime = (UINT)(time >> 32);
377 ft.dwLowDateTime = (UINT)time;
378 FileTimeToSystemTime(&ft, &st);
380 res->tm_isdst = is_dst(&st) ? 1 : 0;
381 if(res->tm_isdst) {
382 time -= MSVCRT__dstbias * (ULONGLONG)TICKSPERSEC;
383 ft.dwHighDateTime = (UINT)(time >> 32);
384 ft.dwLowDateTime = (UINT)time;
385 FileTimeToSystemTime(&ft, &st);
388 res->tm_sec = st.wSecond;
389 res->tm_min = st.wMinute;
390 res->tm_hour = st.wHour;
391 res->tm_mday = st.wDay;
392 res->tm_year = st.wYear - 1900;
393 res->tm_mon = st.wMonth - 1;
394 res->tm_wday = st.wDayOfWeek;
395 for (i = res->tm_yday = 0; i < st.wMonth - 1; i++)
396 res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
397 res->tm_yday += st.wDay - 1;
399 return 0;
402 /*********************************************************************
403 * _localtime64 (MSVCRT.@)
405 struct tm* CDECL _localtime64(const __time64_t* secs)
407 thread_data_t *data = msvcrt_get_thread_data();
409 if(!data->time_buffer)
410 data->time_buffer = malloc(sizeof(struct tm));
412 if(_localtime64_s(data->time_buffer, secs))
413 return NULL;
414 return data->time_buffer;
417 /*********************************************************************
418 * _localtime32 (MSVCRT.@)
420 struct tm* CDECL _localtime32(const __time32_t* secs)
422 __time64_t secs64;
424 if(!secs)
425 return NULL;
427 secs64 = *secs;
428 return _localtime64( &secs64 );
431 /*********************************************************************
432 * _localtime32_s (MSVCRT.@)
434 int CDECL _localtime32_s(struct tm *time, const __time32_t *secs)
436 __time64_t secs64;
438 if (!time || !secs || *secs < 0)
440 if (time)
441 write_invalid_msvcrt_tm(time);
443 *_errno() = EINVAL;
444 return EINVAL;
447 secs64 = *secs;
448 return _localtime64_s(time, &secs64);
451 /*********************************************************************
452 * _gmtime64 (MSVCRT.@)
454 int CDECL _gmtime64_s(struct tm *res, const __time64_t *secs)
456 int i;
457 FILETIME ft;
458 SYSTEMTIME st;
459 ULONGLONG time;
461 if (!res || !secs || *secs < 0 || *secs > _MAX__TIME64_T) {
462 if (res) {
463 write_invalid_msvcrt_tm(res);
466 *_errno() = EINVAL;
467 return EINVAL;
470 time = *secs * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
472 ft.dwHighDateTime = (UINT)(time >> 32);
473 ft.dwLowDateTime = (UINT)time;
475 FileTimeToSystemTime(&ft, &st);
477 res->tm_sec = st.wSecond;
478 res->tm_min = st.wMinute;
479 res->tm_hour = st.wHour;
480 res->tm_mday = st.wDay;
481 res->tm_year = st.wYear - 1900;
482 res->tm_mon = st.wMonth - 1;
483 res->tm_wday = st.wDayOfWeek;
484 for (i = res->tm_yday = 0; i < st.wMonth - 1; i++) {
485 res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
488 res->tm_yday += st.wDay - 1;
489 res->tm_isdst = 0;
491 return 0;
494 /*********************************************************************
495 * _gmtime64 (MSVCRT.@)
497 struct tm* CDECL _gmtime64(const __time64_t *secs)
499 thread_data_t * const data = msvcrt_get_thread_data();
501 if(!data->time_buffer)
502 data->time_buffer = malloc(sizeof(struct tm));
504 if(_gmtime64_s(data->time_buffer, secs))
505 return NULL;
506 return data->time_buffer;
509 /*********************************************************************
510 * _gmtime32_s (MSVCRT.@)
512 int CDECL _gmtime32_s(struct tm *res, const __time32_t *secs)
514 __time64_t secs64;
516 if(secs) {
517 secs64 = *secs;
518 return _gmtime64_s(res, &secs64);
520 return _gmtime64_s(res, NULL);
523 /*********************************************************************
524 * _gmtime32 (MSVCRT.@)
526 struct tm* CDECL _gmtime32(const __time32_t* secs)
528 __time64_t secs64;
530 if(!secs)
531 return NULL;
533 secs64 = *secs;
534 return _gmtime64( &secs64 );
537 /**********************************************************************
538 * _strdate (MSVCRT.@)
540 char* CDECL _strdate(char* date)
542 GetDateFormatA(LOCALE_NEUTRAL, 0, NULL, "MM'/'dd'/'yy", date, 9);
543 return date;
546 /**********************************************************************
547 * _strdate_s (MSVCRT.@)
549 int CDECL _strdate_s(char* date, size_t size)
551 if(date && size)
552 date[0] = '\0';
554 if(!date) {
555 *_errno() = EINVAL;
556 return EINVAL;
559 if(size < 9) {
560 *_errno() = ERANGE;
561 return ERANGE;
564 _strdate(date);
565 return 0;
568 /**********************************************************************
569 * _wstrdate (MSVCRT.@)
571 wchar_t* CDECL _wstrdate(wchar_t* date)
573 GetDateFormatW(LOCALE_NEUTRAL, 0, NULL, L"MM'/'dd'/'yy", date, 9);
574 return date;
577 /**********************************************************************
578 * _wstrdate_s (MSVCRT.@)
580 int CDECL _wstrdate_s(wchar_t* date, size_t size)
582 if(date && size)
583 date[0] = '\0';
585 if(!date) {
586 *_errno() = EINVAL;
587 return EINVAL;
590 if(size < 9) {
591 *_errno() = ERANGE;
592 return ERANGE;
595 _wstrdate(date);
596 return 0;
599 /*********************************************************************
600 * _strtime (MSVCRT.@)
602 char* CDECL _strtime(char* time)
604 GetTimeFormatA(LOCALE_NEUTRAL, 0, NULL, "HH':'mm':'ss", time, 9);
605 return time;
608 /*********************************************************************
609 * _strtime_s (MSVCRT.@)
611 int CDECL _strtime_s(char* time, size_t size)
613 if(time && size)
614 time[0] = '\0';
616 if(!time) {
617 *_errno() = EINVAL;
618 return EINVAL;
621 if(size < 9) {
622 *_errno() = ERANGE;
623 return ERANGE;
626 _strtime(time);
627 return 0;
630 /*********************************************************************
631 * _wstrtime (MSVCRT.@)
633 wchar_t* CDECL _wstrtime(wchar_t* time)
635 GetTimeFormatW(LOCALE_NEUTRAL, 0, NULL, L"HH':'mm':'ss", time, 9);
636 return time;
639 /*********************************************************************
640 * _wstrtime_s (MSVCRT.@)
642 int CDECL _wstrtime_s(wchar_t* time, size_t size)
644 if(time && size)
645 time[0] = '\0';
647 if(!time) {
648 *_errno() = EINVAL;
649 return EINVAL;
652 if(size < 9) {
653 *_errno() = ERANGE;
654 return ERANGE;
657 _wstrtime(time);
658 return 0;
661 /*********************************************************************
662 * clock (MSVCRT.@)
664 clock_t CDECL clock(void)
666 LARGE_INTEGER systime;
668 NtQuerySystemTime(&systime);
669 return (systime.QuadPart - init_time) / (TICKSPERSEC / MSVCRT_CLOCKS_PER_SEC);
672 /*********************************************************************
673 * _difftime64 (MSVCRT.@)
675 double CDECL _difftime64(__time64_t time1, __time64_t time2)
677 return (double)(time1 - time2);
680 /*********************************************************************
681 * _difftime32 (MSVCRT.@)
683 double CDECL _difftime32(__time32_t time1, __time32_t time2)
685 return (double)(time1 - time2);
688 /*********************************************************************
689 * _ftime64 (MSVCRT.@)
691 void CDECL _ftime64(struct __timeb64 *buf)
693 FILETIME ft;
694 ULONGLONG time;
696 _tzset_init();
698 GetSystemTimeAsFileTime(&ft);
700 time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
702 buf->time = time / TICKSPERSEC - SECS_1601_TO_1970;
703 buf->millitm = (time % TICKSPERSEC) / TICKSPERMSEC;
704 buf->timezone = MSVCRT___timezone / 60;
705 buf->dstflag = GetDaylightFlag();
708 /*********************************************************************
709 * _ftime64_s (MSVCRT.@)
711 int CDECL _ftime64_s(struct __timeb64 *buf)
713 if (!MSVCRT_CHECK_PMT( buf != NULL )) return EINVAL;
714 _ftime64(buf);
715 return 0;
718 /*********************************************************************
719 * _ftime32 (MSVCRT.@)
721 void CDECL _ftime32(struct __timeb32 *buf)
723 struct __timeb64 buf64;
725 _ftime64( &buf64 );
726 buf->time = buf64.time;
727 buf->millitm = buf64.millitm;
728 buf->timezone = buf64.timezone;
729 buf->dstflag = buf64.dstflag;
732 /*********************************************************************
733 * _ftime32_s (MSVCRT.@)
735 int CDECL _ftime32_s(struct __timeb32 *buf)
737 if (!MSVCRT_CHECK_PMT( buf != NULL )) return EINVAL;
738 _ftime32(buf);
739 return 0;
742 /*********************************************************************
743 * _time64 (MSVCRT.@)
745 __time64_t CDECL _time64(__time64_t *buf)
747 __time64_t curtime;
748 struct __timeb64 tb;
750 _ftime64(&tb);
752 curtime = tb.time;
753 return buf ? *buf = curtime : curtime;
756 /*********************************************************************
757 * _time32 (MSVCRT.@)
759 __time32_t CDECL _time32(__time32_t *buf)
761 __time32_t curtime;
762 struct __timeb64 tb;
764 _ftime64(&tb);
766 curtime = tb.time;
767 return buf ? *buf = curtime : curtime;
770 /*********************************************************************
771 * __p__daylight (MSVCRT.@)
773 int * CDECL __p__daylight(void)
775 return &MSVCRT___daylight;
778 /*********************************************************************
779 * __p__dstbias (MSVCRT.@)
781 __msvcrt_long * CDECL __p__dstbias(void)
783 return &MSVCRT__dstbias;
786 #if _MSVCR_VER >= 80
787 /*********************************************************************
788 * _get_dstbias (MSVCR80.@)
790 int CDECL _get_dstbias(int *seconds)
792 if (!MSVCRT_CHECK_PMT(seconds != NULL)) return EINVAL;
793 *seconds = MSVCRT__dstbias;
794 return 0;
796 #endif
798 /*********************************************************************
799 * __p__timezone (MSVCRT.@)
801 __msvcrt_long * CDECL __p__timezone(void)
803 return &MSVCRT___timezone;
806 /*********************************************************************
807 * _get_tzname (MSVCRT.@)
809 int CDECL _get_tzname(size_t *ret, char *buf, size_t bufsize, int index)
811 char *timezone;
813 switch(index)
815 case 0:
816 timezone = tzname_std;
817 break;
818 case 1:
819 timezone = tzname_dst;
820 break;
821 default:
822 *_errno() = EINVAL;
823 return EINVAL;
826 if(!ret || (!buf && bufsize > 0) || (buf && !bufsize))
828 *_errno() = EINVAL;
829 return EINVAL;
832 *ret = strlen(timezone)+1;
833 if(!buf && !bufsize)
834 return 0;
835 if(*ret > bufsize)
837 buf[0] = 0;
838 return ERANGE;
841 strcpy(buf, timezone);
842 return 0;
845 /*********************************************************************
846 * __p_tzname (MSVCRT.@)
848 char ** CDECL __p__tzname(void)
850 return MSVCRT__tzname;
853 #if _MSVCR_VER <= 90
854 #define STRFTIME_CHAR char
855 #define STRFTIME_TD(td, name) td->str.names.name
856 #else
857 #define STRFTIME_CHAR wchar_t
858 #define STRFTIME_TD(td, name) td->wstr.names.name
859 #endif
861 #define strftime_str(a,b,c,d) strftime_nstr(a,b,c,d,SIZE_MAX)
862 static inline BOOL strftime_nstr(STRFTIME_CHAR *str, size_t *pos,
863 size_t max, const STRFTIME_CHAR *src, size_t len)
865 while(*src && len)
867 if(*pos >= max) {
868 *str = 0;
869 *_errno() = ERANGE;
870 return FALSE;
873 str[*pos] = *src;
874 src++;
875 *pos += 1;
876 len--;
878 return TRUE;
881 static inline BOOL strftime_int(STRFTIME_CHAR *str, size_t *pos, size_t max,
882 int src, int prec, int l, int h)
884 size_t len;
886 if(!MSVCRT_CHECK_PMT(src>=l && src<=h)) {
887 *str = 0;
888 return FALSE;
891 #if _MSVCR_VER <= 90
892 len = _snprintf(str+*pos, max-*pos, "%0*d", prec, src);
893 #else
894 len = _snwprintf(str+*pos, max-*pos, L"%0*d", prec, src);
895 #endif
896 if(len == -1) {
897 *str = 0;
898 *_errno() = ERANGE;
899 return FALSE;
902 *pos += len;
903 return TRUE;
906 static inline BOOL strftime_format(STRFTIME_CHAR *str, size_t *pos, size_t max,
907 const struct tm *mstm, __lc_time_data *time_data, const STRFTIME_CHAR *format)
909 size_t count;
910 BOOL ret = TRUE;
912 while(*format && ret)
914 count = 1;
915 while(format[0] == format[count]) count++;
917 switch(*format) {
918 case '\'':
919 if(count % 2 == 0) break;
921 format += count;
922 count = 0;
923 while(format[count] && format[count] != '\'') count++;
925 ret = strftime_nstr(str, pos, max, format, count);
926 if(!ret) return FALSE;
927 if(format[count] == '\'') count++;
928 break;
929 case 'd':
930 if(count > 2)
932 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
934 *str = 0;
935 return FALSE;
938 switch(count) {
939 case 1:
940 case 2:
941 ret = strftime_int(str, pos, max, mstm->tm_mday, count==1 ? 0 : 2, 1, 31);
942 break;
943 case 3:
944 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, short_wday)[mstm->tm_wday]);
945 break;
946 default:
947 ret = strftime_nstr(str, pos, max, format, count-4);
948 if(ret)
949 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, wday)[mstm->tm_wday]);
950 break;
952 break;
953 case 'M':
954 if(count > 2)
956 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
958 *str = 0;
959 return FALSE;
962 switch(count) {
963 case 1:
964 case 2:
965 ret = strftime_int(str, pos, max, mstm->tm_mon+1, count==1 ? 0 : 2, 1, 12);
966 break;
967 case 3:
968 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, short_mon)[mstm->tm_mon]);
969 break;
970 default:
971 ret = strftime_nstr(str, pos, max, format, count-4);
972 if(ret)
973 ret = strftime_str(str, pos, max, STRFTIME_TD(time_data, mon)[mstm->tm_mon]);
974 break;
976 break;
977 case 'y':
978 if(count > 1)
980 #if _MSVCR_VER>=140
981 if(!MSVCRT_CHECK_PMT(mstm->tm_year >= -1900 && mstm->tm_year <= 8099))
982 #else
983 if(!MSVCRT_CHECK_PMT(mstm->tm_year >= 0))
984 #endif
986 *str = 0;
987 return FALSE;
991 switch(count) {
992 case 1:
993 ret = strftime_nstr(str, pos, max, format, 1);
994 break;
995 case 2:
996 case 3:
997 ret = strftime_nstr(str, pos, max, format, count-2);
998 if(ret)
999 ret = strftime_int(str, pos, max, (mstm->tm_year+1900)%100, 2, 0, 99);
1000 break;
1001 default:
1002 ret = strftime_nstr(str, pos, max, format, count-4);
1003 if(ret)
1004 ret = strftime_int(str, pos, max, mstm->tm_year+1900, 4, 0, 9999);
1005 break;
1007 break;
1008 case 'h':
1009 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1011 *str = 0;
1012 return FALSE;
1014 if(count > 2)
1015 ret = strftime_nstr(str, pos, max, format, count-2);
1016 if(ret)
1017 ret = strftime_int(str, pos, max, (mstm->tm_hour + 11) % 12 + 1,
1018 count == 1 ? 0 : 2, 1, 12);
1019 break;
1020 case 'H':
1021 if(count > 2)
1022 ret = strftime_nstr(str, pos, max, format, count-2);
1023 if(ret)
1024 ret = strftime_int(str, pos, max, mstm->tm_hour, count == 1 ? 0 : 2, 0, 23);
1025 break;
1026 case 'm':
1027 if(count > 2)
1028 ret = strftime_nstr(str, pos, max, format, count-2);
1029 if(ret)
1030 ret = strftime_int(str, pos, max, mstm->tm_min, count == 1 ? 0 : 2, 0, 59);
1031 break;
1032 case 's':
1033 if(count > 2)
1034 ret = strftime_nstr(str, pos, max, format, count-2);
1035 if(ret)
1036 ret = strftime_int(str, pos, max, mstm->tm_sec, count == 1 ? 0 : 2, 0, MAX_SECONDS);
1037 break;
1038 case 'a':
1039 case 'A':
1040 case 't':
1041 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1043 *str = 0;
1044 return FALSE;
1046 ret = strftime_nstr(str, pos, max,
1047 mstm->tm_hour < 12 ? STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm),
1048 (*format == 't' && count == 1) ? 1 : SIZE_MAX);
1049 break;
1050 default:
1051 ret = strftime_nstr(str, pos, max, format, count);
1052 break;
1054 format += count;
1057 return ret;
1060 #if _MSVCR_VER>=140
1061 static inline BOOL strftime_tzdiff(STRFTIME_CHAR *str, size_t *pos, size_t max, BOOL is_dst)
1063 __msvcrt_long tz = MSVCRT___timezone + (is_dst ? MSVCRT__dstbias : 0);
1064 char sign;
1066 if(tz < 0) {
1067 sign = '+';
1068 tz = -tz;
1069 }else {
1070 sign = '-';
1073 if(*pos < max)
1074 str[(*pos)++] = sign;
1075 if(!strftime_int(str, pos, max, tz/60/60, 2, 0, 99))
1076 return FALSE;
1077 return strftime_int(str, pos, max, tz/60%60, 2, 0, 59);
1079 #endif
1081 static size_t strftime_impl(STRFTIME_CHAR *str, size_t max,
1082 const STRFTIME_CHAR *format, const struct tm *mstm,
1083 __lc_time_data *time_data, _locale_t loc)
1085 size_t ret, tmp;
1086 BOOL alternate;
1087 int year = mstm ? mstm->tm_year + 1900 : -1;
1089 if(!str || !format) {
1090 if(str && max)
1091 *str = 0;
1092 *_errno() = EINVAL;
1093 return 0;
1096 if(!time_data)
1097 time_data = loc ? loc->locinfo->lc_time_curr : get_locinfo()->lc_time_curr;
1099 for(ret=0; *format && ret<max; format++) {
1100 if(*format != '%') {
1101 if(_isleadbyte_l((unsigned char)*format, loc)) {
1102 str[ret++] = *(format++);
1103 if(ret == max) continue;
1104 if(!MSVCRT_CHECK_PMT(str[ret]))
1105 goto einval_error;
1107 str[ret++] = *format;
1108 continue;
1111 format++;
1112 if(*format == '#') {
1113 alternate = TRUE;
1114 format++;
1115 }else {
1116 alternate = FALSE;
1119 if(!MSVCRT_CHECK_PMT(mstm))
1120 goto einval_error;
1122 switch(*format) {
1123 case 'c':
1124 #if _MSVCR_VER>=140
1125 if(time_data == &cloc_time_data && !alternate)
1127 tmp = strftime_impl(str+ret, max-ret, L"%a %b %e %T %Y", mstm, time_data, loc);
1128 if(!tmp)
1129 return 0;
1130 ret += tmp;
1131 break;
1133 #endif
1134 if(!strftime_format(str, &ret, max, mstm, time_data,
1135 alternate ? STRFTIME_TD(time_data, date) : STRFTIME_TD(time_data, short_date)))
1136 return 0;
1137 if(ret < max)
1138 str[ret++] = ' ';
1139 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1140 return 0;
1141 break;
1142 case 'x':
1143 if(!strftime_format(str, &ret, max, mstm, time_data,
1144 alternate ? STRFTIME_TD(time_data, date) : STRFTIME_TD(time_data, short_date)))
1145 return 0;
1146 break;
1147 case 'X':
1148 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1149 return 0;
1150 break;
1151 case 'a':
1152 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1153 goto einval_error;
1154 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, short_wday)[mstm->tm_wday]))
1155 return 0;
1156 break;
1157 case 'A':
1158 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1159 goto einval_error;
1160 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, wday)[mstm->tm_wday]))
1161 return 0;
1162 break;
1163 case 'b':
1164 #if _MSVCR_VER>=140
1165 case 'h':
1166 #endif
1167 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
1168 goto einval_error;
1169 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, short_mon)[mstm->tm_mon]))
1170 return 0;
1171 break;
1172 case 'B':
1173 if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11))
1174 goto einval_error;
1175 if(!strftime_str(str, &ret, max, STRFTIME_TD(time_data, mon)[mstm->tm_mon]))
1176 return 0;
1177 break;
1178 #if _MSVCR_VER>=140
1179 case 'C':
1180 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1181 goto einval_error;
1182 if(!strftime_int(str, &ret, max, year/100, alternate ? 0 : 2, 0, 99))
1183 return 0;
1184 break;
1185 #endif
1186 case 'd':
1187 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1188 return 0;
1189 break;
1190 #if _MSVCR_VER>=140
1191 case 'D':
1192 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1193 goto einval_error;
1194 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1195 return 0;
1196 if(ret < max)
1197 str[ret++] = '/';
1198 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1199 return 0;
1200 if(ret < max)
1201 str[ret++] = '/';
1202 if(!strftime_int(str, &ret, max, year%100, alternate ? 0 : 2, 0, 99))
1203 return 0;
1204 break;
1205 case 'e':
1206 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1207 return 0;
1208 if(!alternate && str[ret-2] == '0')
1209 str[ret-2] = ' ';
1210 break;
1211 case 'F':
1212 if(!strftime_int(str, &ret, max, year, alternate ? 0 : 4, 0, 9999))
1213 return 0;
1214 if(ret < max)
1215 str[ret++] = '-';
1216 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1217 return 0;
1218 if(ret < max)
1219 str[ret++] = '-';
1220 if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 1, 31))
1221 return 0;
1222 break;
1223 case 'g':
1224 case 'G':
1225 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1226 goto einval_error;
1227 /* fall through */
1228 case 'V':
1230 int iso_year = year;
1231 int iso_days = mstm->tm_yday - (mstm->tm_wday ? mstm->tm_wday : 7) + 4;
1232 if (iso_days < 0)
1233 iso_days += 365 + IsLeapYear(--iso_year);
1234 else if(iso_days >= 365 + IsLeapYear(iso_year))
1235 iso_days -= 365 + IsLeapYear(iso_year++);
1237 if(*format == 'G') {
1238 if(!strftime_int(str, &ret, max, iso_year, 4, 0, 9999))
1239 return 0;
1240 } else if(*format == 'g') {
1241 if(!strftime_int(str, &ret, max, iso_year%100, 2, 0, 99))
1242 return 0;
1243 } else {
1244 if(!strftime_int(str, &ret, max, iso_days/7 + 1, alternate ? 0 : 2, 0, 53))
1245 return 0;
1247 break;
1249 #endif
1250 case 'H':
1251 if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1252 return 0;
1253 break;
1254 case 'I':
1255 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1256 goto einval_error;
1257 if(!strftime_int(str, &ret, max, (mstm->tm_hour + 11) % 12 + 1,
1258 alternate ? 0 : 2, 1, 12))
1259 return 0;
1260 break;
1261 case 'j':
1262 if(!strftime_int(str, &ret, max, mstm->tm_yday+1, alternate ? 0 : 3, 1, 366))
1263 return 0;
1264 break;
1265 case 'm':
1266 if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1267 return 0;
1268 break;
1269 case 'M':
1270 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1271 return 0;
1272 break;
1273 #if _MSVCR_VER>=140
1274 case 'n':
1275 str[ret++] = '\n';
1276 break;
1277 #endif
1278 case 'p':
1279 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1280 goto einval_error;
1281 if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ?
1282 STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm)))
1283 return 0;
1284 break;
1285 #if _MSVCR_VER>=140
1286 case 'r':
1287 if(time_data == &cloc_time_data)
1289 if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
1290 goto einval_error;
1291 if(!strftime_int(str, &ret, max, (mstm->tm_hour + 11) % 12 + 1,
1292 alternate ? 0 : 2, 1, 12))
1293 return 0;
1294 if(ret < max)
1295 str[ret++] = ':';
1296 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1297 return 0;
1298 if(ret < max)
1299 str[ret++] = ':';
1300 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1301 return 0;
1302 if(ret < max)
1303 str[ret++] = ' ';
1304 if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ?
1305 STRFTIME_TD(time_data, am) : STRFTIME_TD(time_data, pm)))
1306 return 0;
1308 else
1310 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time)))
1311 return 0;
1313 break;
1314 case 'R':
1315 if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1316 return 0;
1317 if(ret < max)
1318 str[ret++] = ':';
1319 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1320 return 0;
1321 break;
1322 #endif
1323 case 'S':
1324 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1325 return 0;
1326 break;
1327 #if _MSVCR_VER>=140
1328 case 't':
1329 str[ret++] = '\t';
1330 break;
1331 case 'T':
1332 if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1333 return 0;
1334 if(ret < max)
1335 str[ret++] = ':';
1336 if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1337 return 0;
1338 if(ret < max)
1339 str[ret++] = ':';
1340 if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
1341 return 0;
1342 break;
1343 case 'u':
1344 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1345 goto einval_error;
1346 tmp = mstm->tm_wday ? mstm->tm_wday : 7;
1347 if(!strftime_int(str, &ret, max, tmp, 0, 1, 7))
1348 return 0;
1349 break;
1350 #endif
1351 case 'w':
1352 if(!strftime_int(str, &ret, max, mstm->tm_wday, 0, 0, 6))
1353 return 0;
1354 break;
1355 case 'y':
1356 #if _MSVCR_VER>=140
1357 if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999))
1358 #else
1359 if(!MSVCRT_CHECK_PMT(year>=1900))
1360 #endif
1361 goto einval_error;
1362 if(!strftime_int(str, &ret, max, year%100, alternate ? 0 : 2, 0, 99))
1363 return 0;
1364 break;
1365 case 'Y':
1366 if(!strftime_int(str, &ret, max, year, alternate ? 0 : 4, 0, 9999))
1367 return 0;
1368 break;
1369 case 'z':
1370 #if _MSVCR_VER>=140
1371 _tzset();
1372 if(!strftime_tzdiff(str, &ret, max, mstm->tm_isdst))
1373 return 0;
1374 break;
1375 #endif
1376 case 'Z':
1377 _tzset();
1378 #if _MSVCR_VER <= 90
1379 if(_get_tzname(&tmp, str+ret, max-ret, mstm->tm_isdst ? 1 : 0))
1380 return 0;
1381 #else
1382 if(_mbstowcs_s_l(&tmp, str+ret, max-ret,
1383 mstm->tm_isdst ? tzname_dst : tzname_std,
1384 MSVCRT__TRUNCATE, loc) == STRUNCATE)
1385 ret = max;
1386 #endif
1387 ret += tmp-1;
1388 break;
1389 case 'U':
1390 case 'W':
1391 if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6))
1392 goto einval_error;
1393 if(!MSVCRT_CHECK_PMT(mstm->tm_yday>=0 && mstm->tm_yday<=365))
1394 goto einval_error;
1395 if(*format == 'U')
1396 tmp = mstm->tm_wday;
1397 else if(!mstm->tm_wday)
1398 tmp = 6;
1399 else
1400 tmp = mstm->tm_wday-1;
1402 tmp = mstm->tm_yday/7 + (tmp<=mstm->tm_yday%7);
1403 if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 0, 53))
1404 return 0;
1405 break;
1406 case '%':
1407 str[ret++] = '%';
1408 break;
1409 default:
1410 WARN("unknown format %c\n", *format);
1411 MSVCRT_INVALID_PMT("unknown format", EINVAL);
1412 goto einval_error;
1416 if(ret == max) {
1417 if(max)
1418 *str = 0;
1419 *_errno() = ERANGE;
1420 return 0;
1423 str[ret] = 0;
1424 return ret;
1426 einval_error:
1427 *str = 0;
1428 return 0;
1431 static size_t strftime_helper(char *str, size_t max, const char *format,
1432 const struct tm *mstm, __lc_time_data *time_data, _locale_t loc)
1434 #if _MSVCR_VER <= 90
1435 TRACE("(%p %Iu %s %p %p %p)\n", str, max, format, mstm, time_data, loc);
1436 return strftime_impl(str, max, format, mstm, time_data, loc);
1437 #else
1438 wchar_t *s, *fmt;
1439 size_t len;
1441 TRACE("(%p %Iu %s %p %p %p)\n", str, max, format, mstm, time_data, loc);
1443 if (!MSVCRT_CHECK_PMT(str != NULL)) return 0;
1444 if (!MSVCRT_CHECK_PMT(max != 0)) return 0;
1445 *str = 0;
1446 if (!MSVCRT_CHECK_PMT(format != NULL)) return 0;
1448 len = _mbstowcs_l( NULL, format, 0, loc ) + 1;
1449 if (!len || !(fmt = malloc( len*sizeof(wchar_t) ))) return 0;
1450 _mbstowcs_l(fmt, format, len, loc);
1452 if ((s = malloc( max*sizeof(wchar_t) )))
1454 len = strftime_impl( s, max, fmt, mstm, time_data, loc );
1455 if (len)
1456 len = _wcstombs_l( str, s, max, loc );
1457 free( s );
1459 else len = 0;
1461 free( fmt );
1462 return len;
1463 #endif
1466 #if _MSVCR_VER >= 80
1467 /********************************************************************
1468 * _strftime_l (MSVCR80.@)
1470 size_t CDECL _strftime_l( char *str, size_t max, const char *format,
1471 const struct tm *mstm, _locale_t loc )
1473 return strftime_helper(str, max, format, mstm, NULL, loc);
1475 #endif
1477 /*********************************************************************
1478 * _Strftime (MSVCRT.@)
1480 size_t CDECL _Strftime(char *str, size_t max, const char *format,
1481 const struct tm *mstm, __lc_time_data *time_data)
1483 return strftime_helper(str, max, format, mstm, time_data, NULL);
1486 /*********************************************************************
1487 * strftime (MSVCRT.@)
1489 size_t CDECL strftime( char *str, size_t max, const char *format,
1490 const struct tm *mstm )
1492 return strftime_helper(str, max, format, mstm, NULL, NULL);
1495 static size_t wcsftime_helper( wchar_t *str, size_t max,
1496 const wchar_t *format, const struct tm *mstm,
1497 __lc_time_data *time_data, _locale_t loc )
1499 #if _MSVCR_VER <= 90
1500 char *s, *fmt;
1501 size_t len;
1503 TRACE("%p %Iu %s %p %p %p\n", str, max, debugstr_w(format), mstm, time_data, loc);
1505 len = _wcstombs_l( NULL, format, 0, loc ) + 1;
1506 if (!(fmt = malloc( len ))) return 0;
1507 _wcstombs_l(fmt, format, len, loc);
1509 if ((s = malloc( max*4 )))
1511 if (!strftime_impl( s, max*4, fmt, mstm, time_data, loc )) s[0] = 0;
1512 len = _mbstowcs_l( str, s, max, loc );
1513 free( s );
1515 else len = 0;
1517 free( fmt );
1518 return len;
1519 #else
1520 TRACE("%p %Iu %s %p %p %p\n", str, max, debugstr_w(format), mstm, time_data, loc);
1521 return strftime_impl(str, max, format, mstm, time_data, loc);
1522 #endif
1525 /*********************************************************************
1526 * _wcsftime_l (MSVCRT.@)
1528 size_t CDECL _wcsftime_l( wchar_t *str, size_t max,
1529 const wchar_t *format, const struct tm *mstm, _locale_t loc )
1531 return wcsftime_helper(str, max, format, mstm, NULL, loc);
1534 /*********************************************************************
1535 * wcsftime (MSVCRT.@)
1537 size_t CDECL wcsftime( wchar_t *str, size_t max,
1538 const wchar_t *format, const struct tm *mstm )
1540 return wcsftime_helper(str, max, format, mstm, NULL, NULL);
1543 #if _MSVCR_VER >= 110
1544 /*********************************************************************
1545 * _Wcsftime (MSVCR110.@)
1547 size_t CDECL _Wcsftime(wchar_t *str, size_t max,
1548 const wchar_t *format, const struct tm *mstm,
1549 __lc_time_data *time_data)
1551 return wcsftime_helper(str, max, format, mstm, time_data, NULL);
1553 #endif
1555 static char* asctime_buf(char *buf, const struct tm *mstm)
1557 static const char wday[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
1558 static const char month[12][4] = {"Jan", "Feb", "Mar", "Apr", "May",
1559 "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1561 if (!mstm || mstm->tm_sec<0 || mstm->tm_sec>59
1562 || mstm->tm_min<0 || mstm->tm_min>59
1563 || mstm->tm_hour<0 || mstm->tm_hour>23
1564 || mstm->tm_mon<0 || mstm->tm_mon>11
1565 || mstm->tm_wday<0 || mstm->tm_wday>6
1566 || mstm->tm_year<0 || mstm->tm_mday<0
1567 || mstm->tm_mday>MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon]) {
1568 *_errno() = EINVAL;
1569 return NULL;
1572 #if _MSVCR_VER>=140
1573 /* C89 (4.12.3.1) uses space-padding for day of month. */
1574 _snprintf(buf, 26, "%s %s %2d %02d:%02d:%02d %c%03d\n", wday[mstm->tm_wday],
1575 month[mstm->tm_mon], mstm->tm_mday, mstm->tm_hour, mstm->tm_min,
1576 mstm->tm_sec, '1'+(mstm->tm_year+900)/1000, (900+mstm->tm_year)%1000);
1577 #else
1578 _snprintf(buf, 26, "%s %s %02d %02d:%02d:%02d %c%03d\n", wday[mstm->tm_wday],
1579 month[mstm->tm_mon], mstm->tm_mday, mstm->tm_hour, mstm->tm_min,
1580 mstm->tm_sec, '1'+(mstm->tm_year+900)/1000, (900+mstm->tm_year)%1000);
1581 #endif
1582 return buf;
1585 /*********************************************************************
1586 * asctime (MSVCRT.@)
1588 char * CDECL asctime(const struct tm *mstm)
1590 thread_data_t *data = msvcrt_get_thread_data();
1592 /* asctime returns date in format that always has exactly 26 characters */
1593 if (!data->asctime_buffer) {
1594 data->asctime_buffer = malloc(26);
1595 if (!data->asctime_buffer) {
1596 *_errno() = ENOMEM;
1597 return NULL;
1601 return asctime_buf(data->asctime_buffer, mstm);
1604 /*********************************************************************
1605 * asctime_s (MSVCRT.@)
1607 int CDECL asctime_s(char* time, size_t size, const struct tm *mstm)
1609 if (!MSVCRT_CHECK_PMT(time != NULL)) return EINVAL;
1610 if (size) time[0] = 0;
1611 if (!MSVCRT_CHECK_PMT(size >= 26)) return EINVAL;
1612 if (!MSVCRT_CHECK_PMT(mstm != NULL)) return EINVAL;
1613 if (!MSVCRT_CHECK_PMT(mstm->tm_sec >= 0 && mstm->tm_sec < 60)) return EINVAL;
1614 if (!MSVCRT_CHECK_PMT(mstm->tm_min >= 0 && mstm->tm_min < 60)) return EINVAL;
1615 if (!MSVCRT_CHECK_PMT(mstm->tm_hour >= 0 && mstm->tm_hour < 24)) return EINVAL;
1616 if (!MSVCRT_CHECK_PMT(mstm->tm_mon >= 0 && mstm->tm_mon < 12)) return EINVAL;
1617 if (!MSVCRT_CHECK_PMT(mstm->tm_wday >= 0 && mstm->tm_wday < 7)) return EINVAL;
1618 if (!MSVCRT_CHECK_PMT(mstm->tm_year >= 0)) return EINVAL;
1619 if (!MSVCRT_CHECK_PMT(mstm->tm_mday >= 0)) return EINVAL;
1620 if (!MSVCRT_CHECK_PMT(mstm->tm_mday <= MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon])) return EINVAL;
1622 asctime_buf(time, mstm);
1623 return 0;
1626 /*********************************************************************
1627 * _wasctime (MSVCRT.@)
1629 wchar_t * CDECL _wasctime(const struct tm *mstm)
1631 thread_data_t *data = msvcrt_get_thread_data();
1632 char buffer[26];
1634 if(!data->wasctime_buffer) {
1635 data->wasctime_buffer = malloc(26*sizeof(wchar_t));
1636 if(!data->wasctime_buffer) {
1637 *_errno() = ENOMEM;
1638 return NULL;
1642 if(!asctime_buf(buffer, mstm))
1643 return NULL;
1645 MultiByteToWideChar(CP_ACP, 0, buffer, -1, data->wasctime_buffer, 26);
1646 return data->wasctime_buffer;
1649 /*********************************************************************
1650 * _wasctime_s (MSVCRT.@)
1652 int CDECL _wasctime_s(wchar_t* time, size_t size, const struct tm *mstm)
1654 char buffer[26];
1655 int ret;
1657 if (!MSVCRT_CHECK_PMT(time != NULL)) return EINVAL;
1658 if (size) time[0] = 0;
1659 if (!MSVCRT_CHECK_PMT(size >= 26)) return EINVAL;
1660 if (!MSVCRT_CHECK_PMT(mstm != NULL)) return EINVAL;
1662 ret = asctime_s(buffer, sizeof(buffer), mstm);
1663 if(ret)
1664 return ret;
1665 MultiByteToWideChar(CP_ACP, 0, buffer, -1, time, size);
1666 return 0;
1669 /*********************************************************************
1670 * _ctime64 (MSVCRT.@)
1672 char * CDECL _ctime64(const __time64_t *time)
1674 struct tm *t;
1675 t = _localtime64( time );
1676 if (!t) return NULL;
1677 return asctime( t );
1680 /*********************************************************************
1681 * _ctime64_s (MSVCRT.@)
1683 int CDECL _ctime64_s(char *res, size_t len, const __time64_t *time)
1685 struct tm *t;
1687 if (!MSVCRT_CHECK_PMT( res != NULL )) return EINVAL;
1688 if (!MSVCRT_CHECK_PMT( len >= 26 )) return EINVAL;
1689 res[0] = '\0';
1690 if (!MSVCRT_CHECK_PMT( time != NULL )) return EINVAL;
1691 if (!MSVCRT_CHECK_PMT( *time > 0 )) return EINVAL;
1693 t = _localtime64( time );
1694 strcpy( res, asctime( t ) );
1695 return 0;
1698 /*********************************************************************
1699 * _ctime32 (MSVCRT.@)
1701 char * CDECL _ctime32(const __time32_t *time)
1703 struct tm *t;
1704 t = _localtime32( time );
1705 if (!t) return NULL;
1706 return asctime( t );
1709 /*********************************************************************
1710 * _ctime32_s (MSVCRT.@)
1712 int CDECL _ctime32_s(char *res, size_t len, const __time32_t *time)
1714 struct tm *t;
1716 if (!MSVCRT_CHECK_PMT( res != NULL )) return EINVAL;
1717 if (!MSVCRT_CHECK_PMT( len >= 26 )) return EINVAL;
1718 res[0] = '\0';
1719 if (!MSVCRT_CHECK_PMT( time != NULL )) return EINVAL;
1720 if (!MSVCRT_CHECK_PMT( *time > 0 )) return EINVAL;
1722 t = _localtime32( time );
1723 strcpy( res, asctime( t ) );
1724 return 0;
1727 /*********************************************************************
1728 * _wctime64 (MSVCRT.@)
1730 wchar_t * CDECL _wctime64(const __time64_t *time)
1732 return _wasctime( _localtime64(time) );
1735 /*********************************************************************
1736 * _wctime32 (MSVCRT.@)
1738 wchar_t * CDECL _wctime32(const __time32_t *time)
1740 return _wasctime( _localtime32(time) );
1743 /*********************************************************************
1744 * _wctime64_s (MSVCRT.@)
1746 int CDECL _wctime64_s(wchar_t *buf,
1747 size_t size, const __time64_t *time)
1749 struct tm tm;
1750 int ret;
1752 if(!MSVCRT_CHECK_PMT(buf != NULL)) return EINVAL;
1753 if(!MSVCRT_CHECK_PMT(size != 0)) return EINVAL;
1754 buf[0] = 0;
1755 if(!MSVCRT_CHECK_PMT(time != NULL)) return EINVAL;
1756 if(!MSVCRT_CHECK_PMT(*time >= 0)) return EINVAL;
1757 if(!MSVCRT_CHECK_PMT(*time <= _MAX__TIME64_T)) return EINVAL;
1759 ret = _localtime64_s(&tm, time);
1760 if(ret != 0)
1761 return ret;
1763 return _wasctime_s(buf, size, &tm);
1766 /*********************************************************************
1767 * _wctime32_s (MSVCRT.@)
1769 int CDECL _wctime32_s(wchar_t *buf, size_t size,
1770 const __time32_t *time)
1772 struct tm tm;
1773 int ret;
1775 if(!MSVCRT_CHECK_PMT(buf != NULL)) return EINVAL;
1776 if(!MSVCRT_CHECK_PMT(size != 0)) return EINVAL;
1777 buf[0] = 0;
1778 if(!MSVCRT_CHECK_PMT(time != NULL)) return EINVAL;
1779 if(!MSVCRT_CHECK_PMT(*time >= 0)) return EINVAL;
1781 ret = _localtime32_s(&tm, time);
1782 if(ret != 0)
1783 return ret;
1785 return _wasctime_s(buf, size, &tm);
1788 #if _MSVCR_VER >= 80
1790 /*********************************************************************
1791 * _get_timezone (MSVCR80.@)
1793 int CDECL _get_timezone(LONG *timezone)
1795 if(!MSVCRT_CHECK_PMT(timezone != NULL)) return EINVAL;
1797 *timezone = MSVCRT___timezone;
1798 return 0;
1801 /*********************************************************************
1802 * _get_daylight (MSVCR80.@)
1804 int CDECL _get_daylight(int *hours)
1806 if(!MSVCRT_CHECK_PMT(hours != NULL)) return EINVAL;
1808 *hours = MSVCRT___daylight;
1809 return 0;
1812 #endif /* _MSVCR_VER >= 80 */
1814 #if _MSVCR_VER >= 140
1816 #define TIME_UTC 1
1818 struct _timespec32
1820 __time32_t tv_sec;
1821 LONG tv_nsec;
1824 struct _timespec64
1826 __time64_t tv_sec;
1827 LONG tv_nsec;
1830 /*********************************************************************
1831 * _timespec64_get (UCRTBASE.@)
1833 int CDECL _timespec64_get(struct _timespec64 *ts, int base)
1835 ULONGLONG time;
1836 FILETIME ft;
1838 if(!MSVCRT_CHECK_PMT(ts != NULL)) return 0;
1839 if(base != TIME_UTC) return 0;
1841 GetSystemTimePreciseAsFileTime(&ft);
1842 time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
1844 ts->tv_sec = time / TICKSPERSEC - SECS_1601_TO_1970;
1845 ts->tv_nsec = time % TICKSPERSEC * 100;
1846 return base;
1849 /*********************************************************************
1850 * _timespec32_get (UCRTBASE.@)
1852 int CDECL _timespec32_get(struct _timespec32 *ts, int base)
1854 struct _timespec64 ts64;
1856 if(!MSVCRT_CHECK_PMT(ts != NULL)) return 0;
1857 if(base != TIME_UTC) return 0;
1859 if(_timespec64_get(&ts64, base) != base)
1860 return 0;
1861 if(ts64.tv_sec != (__time32_t)ts64.tv_sec)
1862 return 0;
1864 ts->tv_sec = ts64.tv_sec;
1865 ts->tv_nsec = ts64.tv_nsec;
1866 return base;
1868 #endif /* _MSVCR_VER >= 140 */