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
28 #include <sys/timeb.h>
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
47 static LONGLONG init_time
;
49 void msvcrt_init_clock(void)
51 LARGE_INTEGER systime
;
53 NtQuerySystemTime(&systime
);
54 init_time
= systime
.QuadPart
;
57 static const int MonthLengths
[2][12] =
59 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
60 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
64 static const int MAX_SECONDS
= 60;
66 static const int MAX_SECONDS
= 59;
69 static inline BOOL
IsLeapYear(int Year
)
71 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0);
74 static inline void write_invalid_msvcrt_tm( struct tm
*tm
)
87 /*********************************************************************
88 * _daylight (MSVCRT.@)
90 int MSVCRT___daylight
= 1;
92 /*********************************************************************
93 * _timezone (MSVCRT.@)
95 __msvcrt_long MSVCRT___timezone
= 28800;
97 /*********************************************************************
100 __msvcrt_long MSVCRT__dstbias
= -3600;
102 /*********************************************************************
105 * Some apps (notably Mozilla) insist on writing to these, so the buffer
106 * must be large enough.
108 static char tzname_std
[64] = "PST";
109 static char tzname_dst
[64] = "PDT";
110 char *MSVCRT__tzname
[2] = { tzname_std
, tzname_dst
};
112 static TIME_ZONE_INFORMATION tzi
= {0};
113 /*********************************************************************
116 void CDECL
_tzset(void)
118 char *tz
= getenv("TZ");
123 BOOL neg_zone
= FALSE
;
125 memset(&tzi
, 0, sizeof(tzi
));
127 /* Parse timezone information: tzn[+|-]hh[:mm[:ss]][dzn] */
128 lstrcpynA(MSVCRT__tzname
[0], tz
, 3);
134 }else if(*tz
== '+') {
137 MSVCRT___timezone
= strtol(tz
, &tz
, 10)*3600;
139 MSVCRT___timezone
+= strtol(tz
+1, &tz
, 10)*60;
141 MSVCRT___timezone
+= strtol(tz
+1, &tz
, 10);
144 MSVCRT___timezone
= -MSVCRT___timezone
;
146 MSVCRT___daylight
= *tz
;
147 lstrcpynA(MSVCRT__tzname
[1], tz
, 3);
148 }else if(GetTimeZoneInformation(&tzi
) != TIME_ZONE_ID_INVALID
) {
149 MSVCRT___timezone
= tzi
.Bias
*60;
150 if(tzi
.StandardDate
.wMonth
)
151 MSVCRT___timezone
+= tzi
.StandardBias
*60;
153 if(tzi
.DaylightDate
.wMonth
) {
154 MSVCRT___daylight
= 1;
155 MSVCRT__dstbias
= (tzi
.DaylightBias
-tzi
.StandardBias
)*60;
157 MSVCRT___daylight
= 0;
161 if(!WideCharToMultiByte(CP_ACP
, 0, tzi
.StandardName
, -1, MSVCRT__tzname
[0],
162 sizeof(tzname_std
), NULL
, &error
) || error
)
163 *MSVCRT__tzname
[0] = 0;
164 if(!WideCharToMultiByte(CP_ACP
, 0, tzi
.DaylightName
, -1, MSVCRT__tzname
[1],
165 sizeof(tzname_dst
), NULL
, &error
) || error
)
166 *MSVCRT__tzname
[0] = 0;
171 static void _tzset_init(void)
173 static BOOL init
= FALSE
;
185 static BOOL
is_dst(const SYSTEMTIME
*st
)
187 TIME_ZONE_INFORMATION tmp
;
190 if(!MSVCRT___daylight
)
193 if(tzi
.DaylightDate
.wMonth
) {
195 }else if(st
->wYear
>= 2007) {
196 memset(&tmp
, 0, sizeof(tmp
));
197 tmp
.StandardDate
.wMonth
= 11;
198 tmp
.StandardDate
.wDay
= 1;
199 tmp
.StandardDate
.wHour
= 2;
200 tmp
.DaylightDate
.wMonth
= 3;
201 tmp
.DaylightDate
.wDay
= 2;
202 tmp
.DaylightDate
.wHour
= 2;
204 memset(&tmp
, 0, sizeof(tmp
));
205 tmp
.StandardDate
.wMonth
= 10;
206 tmp
.StandardDate
.wDay
= 5;
207 tmp
.StandardDate
.wHour
= 2;
208 tmp
.DaylightDate
.wMonth
= 4;
209 tmp
.DaylightDate
.wDay
= 1;
210 tmp
.DaylightDate
.wHour
= 2;
214 tmp
.StandardBias
= 0;
215 tmp
.DaylightBias
= MSVCRT__dstbias
/60;
216 if(!SystemTimeToTzSpecificLocalTime(&tmp
, st
, &out
))
219 return memcmp(st
, &out
, sizeof(SYSTEMTIME
));
222 #define SECSPERDAY 86400
223 /* 1601 to 1970 is 369 years plus 89 leap days */
224 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
225 #define TICKSPERSEC 10000000
226 #define TICKSPERMSEC 10000
227 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
229 static __time64_t
mktime_helper(struct tm
*mstm
, BOOL local
)
235 BOOL use_dst
= FALSE
;
237 ret
= mstm
->tm_year
+ mstm
->tm_mon
/12;
239 if(mstm
->tm_mon
< 0) {
244 if(ret
<70 || ret
>1100) {
249 memset(&st
, 0, sizeof(SYSTEMTIME
));
251 st
.wMonth
= mstm
->tm_mon
+1;
254 if(!SystemTimeToFileTime(&st
, &ft
)) {
259 ret
= ((__time64_t
)ft
.dwHighDateTime
<<32)+ft
.dwLowDateTime
;
260 ret
+= (__time64_t
)mstm
->tm_sec
*TICKSPERSEC
;
261 ret
+= (__time64_t
)mstm
->tm_min
*60*TICKSPERSEC
;
262 ret
+= (__time64_t
)mstm
->tm_hour
*60*60*TICKSPERSEC
;
263 ret
+= (__time64_t
)(mstm
->tm_mday
-1)*SECSPERDAY
*TICKSPERSEC
;
265 ft
.dwLowDateTime
= ret
& 0xffffffff;
266 ft
.dwHighDateTime
= ret
>> 32;
267 FileTimeToSystemTime(&ft
, &st
);
271 use_dst
= is_dst(&st
);
272 if((mstm
->tm_isdst
<=-1 && use_dst
) || (mstm
->tm_isdst
>=1)) {
275 ret
+= (__time64_t
)MSVCRT__dstbias
*TICKSPERSEC
;
277 ft
.dwLowDateTime
= ret
& 0xffffffff;
278 ft
.dwHighDateTime
= ret
>> 32;
279 FileTimeToSystemTime(&ft
, &tmp
);
287 }else if(mstm
->tm_isdst
==0 && use_dst
) {
288 ret
-= (__time64_t
)MSVCRT__dstbias
*TICKSPERSEC
;
289 ft
.dwLowDateTime
= ret
& 0xffffffff;
290 ft
.dwHighDateTime
= ret
>> 32;
291 FileTimeToSystemTime(&ft
, &st
);
292 ret
+= (__time64_t
)MSVCRT__dstbias
*TICKSPERSEC
;
294 ret
+= (__time64_t
)MSVCRT___timezone
*TICKSPERSEC
;
297 mstm
->tm_sec
= st
.wSecond
;
298 mstm
->tm_min
= st
.wMinute
;
299 mstm
->tm_hour
= st
.wHour
;
300 mstm
->tm_mday
= st
.wDay
;
301 mstm
->tm_mon
= st
.wMonth
-1;
302 mstm
->tm_year
= st
.wYear
-1900;
303 mstm
->tm_wday
= st
.wDayOfWeek
;
304 for(i
=mstm
->tm_yday
=0; i
<st
.wMonth
-1; i
++)
305 mstm
->tm_yday
+= MonthLengths
[IsLeapYear(st
.wYear
)][i
];
306 mstm
->tm_yday
+= st
.wDay
-1;
307 mstm
->tm_isdst
= use_dst
? 1 : 0;
309 if(ret
< TICKS_1601_TO_1970
) {
313 ret
= (ret
-TICKS_1601_TO_1970
)/TICKSPERSEC
;
317 /**********************************************************************
318 * _mktime64 (MSVCRT.@)
320 __time64_t CDECL
_mktime64(struct tm
*mstm
)
322 return mktime_helper(mstm
, TRUE
);
325 /**********************************************************************
326 * _mktime32 (MSVCRT.@)
328 __time32_t CDECL
_mktime32(struct tm
*mstm
)
330 __time64_t ret
= _mktime64( mstm
);
331 return ret
== (__time32_t
)ret
? ret
: -1;
334 /**********************************************************************
335 * _mkgmtime64 (MSVCRT.@)
337 * time->tm_isdst value is ignored
339 __time64_t CDECL
_mkgmtime64(struct tm
*time
)
341 return mktime_helper(time
, FALSE
);
344 /**********************************************************************
345 * _mkgmtime32 (MSVCRT.@)
347 __time32_t CDECL
_mkgmtime32(struct tm
*time
)
349 __time64_t ret
= _mkgmtime64(time
);
350 return ret
== (__time32_t
)ret
? ret
: -1;
353 /*********************************************************************
354 * _localtime64_s (MSVCRT.@)
356 int CDECL
_localtime64_s(struct tm
*res
, const __time64_t
*secs
)
363 if (!res
|| !secs
|| *secs
< 0 || *secs
> _MAX__TIME64_T
)
366 write_invalid_msvcrt_tm(res
);
373 time
= (*secs
- MSVCRT___timezone
) * (ULONGLONG
)TICKSPERSEC
+ TICKS_1601_TO_1970
;
375 ft
.dwHighDateTime
= (UINT
)(time
>> 32);
376 ft
.dwLowDateTime
= (UINT
)time
;
377 FileTimeToSystemTime(&ft
, &st
);
379 res
->tm_isdst
= is_dst(&st
) ? 1 : 0;
381 time
-= MSVCRT__dstbias
* (ULONGLONG
)TICKSPERSEC
;
382 ft
.dwHighDateTime
= (UINT
)(time
>> 32);
383 ft
.dwLowDateTime
= (UINT
)time
;
384 FileTimeToSystemTime(&ft
, &st
);
387 res
->tm_sec
= st
.wSecond
;
388 res
->tm_min
= st
.wMinute
;
389 res
->tm_hour
= st
.wHour
;
390 res
->tm_mday
= st
.wDay
;
391 res
->tm_year
= st
.wYear
- 1900;
392 res
->tm_mon
= st
.wMonth
- 1;
393 res
->tm_wday
= st
.wDayOfWeek
;
394 for (i
= res
->tm_yday
= 0; i
< st
.wMonth
- 1; i
++)
395 res
->tm_yday
+= MonthLengths
[IsLeapYear(st
.wYear
)][i
];
396 res
->tm_yday
+= st
.wDay
- 1;
401 /*********************************************************************
402 * _localtime64 (MSVCRT.@)
404 struct tm
* CDECL
_localtime64(const __time64_t
* secs
)
406 thread_data_t
*data
= msvcrt_get_thread_data();
408 if(!data
->time_buffer
)
409 data
->time_buffer
= malloc(sizeof(struct tm
));
411 if(_localtime64_s(data
->time_buffer
, secs
))
413 return data
->time_buffer
;
416 /*********************************************************************
417 * _localtime32 (MSVCRT.@)
419 struct tm
* CDECL
_localtime32(const __time32_t
* secs
)
427 return _localtime64( &secs64
);
430 /*********************************************************************
431 * _localtime32_s (MSVCRT.@)
433 int CDECL
_localtime32_s(struct tm
*time
, const __time32_t
*secs
)
437 if (!time
|| !secs
|| *secs
< 0)
440 write_invalid_msvcrt_tm(time
);
447 return _localtime64_s(time
, &secs64
);
450 /*********************************************************************
451 * _gmtime64 (MSVCRT.@)
453 int CDECL
_gmtime64_s(struct tm
*res
, const __time64_t
*secs
)
460 if (!res
|| !secs
|| *secs
< 0 || *secs
> _MAX__TIME64_T
) {
462 write_invalid_msvcrt_tm(res
);
469 time
= *secs
* (ULONGLONG
)TICKSPERSEC
+ TICKS_1601_TO_1970
;
471 ft
.dwHighDateTime
= (UINT
)(time
>> 32);
472 ft
.dwLowDateTime
= (UINT
)time
;
474 FileTimeToSystemTime(&ft
, &st
);
476 res
->tm_sec
= st
.wSecond
;
477 res
->tm_min
= st
.wMinute
;
478 res
->tm_hour
= st
.wHour
;
479 res
->tm_mday
= st
.wDay
;
480 res
->tm_year
= st
.wYear
- 1900;
481 res
->tm_mon
= st
.wMonth
- 1;
482 res
->tm_wday
= st
.wDayOfWeek
;
483 for (i
= res
->tm_yday
= 0; i
< st
.wMonth
- 1; i
++) {
484 res
->tm_yday
+= MonthLengths
[IsLeapYear(st
.wYear
)][i
];
487 res
->tm_yday
+= st
.wDay
- 1;
493 /*********************************************************************
494 * _gmtime64 (MSVCRT.@)
496 struct tm
* CDECL
_gmtime64(const __time64_t
*secs
)
498 thread_data_t
* const data
= msvcrt_get_thread_data();
500 if(!data
->time_buffer
)
501 data
->time_buffer
= malloc(sizeof(struct tm
));
503 if(_gmtime64_s(data
->time_buffer
, secs
))
505 return data
->time_buffer
;
508 /*********************************************************************
509 * _gmtime32_s (MSVCRT.@)
511 int CDECL
_gmtime32_s(struct tm
*res
, const __time32_t
*secs
)
517 return _gmtime64_s(res
, &secs64
);
519 return _gmtime64_s(res
, NULL
);
522 /*********************************************************************
523 * _gmtime32 (MSVCRT.@)
525 struct tm
* CDECL
_gmtime32(const __time32_t
* secs
)
533 return _gmtime64( &secs64
);
536 /**********************************************************************
537 * _strdate (MSVCRT.@)
539 char* CDECL
_strdate(char* date
)
544 date
[0] = '0' + st
.wMonth
/ 10;
545 date
[1] = '0' + st
.wMonth
% 10;
547 date
[3] = '0' + st
.wDay
/ 10;
548 date
[4] = '0' + st
.wDay
% 10;
550 date
[6] = '0' + st
.wYear
/ 10 % 10;
551 date
[7] = '0' + st
.wYear
% 10;
556 /**********************************************************************
557 * _strdate_s (MSVCRT.@)
559 int CDECL
_strdate_s(char* date
, size_t size
)
578 /**********************************************************************
579 * _wstrdate (MSVCRT.@)
581 wchar_t* CDECL
_wstrdate(wchar_t* date
)
583 GetDateFormatW(LOCALE_NEUTRAL
, 0, NULL
, L
"MM'/'dd'/'yy", date
, 9);
587 /**********************************************************************
588 * _wstrdate_s (MSVCRT.@)
590 int CDECL
_wstrdate_s(wchar_t* date
, size_t size
)
609 /*********************************************************************
610 * _strtime (MSVCRT.@)
612 char* CDECL
_strtime(char* time
)
617 time
[0] = '0' + st
.wHour
/ 10;
618 time
[1] = '0' + st
.wHour
% 10;
620 time
[3] = '0' + st
.wMinute
/ 10;
621 time
[4] = '0' + st
.wMinute
% 10;
623 time
[6] = '0' + st
.wSecond
/ 10;
624 time
[7] = '0' + st
.wSecond
% 10;
629 /*********************************************************************
630 * _strtime_s (MSVCRT.@)
632 int CDECL
_strtime_s(char* time
, size_t size
)
651 /*********************************************************************
652 * _wstrtime (MSVCRT.@)
654 wchar_t* CDECL
_wstrtime(wchar_t* time
)
656 GetTimeFormatW(LOCALE_NEUTRAL
, 0, NULL
, L
"HH':'mm':'ss", time
, 9);
660 /*********************************************************************
661 * _wstrtime_s (MSVCRT.@)
663 int CDECL
_wstrtime_s(wchar_t* time
, size_t size
)
682 /*********************************************************************
685 clock_t CDECL
clock(void)
687 LARGE_INTEGER systime
;
689 NtQuerySystemTime(&systime
);
690 return (systime
.QuadPart
- init_time
) / (TICKSPERSEC
/ CLOCKS_PER_SEC
);
693 /*********************************************************************
694 * _difftime64 (MSVCRT.@)
696 double CDECL
_difftime64(__time64_t time1
, __time64_t time2
)
698 return (double)(time1
- time2
);
701 /*********************************************************************
702 * _difftime32 (MSVCRT.@)
704 double CDECL
_difftime32(__time32_t time1
, __time32_t time2
)
706 return (double)(time1
- time2
);
709 /*********************************************************************
710 * _ftime64 (MSVCRT.@)
712 void CDECL
_ftime64(struct __timeb64
*buf
)
714 TIME_ZONE_INFORMATION tzinfo
;
720 GetSystemTimeAsFileTime(&ft
);
722 time
= ((ULONGLONG
)ft
.dwHighDateTime
<< 32) | ft
.dwLowDateTime
;
724 buf
->time
= time
/ TICKSPERSEC
- SECS_1601_TO_1970
;
725 buf
->millitm
= (time
% TICKSPERSEC
) / TICKSPERMSEC
;
726 buf
->timezone
= MSVCRT___timezone
/ 60;
727 buf
->dstflag
= GetTimeZoneInformation( &tzinfo
) == TIME_ZONE_ID_DAYLIGHT
;
730 /*********************************************************************
731 * _ftime64_s (MSVCRT.@)
733 int CDECL
_ftime64_s(struct __timeb64
*buf
)
735 if (!MSVCRT_CHECK_PMT( buf
!= NULL
)) return EINVAL
;
740 /*********************************************************************
741 * _ftime32 (MSVCRT.@)
743 void CDECL
_ftime32(struct __timeb32
*buf
)
745 struct __timeb64 buf64
;
748 buf
->time
= buf64
.time
;
749 buf
->millitm
= buf64
.millitm
;
750 buf
->timezone
= buf64
.timezone
;
751 buf
->dstflag
= buf64
.dstflag
;
754 /*********************************************************************
755 * _ftime32_s (MSVCRT.@)
757 int CDECL
_ftime32_s(struct __timeb32
*buf
)
759 if (!MSVCRT_CHECK_PMT( buf
!= NULL
)) return EINVAL
;
764 /*********************************************************************
767 __time64_t CDECL
_time64(__time64_t
*buf
)
775 return buf
? *buf
= curtime
: curtime
;
778 /*********************************************************************
781 __time32_t CDECL
_time32(__time32_t
*buf
)
789 return buf
? *buf
= curtime
: curtime
;
792 /*********************************************************************
793 * __p__daylight (MSVCRT.@)
795 int * CDECL
__p__daylight(void)
797 return &MSVCRT___daylight
;
800 /*********************************************************************
801 * __p__dstbias (MSVCRT.@)
803 __msvcrt_long
* CDECL
__p__dstbias(void)
805 return &MSVCRT__dstbias
;
809 /*********************************************************************
810 * _get_dstbias (MSVCR80.@)
812 int CDECL
_get_dstbias(int *seconds
)
814 if (!MSVCRT_CHECK_PMT(seconds
!= NULL
)) return EINVAL
;
815 *seconds
= MSVCRT__dstbias
;
820 /*********************************************************************
821 * __p__timezone (MSVCRT.@)
823 __msvcrt_long
* CDECL
__p__timezone(void)
825 return &MSVCRT___timezone
;
828 /*********************************************************************
829 * _get_tzname (MSVCRT.@)
831 int CDECL
_get_tzname(size_t *ret
, char *buf
, size_t bufsize
, int index
)
838 timezone
= tzname_std
;
841 timezone
= tzname_dst
;
848 if(!ret
|| (!buf
&& bufsize
> 0) || (buf
&& !bufsize
))
854 *ret
= strlen(timezone
)+1;
863 strcpy(buf
, timezone
);
867 /*********************************************************************
868 * __p_tzname (MSVCRT.@)
870 char ** CDECL
__p__tzname(void)
872 return MSVCRT__tzname
;
876 #define STRFTIME_CHAR char
877 #define STRFTIME_TD(td, name) td->str.names.name
879 #define STRFTIME_CHAR wchar_t
880 #define STRFTIME_TD(td, name) td->wstr.names.name
883 #define strftime_str(a,b,c,d) strftime_nstr(a,b,c,d,SIZE_MAX)
884 static inline BOOL
strftime_nstr(STRFTIME_CHAR
*str
, size_t *pos
,
885 size_t max
, const STRFTIME_CHAR
*src
, size_t len
)
903 static inline BOOL
strftime_int(STRFTIME_CHAR
*str
, size_t *pos
, size_t max
,
904 int src
, int prec
, int l
, int h
)
908 if(!MSVCRT_CHECK_PMT(src
>=l
&& src
<=h
)) {
914 len
= _snprintf(str
+*pos
, max
-*pos
, "%0*d", prec
, src
);
916 len
= _snwprintf(str
+*pos
, max
-*pos
, L
"%0*d", prec
, src
);
928 static inline BOOL
strftime_format(STRFTIME_CHAR
*str
, size_t *pos
, size_t max
,
929 const struct tm
*mstm
, __lc_time_data
*time_data
, const STRFTIME_CHAR
*format
)
934 while(*format
&& ret
)
937 while(format
[0] == format
[count
]) count
++;
941 if(count
% 2 == 0) break;
945 while(format
[count
] && format
[count
] != '\'') count
++;
947 ret
= strftime_nstr(str
, pos
, max
, format
, count
);
948 if(!ret
) return FALSE
;
949 if(format
[count
] == '\'') count
++;
954 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
963 ret
= strftime_int(str
, pos
, max
, mstm
->tm_mday
, count
==1 ? 0 : 2, 1, 31);
966 ret
= strftime_str(str
, pos
, max
, STRFTIME_TD(time_data
, short_wday
)[mstm
->tm_wday
]);
969 ret
= strftime_nstr(str
, pos
, max
, format
, count
-4);
971 ret
= strftime_str(str
, pos
, max
, STRFTIME_TD(time_data
, wday
)[mstm
->tm_wday
]);
978 if(!MSVCRT_CHECK_PMT(mstm
->tm_mon
>=0 && mstm
->tm_mon
<=11))
987 ret
= strftime_int(str
, pos
, max
, mstm
->tm_mon
+1, count
==1 ? 0 : 2, 1, 12);
990 ret
= strftime_str(str
, pos
, max
, STRFTIME_TD(time_data
, short_mon
)[mstm
->tm_mon
]);
993 ret
= strftime_nstr(str
, pos
, max
, format
, count
-4);
995 ret
= strftime_str(str
, pos
, max
, STRFTIME_TD(time_data
, mon
)[mstm
->tm_mon
]);
1003 if(!MSVCRT_CHECK_PMT(mstm
->tm_year
>= -1900 && mstm
->tm_year
<= 8099))
1005 if(!MSVCRT_CHECK_PMT(mstm
->tm_year
>= 0))
1015 ret
= strftime_nstr(str
, pos
, max
, format
, 1);
1019 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1021 ret
= strftime_int(str
, pos
, max
, (mstm
->tm_year
+1900)%100, 2, 0, 99);
1024 ret
= strftime_nstr(str
, pos
, max
, format
, count
-4);
1026 ret
= strftime_int(str
, pos
, max
, mstm
->tm_year
+1900, 4, 0, 9999);
1031 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1037 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1039 ret
= strftime_int(str
, pos
, max
, (mstm
->tm_hour
+ 11) % 12 + 1,
1040 count
== 1 ? 0 : 2, 1, 12);
1044 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1046 ret
= strftime_int(str
, pos
, max
, mstm
->tm_hour
, count
== 1 ? 0 : 2, 0, 23);
1050 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1052 ret
= strftime_int(str
, pos
, max
, mstm
->tm_min
, count
== 1 ? 0 : 2, 0, 59);
1056 ret
= strftime_nstr(str
, pos
, max
, format
, count
-2);
1058 ret
= strftime_int(str
, pos
, max
, mstm
->tm_sec
, count
== 1 ? 0 : 2, 0, MAX_SECONDS
);
1063 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1068 ret
= strftime_nstr(str
, pos
, max
,
1069 mstm
->tm_hour
< 12 ? STRFTIME_TD(time_data
, am
) : STRFTIME_TD(time_data
, pm
),
1070 (*format
== 't' && count
== 1) ? 1 : SIZE_MAX
);
1073 ret
= strftime_nstr(str
, pos
, max
, format
, count
);
1083 static inline BOOL
strftime_tzdiff(STRFTIME_CHAR
*str
, size_t *pos
, size_t max
, BOOL is_dst
)
1085 __msvcrt_long tz
= MSVCRT___timezone
+ (is_dst
? MSVCRT__dstbias
: 0);
1096 str
[(*pos
)++] = sign
;
1097 if(!strftime_int(str
, pos
, max
, tz
/60/60, 2, 0, 99))
1099 return strftime_int(str
, pos
, max
, tz
/60%60, 2, 0, 59);
1103 static size_t strftime_impl(STRFTIME_CHAR
*str
, size_t max
,
1104 const STRFTIME_CHAR
*format
, const struct tm
*mstm
,
1105 __lc_time_data
*time_data
, _locale_t loc
)
1109 int year
= mstm
? mstm
->tm_year
+ 1900 : -1;
1111 if(!str
|| !format
) {
1119 time_data
= loc
? loc
->locinfo
->lc_time_curr
: get_locinfo()->lc_time_curr
;
1121 for(ret
=0; *format
&& ret
<max
; format
++) {
1122 if(*format
!= '%') {
1123 if(_isleadbyte_l((unsigned char)*format
, loc
)) {
1124 str
[ret
++] = *(format
++);
1125 if(ret
== max
) continue;
1126 if(!MSVCRT_CHECK_PMT(str
[ret
]))
1129 str
[ret
++] = *format
;
1134 if(*format
== '#') {
1141 if(!MSVCRT_CHECK_PMT(mstm
))
1147 if(time_data
== &cloc_time_data
&& !alternate
)
1149 tmp
= strftime_impl(str
+ret
, max
-ret
, L
"%a %b %e %T %Y", mstm
, time_data
, loc
);
1156 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
,
1157 alternate
? STRFTIME_TD(time_data
, date
) : STRFTIME_TD(time_data
, short_date
)))
1161 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
, STRFTIME_TD(time_data
, time
)))
1165 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
,
1166 alternate
? STRFTIME_TD(time_data
, date
) : STRFTIME_TD(time_data
, short_date
)))
1170 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
, STRFTIME_TD(time_data
, time
)))
1174 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1176 if(!strftime_str(str
, &ret
, max
, STRFTIME_TD(time_data
, short_wday
)[mstm
->tm_wday
]))
1180 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1182 if(!strftime_str(str
, &ret
, max
, STRFTIME_TD(time_data
, wday
)[mstm
->tm_wday
]))
1189 if(!MSVCRT_CHECK_PMT(mstm
->tm_mon
>=0 && mstm
->tm_mon
<=11))
1191 if(!strftime_str(str
, &ret
, max
, STRFTIME_TD(time_data
, short_mon
)[mstm
->tm_mon
]))
1195 if(!MSVCRT_CHECK_PMT(mstm
->tm_mon
>=0 && mstm
->tm_mon
<=11))
1197 if(!strftime_str(str
, &ret
, max
, STRFTIME_TD(time_data
, mon
)[mstm
->tm_mon
]))
1202 if(!MSVCRT_CHECK_PMT(year
>=0 && year
<=9999))
1204 if(!strftime_int(str
, &ret
, max
, year
/100, alternate
? 0 : 2, 0, 99))
1209 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 1, 31))
1214 if(!MSVCRT_CHECK_PMT(year
>=0 && year
<=9999))
1216 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mon
+1, alternate
? 0 : 2, 1, 12))
1220 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 1, 31))
1224 if(!strftime_int(str
, &ret
, max
, year
%100, alternate
? 0 : 2, 0, 99))
1228 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 1, 31))
1230 if(!alternate
&& str
[ret
-2] == '0')
1234 if(!strftime_int(str
, &ret
, max
, year
, alternate
? 0 : 4, 0, 9999))
1238 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mon
+1, alternate
? 0 : 2, 1, 12))
1242 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 1, 31))
1247 if(!MSVCRT_CHECK_PMT(year
>=0 && year
<=9999))
1252 int iso_year
= year
;
1253 int iso_days
= mstm
->tm_yday
- (mstm
->tm_wday
? mstm
->tm_wday
: 7) + 4;
1255 iso_days
+= 365 + IsLeapYear(--iso_year
);
1256 else if(iso_days
>= 365 + IsLeapYear(iso_year
))
1257 iso_days
-= 365 + IsLeapYear(iso_year
++);
1259 if(*format
== 'G') {
1260 if(!strftime_int(str
, &ret
, max
, iso_year
, 4, 0, 9999))
1262 } else if(*format
== 'g') {
1263 if(!strftime_int(str
, &ret
, max
, iso_year
%100, 2, 0, 99))
1266 if(!strftime_int(str
, &ret
, max
, iso_days
/7 + 1, alternate
? 0 : 2, 0, 53))
1273 if(!strftime_int(str
, &ret
, max
, mstm
->tm_hour
, alternate
? 0 : 2, 0, 23))
1277 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1279 if(!strftime_int(str
, &ret
, max
, (mstm
->tm_hour
+ 11) % 12 + 1,
1280 alternate
? 0 : 2, 1, 12))
1284 if(!strftime_int(str
, &ret
, max
, mstm
->tm_yday
+1, alternate
? 0 : 3, 1, 366))
1288 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mon
+1, alternate
? 0 : 2, 1, 12))
1292 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1301 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1303 if(!strftime_str(str
, &ret
, max
, mstm
->tm_hour
<12 ?
1304 STRFTIME_TD(time_data
, am
) : STRFTIME_TD(time_data
, pm
)))
1309 if(time_data
== &cloc_time_data
)
1311 if(!MSVCRT_CHECK_PMT(mstm
->tm_hour
>=0 && mstm
->tm_hour
<=23))
1313 if(!strftime_int(str
, &ret
, max
, (mstm
->tm_hour
+ 11) % 12 + 1,
1314 alternate
? 0 : 2, 1, 12))
1318 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1322 if(!strftime_int(str
, &ret
, max
, mstm
->tm_sec
, alternate
? 0 : 2, 0, MAX_SECONDS
))
1326 if(!strftime_str(str
, &ret
, max
, mstm
->tm_hour
<12 ?
1327 STRFTIME_TD(time_data
, am
) : STRFTIME_TD(time_data
, pm
)))
1332 if(!strftime_format(str
, &ret
, max
, mstm
, time_data
, STRFTIME_TD(time_data
, time
)))
1337 if(!strftime_int(str
, &ret
, max
, mstm
->tm_hour
, alternate
? 0 : 2, 0, 23))
1341 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1346 if(!strftime_int(str
, &ret
, max
, mstm
->tm_sec
, alternate
? 0 : 2, 0, MAX_SECONDS
))
1354 if(!strftime_int(str
, &ret
, max
, mstm
->tm_hour
, alternate
? 0 : 2, 0, 23))
1358 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1362 if(!strftime_int(str
, &ret
, max
, mstm
->tm_sec
, alternate
? 0 : 2, 0, MAX_SECONDS
))
1366 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1368 tmp
= mstm
->tm_wday
? mstm
->tm_wday
: 7;
1369 if(!strftime_int(str
, &ret
, max
, tmp
, 0, 1, 7))
1374 if(!strftime_int(str
, &ret
, max
, mstm
->tm_wday
, 0, 0, 6))
1379 if(!MSVCRT_CHECK_PMT(year
>=0 && year
<=9999))
1381 if(!MSVCRT_CHECK_PMT(year
>=1900))
1384 if(!strftime_int(str
, &ret
, max
, year
%100, alternate
? 0 : 2, 0, 99))
1388 if(!strftime_int(str
, &ret
, max
, year
, alternate
? 0 : 4, 0, 9999))
1394 if(!strftime_tzdiff(str
, &ret
, max
, mstm
->tm_isdst
))
1400 #if _MSVCR_VER <= 90
1401 if(_get_tzname(&tmp
, str
+ret
, max
-ret
, mstm
->tm_isdst
? 1 : 0))
1404 if(_mbstowcs_s_l(&tmp
, str
+ret
, max
-ret
,
1405 mstm
->tm_isdst
? tzname_dst
: tzname_std
,
1406 _TRUNCATE
, loc
) == STRUNCATE
)
1413 if(!MSVCRT_CHECK_PMT(mstm
->tm_wday
>=0 && mstm
->tm_wday
<=6))
1415 if(!MSVCRT_CHECK_PMT(mstm
->tm_yday
>=0 && mstm
->tm_yday
<=365))
1418 tmp
= mstm
->tm_wday
;
1419 else if(!mstm
->tm_wday
)
1422 tmp
= mstm
->tm_wday
-1;
1424 tmp
= mstm
->tm_yday
/7 + (tmp
<=mstm
->tm_yday
%7);
1425 if(!strftime_int(str
, &ret
, max
, tmp
, alternate
? 0 : 2, 0, 53))
1432 WARN("unknown format %c\n", *format
);
1433 MSVCRT_INVALID_PMT("unknown format", EINVAL
);
1453 static size_t strftime_helper(char *str
, size_t max
, const char *format
,
1454 const struct tm
*mstm
, __lc_time_data
*time_data
, _locale_t loc
)
1456 #if _MSVCR_VER <= 90
1457 TRACE("(%p %Iu %s %p %p %p)\n", str
, max
, format
, mstm
, time_data
, loc
);
1458 return strftime_impl(str
, max
, format
, mstm
, time_data
, loc
);
1464 TRACE("(%p %Iu %s %p %p %p)\n", str
, max
, format
, mstm
, time_data
, loc
);
1466 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return 0;
1467 if (!MSVCRT_CHECK_PMT(max
!= 0)) return 0;
1469 if (!MSVCRT_CHECK_PMT(format
!= NULL
)) return 0;
1471 cp
= (loc
? loc
->locinfo
: get_locinfo())->lc_id
[LC_TIME
].wCodePage
;
1473 len
= MultiByteToWideChar( cp
, 0, format
, -1, NULL
, 0 );
1479 fmt
= malloc( len
*sizeof(wchar_t) );
1481 MultiByteToWideChar( cp
, 0, format
, -1, fmt
, len
);
1483 if ((s
= malloc( max
*sizeof(wchar_t) )))
1485 len
= strftime_impl( s
, max
, fmt
, mstm
, time_data
, loc
);
1488 len
= WideCharToMultiByte( cp
, 0, s
, -1, str
, max
, NULL
, NULL
);
1490 else *_errno() = EILSEQ
;
1501 #if _MSVCR_VER >= 80
1502 /********************************************************************
1503 * _strftime_l (MSVCR80.@)
1505 size_t CDECL
_strftime_l( char *str
, size_t max
, const char *format
,
1506 const struct tm
*mstm
, _locale_t loc
)
1508 return strftime_helper(str
, max
, format
, mstm
, NULL
, loc
);
1512 /*********************************************************************
1513 * _Strftime (MSVCRT.@)
1515 size_t CDECL
_Strftime(char *str
, size_t max
, const char *format
,
1516 const struct tm
*mstm
, void *time_data
)
1518 return strftime_helper(str
, max
, format
, mstm
, time_data
, NULL
);
1521 /*********************************************************************
1522 * strftime (MSVCRT.@)
1524 size_t CDECL
strftime( char *str
, size_t max
, const char *format
,
1525 const struct tm
*mstm
)
1527 return strftime_helper(str
, max
, format
, mstm
, NULL
, NULL
);
1530 static size_t wcsftime_helper( wchar_t *str
, size_t max
,
1531 const wchar_t *format
, const struct tm
*mstm
,
1532 __lc_time_data
*time_data
, _locale_t loc
)
1534 #if _MSVCR_VER <= 90
1538 TRACE("%p %Iu %s %p %p %p\n", str
, max
, debugstr_w(format
), mstm
, time_data
, loc
);
1540 len
= _wcstombs_l( NULL
, format
, 0, loc
) + 1;
1541 if (!(fmt
= malloc( len
))) return 0;
1542 _wcstombs_l(fmt
, format
, len
, loc
);
1544 if ((s
= malloc( max
*4 )))
1546 if (!strftime_impl( s
, max
*4, fmt
, mstm
, time_data
, loc
)) s
[0] = 0;
1547 len
= _mbstowcs_l( str
, s
, max
, loc
);
1555 TRACE("%p %Iu %s %p %p %p\n", str
, max
, debugstr_w(format
), mstm
, time_data
, loc
);
1556 return strftime_impl(str
, max
, format
, mstm
, time_data
, loc
);
1560 /*********************************************************************
1561 * _wcsftime_l (MSVCRT.@)
1563 size_t CDECL
_wcsftime_l( wchar_t *str
, size_t max
,
1564 const wchar_t *format
, const struct tm
*mstm
, _locale_t loc
)
1566 return wcsftime_helper(str
, max
, format
, mstm
, NULL
, loc
);
1569 /*********************************************************************
1570 * wcsftime (MSVCRT.@)
1572 size_t CDECL
wcsftime( wchar_t *str
, size_t max
,
1573 const wchar_t *format
, const struct tm
*mstm
)
1575 return wcsftime_helper(str
, max
, format
, mstm
, NULL
, NULL
);
1578 #if _MSVCR_VER >= 110
1579 /*********************************************************************
1580 * _Wcsftime (MSVCR110.@)
1582 size_t CDECL
_Wcsftime(wchar_t *str
, size_t max
,
1583 const wchar_t *format
, const struct tm
*mstm
,
1584 __lc_time_data
*time_data
)
1586 return wcsftime_helper(str
, max
, format
, mstm
, time_data
, NULL
);
1590 static char* asctime_buf(char *buf
, const struct tm
*mstm
)
1592 static const char wday
[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
1593 static const char month
[12][4] = {"Jan", "Feb", "Mar", "Apr", "May",
1594 "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1596 if (!mstm
|| mstm
->tm_sec
<0 || mstm
->tm_sec
>59
1597 || mstm
->tm_min
<0 || mstm
->tm_min
>59
1598 || mstm
->tm_hour
<0 || mstm
->tm_hour
>23
1599 || mstm
->tm_mon
<0 || mstm
->tm_mon
>11
1600 || mstm
->tm_wday
<0 || mstm
->tm_wday
>6
1601 || mstm
->tm_year
<0 || mstm
->tm_mday
<0
1602 || mstm
->tm_mday
>MonthLengths
[IsLeapYear(1900+mstm
->tm_year
)][mstm
->tm_mon
]) {
1608 /* C89 (4.12.3.1) uses space-padding for day of month. */
1609 _snprintf(buf
, 26, "%s %s %2d %02d:%02d:%02d %c%03d\n", wday
[mstm
->tm_wday
],
1610 month
[mstm
->tm_mon
], mstm
->tm_mday
, mstm
->tm_hour
, mstm
->tm_min
,
1611 mstm
->tm_sec
, '1'+(mstm
->tm_year
+900)/1000, (900+mstm
->tm_year
)%1000);
1613 _snprintf(buf
, 26, "%s %s %02d %02d:%02d:%02d %c%03d\n", wday
[mstm
->tm_wday
],
1614 month
[mstm
->tm_mon
], mstm
->tm_mday
, mstm
->tm_hour
, mstm
->tm_min
,
1615 mstm
->tm_sec
, '1'+(mstm
->tm_year
+900)/1000, (900+mstm
->tm_year
)%1000);
1620 /*********************************************************************
1621 * asctime (MSVCRT.@)
1623 char * CDECL
asctime(const struct tm
*mstm
)
1625 thread_data_t
*data
= msvcrt_get_thread_data();
1627 /* asctime returns date in format that always has exactly 26 characters */
1628 if (!data
->asctime_buffer
) {
1629 data
->asctime_buffer
= malloc(26);
1630 if (!data
->asctime_buffer
) {
1636 return asctime_buf(data
->asctime_buffer
, mstm
);
1639 /*********************************************************************
1640 * asctime_s (MSVCRT.@)
1642 int CDECL
asctime_s(char* time
, size_t size
, const struct tm
*mstm
)
1644 if (!MSVCRT_CHECK_PMT(time
!= NULL
)) return EINVAL
;
1645 if (size
) time
[0] = 0;
1646 if (!MSVCRT_CHECK_PMT(size
>= 26)) return EINVAL
;
1647 if (!MSVCRT_CHECK_PMT(mstm
!= NULL
)) return EINVAL
;
1648 if (!MSVCRT_CHECK_PMT(mstm
->tm_sec
>= 0 && mstm
->tm_sec
< 60)) return EINVAL
;
1649 if (!MSVCRT_CHECK_PMT(mstm
->tm_min
>= 0 && mstm
->tm_min
< 60)) return EINVAL
;
1650 if (!MSVCRT_CHECK_PMT(mstm
->tm_hour
>= 0 && mstm
->tm_hour
< 24)) return EINVAL
;
1651 if (!MSVCRT_CHECK_PMT(mstm
->tm_mon
>= 0 && mstm
->tm_mon
< 12)) return EINVAL
;
1652 if (!MSVCRT_CHECK_PMT(mstm
->tm_wday
>= 0 && mstm
->tm_wday
< 7)) return EINVAL
;
1653 if (!MSVCRT_CHECK_PMT(mstm
->tm_year
>= 0)) return EINVAL
;
1654 if (!MSVCRT_CHECK_PMT(mstm
->tm_mday
>= 0)) return EINVAL
;
1655 if (!MSVCRT_CHECK_PMT(mstm
->tm_mday
<= MonthLengths
[IsLeapYear(1900+mstm
->tm_year
)][mstm
->tm_mon
])) return EINVAL
;
1657 asctime_buf(time
, mstm
);
1661 /*********************************************************************
1662 * _wasctime (MSVCRT.@)
1664 wchar_t * CDECL
_wasctime(const struct tm
*mstm
)
1666 thread_data_t
*data
= msvcrt_get_thread_data();
1669 if(!data
->wasctime_buffer
) {
1670 data
->wasctime_buffer
= malloc(26*sizeof(wchar_t));
1671 if(!data
->wasctime_buffer
) {
1677 if(!asctime_buf(buffer
, mstm
))
1680 MultiByteToWideChar(CP_ACP
, 0, buffer
, -1, data
->wasctime_buffer
, 26);
1681 return data
->wasctime_buffer
;
1684 /*********************************************************************
1685 * _wasctime_s (MSVCRT.@)
1687 int CDECL
_wasctime_s(wchar_t* time
, size_t size
, const struct tm
*mstm
)
1692 if (!MSVCRT_CHECK_PMT(time
!= NULL
)) return EINVAL
;
1693 if (size
) time
[0] = 0;
1694 if (!MSVCRT_CHECK_PMT(size
>= 26)) return EINVAL
;
1695 if (!MSVCRT_CHECK_PMT(mstm
!= NULL
)) return EINVAL
;
1697 ret
= asctime_s(buffer
, sizeof(buffer
), mstm
);
1700 MultiByteToWideChar(CP_ACP
, 0, buffer
, -1, time
, size
);
1704 /*********************************************************************
1705 * _ctime64 (MSVCRT.@)
1707 char * CDECL
_ctime64(const __time64_t
*time
)
1710 t
= _localtime64( time
);
1711 if (!t
) return NULL
;
1712 return asctime( t
);
1715 /*********************************************************************
1716 * _ctime64_s (MSVCRT.@)
1718 int CDECL
_ctime64_s(char *res
, size_t len
, const __time64_t
*time
)
1722 if (!MSVCRT_CHECK_PMT( res
!= NULL
)) return EINVAL
;
1723 if (!MSVCRT_CHECK_PMT( len
>= 26 )) return EINVAL
;
1725 if (!MSVCRT_CHECK_PMT( time
!= NULL
)) return EINVAL
;
1726 if (!MSVCRT_CHECK_PMT( *time
> 0 )) return EINVAL
;
1728 t
= _localtime64( time
);
1729 strcpy( res
, asctime( t
) );
1733 /*********************************************************************
1734 * _ctime32 (MSVCRT.@)
1736 char * CDECL
_ctime32(const __time32_t
*time
)
1739 t
= _localtime32( time
);
1740 if (!t
) return NULL
;
1741 return asctime( t
);
1744 /*********************************************************************
1745 * _ctime32_s (MSVCRT.@)
1747 int CDECL
_ctime32_s(char *res
, size_t len
, const __time32_t
*time
)
1751 if (!MSVCRT_CHECK_PMT( res
!= NULL
)) return EINVAL
;
1752 if (!MSVCRT_CHECK_PMT( len
>= 26 )) return EINVAL
;
1754 if (!MSVCRT_CHECK_PMT( time
!= NULL
)) return EINVAL
;
1755 if (!MSVCRT_CHECK_PMT( *time
> 0 )) return EINVAL
;
1757 t
= _localtime32( time
);
1758 strcpy( res
, asctime( t
) );
1762 /*********************************************************************
1763 * _wctime64 (MSVCRT.@)
1765 wchar_t * CDECL
_wctime64(const __time64_t
*time
)
1767 return _wasctime( _localtime64(time
) );
1770 /*********************************************************************
1771 * _wctime32 (MSVCRT.@)
1773 wchar_t * CDECL
_wctime32(const __time32_t
*time
)
1775 return _wasctime( _localtime32(time
) );
1778 /*********************************************************************
1779 * _wctime64_s (MSVCRT.@)
1781 int CDECL
_wctime64_s(wchar_t *buf
,
1782 size_t size
, const __time64_t
*time
)
1787 if(!MSVCRT_CHECK_PMT(buf
!= NULL
)) return EINVAL
;
1788 if(!MSVCRT_CHECK_PMT(size
!= 0)) return EINVAL
;
1790 if(!MSVCRT_CHECK_PMT(time
!= NULL
)) return EINVAL
;
1791 if(!MSVCRT_CHECK_PMT(*time
>= 0)) return EINVAL
;
1792 if(!MSVCRT_CHECK_PMT(*time
<= _MAX__TIME64_T
)) return EINVAL
;
1794 ret
= _localtime64_s(&tm
, time
);
1798 return _wasctime_s(buf
, size
, &tm
);
1801 /*********************************************************************
1802 * _wctime32_s (MSVCRT.@)
1804 int CDECL
_wctime32_s(wchar_t *buf
, size_t size
,
1805 const __time32_t
*time
)
1810 if(!MSVCRT_CHECK_PMT(buf
!= NULL
)) return EINVAL
;
1811 if(!MSVCRT_CHECK_PMT(size
!= 0)) return EINVAL
;
1813 if(!MSVCRT_CHECK_PMT(time
!= NULL
)) return EINVAL
;
1814 if(!MSVCRT_CHECK_PMT(*time
>= 0)) return EINVAL
;
1816 ret
= _localtime32_s(&tm
, time
);
1820 return _wasctime_s(buf
, size
, &tm
);
1823 #if _MSVCR_VER >= 80
1825 /*********************************************************************
1826 * _get_timezone (MSVCR80.@)
1828 int CDECL
_get_timezone(LONG
*timezone
)
1830 if(!MSVCRT_CHECK_PMT(timezone
!= NULL
)) return EINVAL
;
1832 *timezone
= MSVCRT___timezone
;
1836 /*********************************************************************
1837 * _get_daylight (MSVCR80.@)
1839 int CDECL
_get_daylight(int *hours
)
1841 if(!MSVCRT_CHECK_PMT(hours
!= NULL
)) return EINVAL
;
1843 *hours
= MSVCRT___daylight
;
1847 #endif /* _MSVCR_VER >= 80 */
1849 #if _MSVCR_VER >= 140
1865 /*********************************************************************
1866 * _timespec64_get (UCRTBASE.@)
1868 int CDECL
_timespec64_get(struct _timespec64
*ts
, int base
)
1873 if(!MSVCRT_CHECK_PMT(ts
!= NULL
)) return 0;
1874 if(base
!= TIME_UTC
) return 0;
1876 GetSystemTimePreciseAsFileTime(&ft
);
1877 time
= ((ULONGLONG
)ft
.dwHighDateTime
<< 32) | ft
.dwLowDateTime
;
1879 ts
->tv_sec
= time
/ TICKSPERSEC
- SECS_1601_TO_1970
;
1880 ts
->tv_nsec
= time
% TICKSPERSEC
* 100;
1884 /*********************************************************************
1885 * _timespec32_get (UCRTBASE.@)
1887 int CDECL
_timespec32_get(struct _timespec32
*ts
, int base
)
1889 struct _timespec64 ts64
;
1891 if(!MSVCRT_CHECK_PMT(ts
!= NULL
)) return 0;
1892 if(base
!= TIME_UTC
) return 0;
1894 if(_timespec64_get(&ts64
, base
) != base
)
1896 if(ts64
.tv_sec
!= (__time32_t
)ts64
.tv_sec
)
1899 ts
->tv_sec
= ts64
.tv_sec
;
1900 ts
->tv_nsec
= ts64
.tv_nsec
;
1903 #endif /* _MSVCR_VER >= 140 */