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
27 #include <sys/timeb.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 }
57 static const int MAX_SECONDS
= 60;
59 static const int MAX_SECONDS
= 59;
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
)
80 /*********************************************************************
81 * _daylight (MSVCRT.@)
83 int MSVCRT___daylight
= 1;
85 /*********************************************************************
86 * _timezone (MSVCRT.@)
88 __msvcrt_long MSVCRT___timezone
= 28800;
90 /*********************************************************************
93 int MSVCRT__dstbias
= -3600;
95 /*********************************************************************
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 /*********************************************************************
109 void CDECL
MSVCRT__tzset(void)
111 char *tz
= MSVCRT_getenv("TZ");
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);
127 }else if(*tz
== '+') {
130 MSVCRT___timezone
= MSVCRT_strtol(tz
, &tz
, 10)*3600;
132 MSVCRT___timezone
+= MSVCRT_strtol(tz
+1, &tz
, 10)*60;
134 MSVCRT___timezone
+= MSVCRT_strtol(tz
+1, &tz
, 10);
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;
150 MSVCRT___daylight
= 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;
164 static void _tzset_init(void)
166 static BOOL init
= FALSE
;
178 static BOOL
is_dst(const SYSTEMTIME
*st
)
180 TIME_ZONE_INFORMATION tmp
;
183 if(!MSVCRT___daylight
)
186 if(tzi
.DaylightDate
.wMonth
) {
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;
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;
207 tmp
.StandardBias
= 0;
208 tmp
.DaylightBias
= MSVCRT__dstbias
/60;
209 if(!SystemTimeToTzSpecificLocalTime(&tmp
, st
, &out
))
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
)
228 BOOL use_dst
= FALSE
;
230 ret
= mstm
->tm_year
+ mstm
->tm_mon
/12;
232 if(mstm
->tm_mon
< 0) {
237 if(ret
<70 || ret
>1100) {
238 *MSVCRT__errno() = EINVAL
;
242 memset(&st
, 0, sizeof(SYSTEMTIME
));
244 st
.wMonth
= mstm
->tm_mon
+1;
247 if(!SystemTimeToFileTime(&st
, &ft
)) {
248 *MSVCRT__errno() = EINVAL
;
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
);
264 use_dst
= is_dst(&st
);
265 if((mstm
->tm_isdst
<=-1 && use_dst
) || (mstm
->tm_isdst
>=1)) {
268 ret
+= (__time64_t
)MSVCRT__dstbias
*TICKSPERSEC
;
270 ft
.dwLowDateTime
= ret
& 0xffffffff;
271 ft
.dwHighDateTime
= ret
>> 32;
272 FileTimeToSystemTime(&ft
, &tmp
);
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 *MSVCRT__errno() = EINVAL
;
306 ret
= (ret
-TICKS_1601_TO_1970
)/TICKSPERSEC
;
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 /**********************************************************************
331 __time64_t CDECL
MSVCRT_mktime(struct tm
*mstm
)
333 return MSVCRT__mktime64( mstm
);
336 __time32_t CDECL
MSVCRT_mktime(struct tm
*mstm
)
338 return MSVCRT__mktime32( mstm
);
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.@)
365 __time64_t CDECL
MSVCRT__mkgmtime(struct tm
*time
)
367 return MSVCRT__mkgmtime64(time
);
370 __time32_t CDECL
MSVCRT__mkgmtime(struct tm
*time
)
372 return MSVCRT__mkgmtime32(time
);
376 /*********************************************************************
377 * _localtime64_s (MSVCRT.@)
379 int CDECL
_localtime64_s(struct tm
*res
, const __time64_t
*secs
)
386 if (!res
|| !secs
|| *secs
< 0 || *secs
> _MAX__TIME64_T
)
389 write_invalid_msvcrt_tm(res
);
391 *MSVCRT__errno() = EINVAL
;
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;
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;
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
= MSVCRT_malloc(sizeof(struct tm
));
434 if(_localtime64_s(data
->time_buffer
, secs
))
436 return data
->time_buffer
;
439 /*********************************************************************
440 * _localtime32 (MSVCRT.@)
442 struct tm
* CDECL
MSVCRT__localtime32(const __time32_t
* secs
)
450 return MSVCRT__localtime64( &secs64
);
453 /*********************************************************************
454 * _localtime32_s (MSVCRT.@)
456 int CDECL
_localtime32_s(struct tm
*time
, const __time32_t
*secs
)
460 if (!time
|| !secs
|| *secs
< 0)
463 write_invalid_msvcrt_tm(time
);
465 *MSVCRT__errno() = EINVAL
;
470 return _localtime64_s(time
, &secs64
);
473 /*********************************************************************
474 * localtime (MSVCRT.@)
477 struct tm
* CDECL
MSVCRT_localtime(const __time64_t
* secs
)
479 return MSVCRT__localtime64( secs
);
482 struct tm
* CDECL
MSVCRT_localtime(const __time32_t
* secs
)
484 return MSVCRT__localtime32( secs
);
488 /*********************************************************************
489 * _gmtime64 (MSVCRT.@)
491 int CDECL
MSVCRT__gmtime64_s(struct tm
*res
, const __time64_t
*secs
)
498 if (!res
|| !secs
|| *secs
< 0 || *secs
> _MAX__TIME64_T
) {
500 write_invalid_msvcrt_tm(res
);
503 *MSVCRT__errno() = 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;
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
= MSVCRT_malloc(sizeof(struct tm
));
541 if(MSVCRT__gmtime64_s(data
->time_buffer
, secs
))
543 return data
->time_buffer
;
546 /*********************************************************************
547 * _gmtime32_s (MSVCRT.@)
549 int CDECL
MSVCRT__gmtime32_s(struct tm
*res
, const __time32_t
*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
)
571 return MSVCRT__gmtime64( &secs64
);
574 /*********************************************************************
578 struct tm
* CDECL
MSVCRT_gmtime(const __time64_t
* secs
)
580 return MSVCRT__gmtime64( secs
);
583 struct tm
* CDECL
MSVCRT_gmtime(const __time32_t
* secs
)
585 return MSVCRT__gmtime32( secs
);
589 /**********************************************************************
590 * _strdate (MSVCRT.@)
592 char* CDECL
MSVCRT__strdate(char* date
)
594 GetDateFormatA(LOCALE_NEUTRAL
, 0, NULL
, "MM'/'dd'/'yy", date
, 9);
598 /**********************************************************************
599 * _strdate_s (MSVCRT.@)
601 int CDECL
_strdate_s(char* date
, size_t size
)
607 *MSVCRT__errno() = EINVAL
;
612 *MSVCRT__errno() = ERANGE
;
616 MSVCRT__strdate(date
);
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);
629 /**********************************************************************
630 * _wstrdate_s (MSVCRT.@)
632 int CDECL
_wstrdate_s(wchar_t* date
, size_t size
)
638 *MSVCRT__errno() = EINVAL
;
643 *MSVCRT__errno() = ERANGE
;
647 MSVCRT__wstrdate(date
);
651 /*********************************************************************
652 * _strtime (MSVCRT.@)
654 char* CDECL
MSVCRT__strtime(char* time
)
656 GetTimeFormatA(LOCALE_NEUTRAL
, 0, NULL
, "HH':'mm':'ss", time
, 9);
660 /*********************************************************************
661 * _strtime_s (MSVCRT.@)
663 int CDECL
_strtime_s(char* time
, size_t size
)
669 *MSVCRT__errno() = EINVAL
;
674 *MSVCRT__errno() = ERANGE
;
678 MSVCRT__strtime(time
);
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);
691 /*********************************************************************
692 * _wstrtime_s (MSVCRT.@)
694 int CDECL
_wstrtime_s(wchar_t* time
, size_t size
)
700 *MSVCRT__errno() = EINVAL
;
705 *MSVCRT__errno() = ERANGE
;
709 MSVCRT__wstrtime(time
);
713 /*********************************************************************
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.@)
744 double CDECL
MSVCRT_difftime(__time64_t time1
, __time64_t time2
)
746 return MSVCRT__difftime64( time1
, time2
);
749 double CDECL
MSVCRT_difftime(__time32_t time1
, __time32_t time2
)
751 return MSVCRT__difftime32( time1
, time2
);
755 /*********************************************************************
756 * _ftime64 (MSVCRT.@)
758 void CDECL
MSVCRT__ftime64(struct __timeb64
*buf
)
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
);
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
);
809 /*********************************************************************
813 void CDECL
MSVCRT__ftime(struct __timeb64
*buf
)
815 MSVCRT__ftime64( buf
);
818 void CDECL
MSVCRT__ftime(struct __timeb32
*buf
)
820 MSVCRT__ftime32( buf
);
824 /*********************************************************************
827 __time64_t CDECL
MSVCRT__time64(__time64_t
*buf
)
832 MSVCRT__ftime64(&tb
);
835 return buf
? *buf
= curtime
: curtime
;
838 /*********************************************************************
841 __time32_t CDECL
MSVCRT__time32(__time32_t
*buf
)
846 MSVCRT__ftime64(&tb
);
849 return buf
? *buf
= curtime
: curtime
;
852 /*********************************************************************
856 __time64_t CDECL
MSVCRT_time(__time64_t
* buf
)
858 return MSVCRT__time64( buf
);
861 __time32_t CDECL
MSVCRT_time(__time32_t
* buf
)
863 return MSVCRT__time32( buf
);
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
;
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
;
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
)
913 timezone
= tzname_std
;
916 timezone
= tzname_dst
;
919 *MSVCRT__errno() = EINVAL
;
923 if(!ret
|| (!buf
&& bufsize
> 0) || (buf
&& !bufsize
))
925 *MSVCRT__errno() = EINVAL
;
929 *ret
= strlen(timezone
)+1;
938 strcpy(buf
, timezone
);
942 /*********************************************************************
943 * __p_tzname (MSVCRT.@)
945 char ** CDECL
__p__tzname(void)
947 return MSVCRT__tzname
;
951 #define STRFTIME_CHAR char
952 #define STRFTIME_TD(td, name) td->str.names.name
954 #define STRFTIME_CHAR wchar_t
955 #define STRFTIME_TD(td, name) td->wstr.names.name
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
)
966 *MSVCRT__errno() = ERANGE
;
978 static inline BOOL
strftime_int(STRFTIME_CHAR
*str
, size_t *pos
, size_t max
,
979 int src
, int prec
, int l
, int h
)
983 if(!MSVCRT_CHECK_PMT(src
>=l
&& src
<=h
)) {
989 len
= MSVCRT__snprintf(str
+*pos
, max
-*pos
, "%0*d", prec
, src
);
991 len
= MSVCRT__snwprintf(str
+*pos
, max
-*pos
, L
"%0*d", prec
, src
);
995 *MSVCRT__errno() = ERANGE
;
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
)
1009 while(*format
&& ret
)
1012 while(format
[0] == format
[count
]) count
++;
1016 if(count
% 2 == 0) break;
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
++;
1029 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1038 ret
= strftime_int(str
, pos
, max
, mstm
->tm_mday
, count
==1 ? 0 : 2, 1, 31);
1041 ret
= strftime_str(str
, pos
, max
, STRFTIME_TD(time_data
, short_wday
)[mstm
->tm_wday
]);
1044 ret
= strftime_nstr(str
, pos
, max
, format
, count
-4);
1046 ret
= strftime_str(str
, pos
, max
, STRFTIME_TD(time_data
, wday
)[mstm
->tm_wday
]);
1053 if(!MSVCRT_CHECK_PMT(mstm
->tm_mon
>=0 && mstm
->tm_mon
<=11))
1062 ret
= strftime_int(str
, pos
, max
, mstm
->tm_mon
+1, count
==1 ? 0 : 2, 1, 12);
1065 ret
= strftime_str(str
, pos
, max
, STRFTIME_TD(time_data
, short_mon
)[mstm
->tm_mon
]);
1068 ret
= strftime_nstr(str
, pos
, max
, format
, count
-4);
1070 ret
= strftime_str(str
, pos
, max
, STRFTIME_TD(time_data
, mon
)[mstm
->tm_mon
]);
1078 if(!MSVCRT_CHECK_PMT(mstm
->tm_year
>= -1900 && mstm
->tm_year
<= 8099))
1080 if(!MSVCRT_CHECK_PMT(mstm
->tm_year
>= 0))
1090 ret
= strftime_nstr(str
, pos
, max
, format
, 1);
1094 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1096 ret
= strftime_int(str
, pos
, max
, (mstm
->tm_year
+1900)%100, 2, 0, 99);
1099 ret
= strftime_nstr(str
, pos
, max
, format
, count
-4);
1101 ret
= strftime_int(str
, pos
, max
, mstm
->tm_year
+1900, 4, 0, 9999);
1106 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1112 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1114 ret
= strftime_int(str
, pos
, max
, (mstm
->tm_hour
+ 11) % 12 + 1,
1115 count
== 1 ? 0 : 2, 1, 12);
1119 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1121 ret
= strftime_int(str
, pos
, max
, mstm
->tm_hour
, count
== 1 ? 0 : 2, 0, 23);
1125 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1127 ret
= strftime_int(str
, pos
, max
, mstm
->tm_min
, count
== 1 ? 0 : 2, 0, 59);
1131 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1133 ret
= strftime_int(str
, pos
, max
, mstm
->tm_sec
, count
== 1 ? 0 : 2, 0, MAX_SECONDS
);
1138 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
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
);
1148 ret
= strftime_nstr(str
, pos
, max
, format
, count
);
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);
1171 str
[(*pos
)++] = sign
;
1172 if(!strftime_int(str
, pos
, max
, tz
/60/60, 2, 0, 99))
1174 return strftime_int(str
, pos
, max
, tz
/60%60, 2, 0, 59);
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
)
1184 int year
= mstm
? mstm
->tm_year
+ 1900 : -1;
1186 if(!str
|| !format
) {
1189 *MSVCRT__errno() = EINVAL
;
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(MSVCRT__isleadbyte_l((unsigned char)*format
, loc
)) {
1199 str
[ret
++] = *(format
++);
1200 if(ret
== max
) continue;
1201 if(!MSVCRT_CHECK_PMT(str
[ret
]))
1204 str
[ret
++] = *format
;
1209 if(*format
== '#') {
1216 if(!MSVCRT_CHECK_PMT(mstm
))
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
);
1231 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
,
1232 alternate
? STRFTIME_TD(time_data
, date
) : STRFTIME_TD(time_data
, short_date
)))
1236 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
, STRFTIME_TD(time_data
, time
)))
1240 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
,
1241 alternate
? STRFTIME_TD(time_data
, date
) : STRFTIME_TD(time_data
, short_date
)))
1245 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
, STRFTIME_TD(time_data
, time
)))
1249 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1251 if(!strftime_str(str
, &ret
, max
, STRFTIME_TD(time_data
, short_wday
)[mstm
->tm_wday
]))
1255 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1257 if(!strftime_str(str
, &ret
, max
, STRFTIME_TD(time_data
, wday
)[mstm
->tm_wday
]))
1264 if(!MSVCRT_CHECK_PMT(mstm
->tm_mon
>=0 && mstm
->tm_mon
<=11))
1266 if(!strftime_str(str
, &ret
, max
, STRFTIME_TD(time_data
, short_mon
)[mstm
->tm_mon
]))
1270 if(!MSVCRT_CHECK_PMT(mstm
->tm_mon
>=0 && mstm
->tm_mon
<=11))
1272 if(!strftime_str(str
, &ret
, max
, STRFTIME_TD(time_data
, mon
)[mstm
->tm_mon
]))
1277 if(!MSVCRT_CHECK_PMT(year
>=0 && year
<=9999))
1279 if(!strftime_int(str
, &ret
, max
, year
/100, alternate
? 0 : 2, 0, 99))
1284 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 1, 31))
1289 if(!MSVCRT_CHECK_PMT(year
>=0 && year
<=9999))
1291 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mon
+1, alternate
? 0 : 2, 1, 12))
1295 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 1, 31))
1299 if(!strftime_int(str
, &ret
, max
, year
%100, alternate
? 0 : 2, 0, 99))
1303 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 1, 31))
1305 if(!alternate
&& str
[ret
-2] == '0')
1309 if(!strftime_int(str
, &ret
, max
, year
, alternate
? 0 : 4, 0, 9999))
1313 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mon
+1, alternate
? 0 : 2, 1, 12))
1317 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 1, 31))
1322 if(!MSVCRT_CHECK_PMT(year
>=0 && year
<=9999))
1327 int iso_year
= year
;
1328 int iso_days
= mstm
->tm_yday
- (mstm
->tm_wday
? mstm
->tm_wday
: 7) + 4;
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))
1337 } else if(*format
== 'g') {
1338 if(!strftime_int(str
, &ret
, max
, iso_year
%100, 2, 0, 99))
1341 if(!strftime_int(str
, &ret
, max
, iso_days
/7 + 1, alternate
? 0 : 2, 0, 53))
1348 if(!strftime_int(str
, &ret
, max
, mstm
->tm_hour
, alternate
? 0 : 2, 0, 23))
1352 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1354 if(!strftime_int(str
, &ret
, max
, (mstm
->tm_hour
+ 11) % 12 + 1,
1355 alternate
? 0 : 2, 1, 12))
1359 if(!strftime_int(str
, &ret
, max
, mstm
->tm_yday
+1, alternate
? 0 : 3, 1, 366))
1363 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mon
+1, alternate
? 0 : 2, 1, 12))
1367 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1376 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1378 if(!strftime_str(str
, &ret
, max
, mstm
->tm_hour
<12 ?
1379 STRFTIME_TD(time_data
, am
) : STRFTIME_TD(time_data
, pm
)))
1384 if(time_data
== &cloc_time_data
)
1386 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1388 if(!strftime_int(str
, &ret
, max
, (mstm
->tm_hour
+ 11) % 12 + 1,
1389 alternate
? 0 : 2, 1, 12))
1393 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1397 if(!strftime_int(str
, &ret
, max
, mstm
->tm_sec
, alternate
? 0 : 2, 0, MAX_SECONDS
))
1401 if(!strftime_str(str
, &ret
, max
, mstm
->tm_hour
<12 ?
1402 STRFTIME_TD(time_data
, am
) : STRFTIME_TD(time_data
, pm
)))
1407 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
, STRFTIME_TD(time_data
, time
)))
1412 if(!strftime_int(str
, &ret
, max
, mstm
->tm_hour
, alternate
? 0 : 2, 0, 23))
1416 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1421 if(!strftime_int(str
, &ret
, max
, mstm
->tm_sec
, alternate
? 0 : 2, 0, MAX_SECONDS
))
1429 if(!strftime_int(str
, &ret
, max
, mstm
->tm_hour
, alternate
? 0 : 2, 0, 23))
1433 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1437 if(!strftime_int(str
, &ret
, max
, mstm
->tm_sec
, alternate
? 0 : 2, 0, MAX_SECONDS
))
1441 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1443 tmp
= mstm
->tm_wday
? mstm
->tm_wday
: 7;
1444 if(!strftime_int(str
, &ret
, max
, tmp
, 0, 1, 7))
1449 if(!strftime_int(str
, &ret
, max
, mstm
->tm_wday
, 0, 0, 6))
1454 if(!MSVCRT_CHECK_PMT(year
>=0 && year
<=9999))
1456 if(!MSVCRT_CHECK_PMT(year
>=1900))
1459 if(!strftime_int(str
, &ret
, max
, year
%100, alternate
? 0 : 2, 0, 99))
1463 if(!strftime_int(str
, &ret
, max
, year
, alternate
? 0 : 4, 0, 9999))
1469 if(!strftime_tzdiff(str
, &ret
, max
, mstm
->tm_isdst
))
1475 #if _MSVCR_VER <= 90
1476 if(MSVCRT__get_tzname(&tmp
, str
+ret
, max
-ret
, mstm
->tm_isdst
? 1 : 0))
1479 if(MSVCRT__mbstowcs_s_l(&tmp
, str
+ret
, max
-ret
,
1480 mstm
->tm_isdst
? tzname_dst
: tzname_std
,
1481 MSVCRT__TRUNCATE
, loc
) == STRUNCATE
)
1488 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1490 if(!MSVCRT_CHECK_PMT(mstm
->tm_yday
>=0 && mstm
->tm_yday
<=365))
1493 tmp
= mstm
->tm_wday
;
1494 else if(!mstm
->tm_wday
)
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))
1507 WARN("unknown format %c\n", *format
);
1508 MSVCRT_INVALID_PMT("unknown format", EINVAL
);
1516 *MSVCRT__errno() = ERANGE
;
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
);
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;
1543 if (!MSVCRT_CHECK_PMT(format
!= NULL
)) return 0;
1545 len
= MSVCRT__mbstowcs_l( NULL
, format
, 0, loc
) + 1;
1546 if (!len
|| !(fmt
= MSVCRT_malloc( len
*sizeof(wchar_t) ))) return 0;
1547 MSVCRT__mbstowcs_l(fmt
, format
, len
, loc
);
1549 if ((s
= MSVCRT_malloc( max
*sizeof(wchar_t) )))
1551 len
= strftime_impl( s
, max
, fmt
, mstm
, time_data
, loc
);
1553 len
= MSVCRT__wcstombs_l( str
, s
, max
, loc
);
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
);
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
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
= MSVCRT_malloc( len
))) return 0;
1604 MSVCRT__wcstombs_l(fmt
, format
, len
, loc
);
1606 if ((s
= MSVCRT_malloc( max
*4 )))
1608 if (!strftime_impl( s
, max
*4, fmt
, mstm
, time_data
, loc
)) s
[0] = 0;
1609 len
= MSVCRT__mbstowcs_l( str
, s
, max
, loc
);
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
);
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
);
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 *MSVCRT__errno() = EINVAL
;
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);
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);
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
= MSVCRT_malloc(26);
1692 if (!data
->asctime_buffer
) {
1693 *MSVCRT__errno() = ENOMEM
;
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
);
1723 /*********************************************************************
1724 * _wasctime (MSVCRT.@)
1726 wchar_t * CDECL
MSVCRT__wasctime(const struct tm
*mstm
)
1728 thread_data_t
*data
= msvcrt_get_thread_data();
1731 if(!data
->wasctime_buffer
) {
1732 data
->wasctime_buffer
= MSVCRT_malloc(26*sizeof(wchar_t));
1733 if(!data
->wasctime_buffer
) {
1734 *MSVCRT__errno() = ENOMEM
;
1739 if(!asctime_buf(buffer
, mstm
))
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
)
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
);
1762 MultiByteToWideChar(CP_ACP
, 0, buffer
, -1, time
, size
);
1766 /*********************************************************************
1767 * _ctime64 (MSVCRT.@)
1769 char * CDECL
MSVCRT__ctime64(const __time64_t
*time
)
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
)
1784 if (!MSVCRT_CHECK_PMT( res
!= NULL
)) return EINVAL
;
1785 if (!MSVCRT_CHECK_PMT( len
>= 26 )) return EINVAL
;
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
) );
1795 /*********************************************************************
1796 * _ctime32 (MSVCRT.@)
1798 char * CDECL
MSVCRT__ctime32(const __time32_t
*time
)
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
)
1813 if (!MSVCRT_CHECK_PMT( res
!= NULL
)) return EINVAL
;
1814 if (!MSVCRT_CHECK_PMT( len
>= 26 )) return EINVAL
;
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
) );
1824 /*********************************************************************
1828 char * CDECL
MSVCRT_ctime(const __time64_t
*time
)
1830 return MSVCRT__ctime64( time
);
1833 char * CDECL
MSVCRT_ctime(const __time32_t
*time
)
1835 return MSVCRT__ctime32( time
);
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.@)
1859 wchar_t * CDECL
MSVCRT__wctime(const __time64_t
*time
)
1861 return MSVCRT__wctime64( time
);
1864 wchar_t * CDECL
MSVCRT__wctime(const __time32_t
*time
)
1866 return MSVCRT__wctime32( time
);
1870 /*********************************************************************
1871 * _wctime64_s (MSVCRT.@)
1873 int CDECL
MSVCRT__wctime64_s(wchar_t *buf
,
1874 size_t size
, const __time64_t
*time
)
1879 if(!MSVCRT_CHECK_PMT(buf
!= NULL
)) return EINVAL
;
1880 if(!MSVCRT_CHECK_PMT(size
!= 0)) return EINVAL
;
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
);
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
)
1902 if(!MSVCRT_CHECK_PMT(buf
!= NULL
)) return EINVAL
;
1903 if(!MSVCRT_CHECK_PMT(size
!= 0)) return EINVAL
;
1905 if(!MSVCRT_CHECK_PMT(time
!= NULL
)) return EINVAL
;
1906 if(!MSVCRT_CHECK_PMT(*time
>= 0)) return EINVAL
;
1908 ret
= _localtime32_s(&tm
, time
);
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
;
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
;
1939 #endif /* _MSVCR_VER >= 80 */
1941 #if _MSVCR_VER >= 140
1957 /*********************************************************************
1958 * _timespec64_get (UCRTBASE.@)
1960 int CDECL
_timespec64_get(struct _timespec64
*ts
, int base
)
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;
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
)
1988 if(ts64
.tv_sec
!= (__time32_t
)ts64
.tv_sec
)
1991 ts
->tv_sec
= ts64
.tv_sec
;
1992 ts
->tv_nsec
= ts64
.tv_nsec
;
1995 #endif /* _MSVCR_VER >= 140 */