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
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
39 static const int MonthLengths
[2][12] =
41 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
42 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
45 static inline BOOL
IsLeapYear(int Year
)
47 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0);
50 static inline void write_invalid_msvcrt_tm( struct MSVCRT_tm
*tm
)
63 /*********************************************************************
64 * _daylight (MSVCRT.@)
66 int MSVCRT___daylight
= 1;
68 /*********************************************************************
69 * _timezone (MSVCRT.@)
71 MSVCRT_long MSVCRT___timezone
= 28800;
73 /*********************************************************************
76 int MSVCRT__dstbias
= -3600;
78 /*********************************************************************
81 * Some apps (notably Mozilla) insist on writing to these, so the buffer
82 * must be large enough.
84 static char tzname_std
[64] = "PST";
85 static char tzname_dst
[64] = "PDT";
86 char *MSVCRT__tzname
[2] = { tzname_std
, tzname_dst
};
88 static TIME_ZONE_INFORMATION tzi
= {0};
89 /*********************************************************************
92 void CDECL
MSVCRT__tzset(void)
94 char *tz
= MSVCRT_getenv("TZ");
99 BOOL neg_zone
= FALSE
;
101 memset(&tzi
, 0, sizeof(tzi
));
103 /* Parse timezone information: tzn[+|-]hh[:mm[:ss]][dzn] */
104 lstrcpynA(MSVCRT__tzname
[0], tz
, 3);
110 }else if(*tz
== '+') {
113 MSVCRT___timezone
= strtol(tz
, &tz
, 10)*3600;
115 MSVCRT___timezone
+= strtol(tz
+1, &tz
, 10)*60;
117 MSVCRT___timezone
+= strtol(tz
+1, &tz
, 10);
120 MSVCRT___timezone
= -MSVCRT___timezone
;
122 MSVCRT___daylight
= *tz
;
123 lstrcpynA(MSVCRT__tzname
[1], tz
, 3);
124 }else if(GetTimeZoneInformation(&tzi
) != TIME_ZONE_ID_INVALID
) {
125 MSVCRT___timezone
= tzi
.Bias
*60;
126 if(tzi
.StandardDate
.wMonth
)
127 MSVCRT___timezone
+= tzi
.StandardBias
*60;
129 if(tzi
.DaylightDate
.wMonth
) {
130 MSVCRT___daylight
= 1;
131 MSVCRT__dstbias
= (tzi
.DaylightBias
-tzi
.StandardBias
)*60;
133 MSVCRT___daylight
= 0;
137 if(!WideCharToMultiByte(CP_ACP
, 0, tzi
.StandardName
, -1, MSVCRT__tzname
[0],
138 sizeof(tzname_std
), NULL
, &error
) || error
)
139 *MSVCRT__tzname
[0] = 0;
140 if(!WideCharToMultiByte(CP_ACP
, 0, tzi
.DaylightName
, -1, MSVCRT__tzname
[1],
141 sizeof(tzname_dst
), NULL
, &error
) || error
)
142 *MSVCRT__tzname
[0] = 0;
144 _munlock(_TIME_LOCK
);
147 static void _tzset_init(void)
149 static BOOL init
= FALSE
;
157 _munlock(_TIME_LOCK
);
161 static BOOL
is_dst(const SYSTEMTIME
*st
)
163 TIME_ZONE_INFORMATION tmp
;
166 if(!MSVCRT___daylight
)
169 if(tzi
.DaylightDate
.wMonth
) {
171 }else if(st
->wYear
>= 2007) {
172 memset(&tmp
, 0, sizeof(tmp
));
173 tmp
.StandardDate
.wMonth
= 11;
174 tmp
.StandardDate
.wDay
= 1;
175 tmp
.StandardDate
.wHour
= 2;
176 tmp
.DaylightDate
.wMonth
= 3;
177 tmp
.DaylightDate
.wDay
= 2;
178 tmp
.DaylightDate
.wHour
= 2;
180 memset(&tmp
, 0, sizeof(tmp
));
181 tmp
.StandardDate
.wMonth
= 10;
182 tmp
.StandardDate
.wDay
= 5;
183 tmp
.StandardDate
.wHour
= 2;
184 tmp
.DaylightDate
.wMonth
= 4;
185 tmp
.DaylightDate
.wDay
= 1;
186 tmp
.DaylightDate
.wHour
= 2;
190 tmp
.StandardBias
= 0;
191 tmp
.DaylightBias
= MSVCRT__dstbias
/60;
192 if(!SystemTimeToTzSpecificLocalTime(&tmp
, st
, &out
))
195 return memcmp(st
, &out
, sizeof(SYSTEMTIME
));
198 #define SECSPERDAY 86400
199 /* 1601 to 1970 is 369 years plus 89 leap days */
200 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
201 #define TICKSPERSEC 10000000
202 #define TICKSPERMSEC 10000
203 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
205 static MSVCRT___time64_t
mktime_helper(struct MSVCRT_tm
*mstm
, BOOL local
)
209 MSVCRT___time64_t ret
= 0;
211 BOOL use_dst
= FALSE
;
213 ret
= mstm
->tm_year
+ mstm
->tm_mon
/12;
215 if(mstm
->tm_mon
< 0) {
220 if(ret
<70 || ret
>1100) {
221 *MSVCRT__errno() = MSVCRT_EINVAL
;
225 memset(&st
, 0, sizeof(SYSTEMTIME
));
227 st
.wMonth
= mstm
->tm_mon
+1;
230 if(!SystemTimeToFileTime(&st
, &ft
)) {
231 *MSVCRT__errno() = MSVCRT_EINVAL
;
235 ret
= ((MSVCRT___time64_t
)ft
.dwHighDateTime
<<32)+ft
.dwLowDateTime
;
236 ret
+= (MSVCRT___time64_t
)mstm
->tm_sec
*TICKSPERSEC
;
237 ret
+= (MSVCRT___time64_t
)mstm
->tm_min
*60*TICKSPERSEC
;
238 ret
+= (MSVCRT___time64_t
)mstm
->tm_hour
*60*60*TICKSPERSEC
;
239 ret
+= (MSVCRT___time64_t
)(mstm
->tm_mday
-1)*SECSPERDAY
*TICKSPERSEC
;
241 ft
.dwLowDateTime
= ret
& 0xffffffff;
242 ft
.dwHighDateTime
= ret
>> 32;
243 FileTimeToSystemTime(&ft
, &st
);
247 use_dst
= is_dst(&st
);
248 if((mstm
->tm_isdst
<=-1 && use_dst
) || (mstm
->tm_isdst
>=1)) {
251 ret
+= (MSVCRT___time64_t
)MSVCRT__dstbias
*TICKSPERSEC
;
253 ft
.dwLowDateTime
= ret
& 0xffffffff;
254 ft
.dwHighDateTime
= ret
>> 32;
255 FileTimeToSystemTime(&ft
, &tmp
);
263 }else if(mstm
->tm_isdst
==0 && use_dst
) {
264 ret
-= (MSVCRT___time64_t
)MSVCRT__dstbias
*TICKSPERSEC
;
265 ft
.dwLowDateTime
= ret
& 0xffffffff;
266 ft
.dwHighDateTime
= ret
>> 32;
267 FileTimeToSystemTime(&ft
, &st
);
268 ret
+= (MSVCRT___time64_t
)MSVCRT__dstbias
*TICKSPERSEC
;
270 ret
+= (MSVCRT___time64_t
)MSVCRT___timezone
*TICKSPERSEC
;
273 mstm
->tm_sec
= st
.wSecond
;
274 mstm
->tm_min
= st
.wMinute
;
275 mstm
->tm_hour
= st
.wHour
;
276 mstm
->tm_mday
= st
.wDay
;
277 mstm
->tm_mon
= st
.wMonth
-1;
278 mstm
->tm_year
= st
.wYear
-1900;
279 mstm
->tm_wday
= st
.wDayOfWeek
;
280 for(i
=mstm
->tm_yday
=0; i
<st
.wMonth
-1; i
++)
281 mstm
->tm_yday
+= MonthLengths
[IsLeapYear(st
.wYear
)][i
];
282 mstm
->tm_yday
+= st
.wDay
-1;
283 mstm
->tm_isdst
= use_dst
? 1 : 0;
285 if(ret
< TICKS_1601_TO_1970
) {
286 *MSVCRT__errno() = MSVCRT_EINVAL
;
289 ret
= (ret
-TICKS_1601_TO_1970
)/TICKSPERSEC
;
293 /**********************************************************************
294 * _mktime64 (MSVCRT.@)
296 MSVCRT___time64_t CDECL
MSVCRT__mktime64(struct MSVCRT_tm
*mstm
)
298 return mktime_helper(mstm
, TRUE
);
301 /**********************************************************************
302 * _mktime32 (MSVCRT.@)
304 MSVCRT___time32_t CDECL
MSVCRT__mktime32(struct MSVCRT_tm
*mstm
)
306 MSVCRT___time64_t ret
= MSVCRT__mktime64( mstm
);
307 return ret
== (MSVCRT___time32_t
)ret
? ret
: -1;
310 /**********************************************************************
314 MSVCRT___time64_t CDECL
MSVCRT_mktime(struct MSVCRT_tm
*mstm
)
316 return MSVCRT__mktime64( mstm
);
319 MSVCRT___time32_t CDECL
MSVCRT_mktime(struct MSVCRT_tm
*mstm
)
321 return MSVCRT__mktime32( mstm
);
325 /**********************************************************************
326 * _mkgmtime64 (MSVCRT.@)
328 * time->tm_isdst value is ignored
330 MSVCRT___time64_t CDECL
MSVCRT__mkgmtime64(struct MSVCRT_tm
*time
)
332 return mktime_helper(time
, FALSE
);
335 /**********************************************************************
336 * _mkgmtime32 (MSVCRT.@)
338 MSVCRT___time32_t CDECL
MSVCRT__mkgmtime32(struct MSVCRT_tm
*time
)
340 MSVCRT___time64_t ret
= MSVCRT__mkgmtime64(time
);
341 return ret
== (MSVCRT___time32_t
)ret
? ret
: -1;
344 /**********************************************************************
345 * _mkgmtime (MSVCRT.@)
348 MSVCRT___time64_t CDECL
MSVCRT__mkgmtime(struct MSVCRT_tm
*time
)
350 return MSVCRT__mkgmtime64(time
);
353 MSVCRT___time32_t CDECL
MSVCRT__mkgmtime(struct MSVCRT_tm
*time
)
355 return MSVCRT__mkgmtime32(time
);
359 /*********************************************************************
360 * _localtime64_s (MSVCRT.@)
362 int CDECL
_localtime64_s(struct MSVCRT_tm
*res
, const MSVCRT___time64_t
*secs
)
369 if (!res
|| !secs
|| *secs
< 0 || *secs
> _MAX__TIME64_T
)
372 write_invalid_msvcrt_tm(res
);
374 *MSVCRT__errno() = MSVCRT_EINVAL
;
375 return MSVCRT_EINVAL
;
379 time
= (*secs
- MSVCRT___timezone
) * (ULONGLONG
)TICKSPERSEC
+ TICKS_1601_TO_1970
;
381 ft
.dwHighDateTime
= (UINT
)(time
>> 32);
382 ft
.dwLowDateTime
= (UINT
)time
;
383 FileTimeToSystemTime(&ft
, &st
);
385 res
->tm_isdst
= is_dst(&st
) ? 1 : 0;
387 time
-= MSVCRT__dstbias
* (ULONGLONG
)TICKSPERSEC
;
388 ft
.dwHighDateTime
= (UINT
)(time
>> 32);
389 ft
.dwLowDateTime
= (UINT
)time
;
390 FileTimeToSystemTime(&ft
, &st
);
393 res
->tm_sec
= st
.wSecond
;
394 res
->tm_min
= st
.wMinute
;
395 res
->tm_hour
= st
.wHour
;
396 res
->tm_mday
= st
.wDay
;
397 res
->tm_year
= st
.wYear
- 1900;
398 res
->tm_mon
= st
.wMonth
- 1;
399 res
->tm_wday
= st
.wDayOfWeek
;
400 for (i
= res
->tm_yday
= 0; i
< st
.wMonth
- 1; i
++)
401 res
->tm_yday
+= MonthLengths
[IsLeapYear(st
.wYear
)][i
];
402 res
->tm_yday
+= st
.wDay
- 1;
407 /*********************************************************************
408 * _localtime64 (MSVCRT.@)
410 struct MSVCRT_tm
* CDECL
MSVCRT__localtime64(const MSVCRT___time64_t
* secs
)
412 thread_data_t
*data
= msvcrt_get_thread_data();
414 if(!data
->time_buffer
)
415 data
->time_buffer
= MSVCRT_malloc(sizeof(struct MSVCRT_tm
));
417 if(_localtime64_s(data
->time_buffer
, secs
))
419 return data
->time_buffer
;
422 /*********************************************************************
423 * _localtime32 (MSVCRT.@)
425 struct MSVCRT_tm
* CDECL
MSVCRT__localtime32(const MSVCRT___time32_t
* secs
)
427 MSVCRT___time64_t secs64
;
433 return MSVCRT__localtime64( &secs64
);
436 /*********************************************************************
437 * _localtime32_s (MSVCRT.@)
439 int CDECL
_localtime32_s(struct MSVCRT_tm
*time
, const MSVCRT___time32_t
*secs
)
441 MSVCRT___time64_t secs64
;
443 if (!time
|| !secs
|| *secs
< 0)
446 write_invalid_msvcrt_tm(time
);
448 *MSVCRT__errno() = MSVCRT_EINVAL
;
449 return MSVCRT_EINVAL
;
453 return _localtime64_s(time
, &secs64
);
456 /*********************************************************************
457 * localtime (MSVCRT.@)
460 struct MSVCRT_tm
* CDECL
MSVCRT_localtime(const MSVCRT___time64_t
* secs
)
462 return MSVCRT__localtime64( secs
);
465 struct MSVCRT_tm
* CDECL
MSVCRT_localtime(const MSVCRT___time32_t
* secs
)
467 return MSVCRT__localtime32( secs
);
471 /*********************************************************************
472 * _gmtime64 (MSVCRT.@)
474 int CDECL
MSVCRT__gmtime64_s(struct MSVCRT_tm
*res
, const MSVCRT___time64_t
*secs
)
481 if (!res
|| !secs
|| *secs
< 0 || *secs
> _MAX__TIME64_T
) {
483 write_invalid_msvcrt_tm(res
);
486 *MSVCRT__errno() = MSVCRT_EINVAL
;
487 return MSVCRT_EINVAL
;
490 time
= *secs
* (ULONGLONG
)TICKSPERSEC
+ TICKS_1601_TO_1970
;
492 ft
.dwHighDateTime
= (UINT
)(time
>> 32);
493 ft
.dwLowDateTime
= (UINT
)time
;
495 FileTimeToSystemTime(&ft
, &st
);
497 res
->tm_sec
= st
.wSecond
;
498 res
->tm_min
= st
.wMinute
;
499 res
->tm_hour
= st
.wHour
;
500 res
->tm_mday
= st
.wDay
;
501 res
->tm_year
= st
.wYear
- 1900;
502 res
->tm_mon
= st
.wMonth
- 1;
503 res
->tm_wday
= st
.wDayOfWeek
;
504 for (i
= res
->tm_yday
= 0; i
< st
.wMonth
- 1; i
++) {
505 res
->tm_yday
+= MonthLengths
[IsLeapYear(st
.wYear
)][i
];
508 res
->tm_yday
+= st
.wDay
- 1;
514 /*********************************************************************
515 * _gmtime64 (MSVCRT.@)
517 struct MSVCRT_tm
* CDECL
MSVCRT__gmtime64(const MSVCRT___time64_t
*secs
)
519 thread_data_t
* const data
= msvcrt_get_thread_data();
521 if(!data
->time_buffer
)
522 data
->time_buffer
= MSVCRT_malloc(sizeof(struct MSVCRT_tm
));
524 if(MSVCRT__gmtime64_s(data
->time_buffer
, secs
))
526 return data
->time_buffer
;
529 /*********************************************************************
530 * _gmtime32_s (MSVCRT.@)
532 int CDECL
MSVCRT__gmtime32_s(struct MSVCRT_tm
*res
, const MSVCRT___time32_t
*secs
)
534 MSVCRT___time64_t secs64
;
538 return MSVCRT__gmtime64_s(res
, &secs64
);
540 return MSVCRT__gmtime64_s(res
, NULL
);
543 /*********************************************************************
544 * _gmtime32 (MSVCRT.@)
546 struct MSVCRT_tm
* CDECL
MSVCRT__gmtime32(const MSVCRT___time32_t
* secs
)
548 MSVCRT___time64_t secs64
;
554 return MSVCRT__gmtime64( &secs64
);
557 /*********************************************************************
561 struct MSVCRT_tm
* CDECL
MSVCRT_gmtime(const MSVCRT___time64_t
* secs
)
563 return MSVCRT__gmtime64( secs
);
566 struct MSVCRT_tm
* CDECL
MSVCRT_gmtime(const MSVCRT___time32_t
* secs
)
568 return MSVCRT__gmtime32( secs
);
572 /**********************************************************************
573 * _strdate (MSVCRT.@)
575 char* CDECL
MSVCRT__strdate(char* date
)
577 static const char format
[] = "MM'/'dd'/'yy";
579 GetDateFormatA(LOCALE_NEUTRAL
, 0, NULL
, format
, date
, 9);
584 /**********************************************************************
585 * _strdate_s (MSVCRT.@)
587 int CDECL
_strdate_s(char* date
, MSVCRT_size_t size
)
593 *MSVCRT__errno() = MSVCRT_EINVAL
;
594 return MSVCRT_EINVAL
;
598 *MSVCRT__errno() = MSVCRT_ERANGE
;
599 return MSVCRT_ERANGE
;
602 MSVCRT__strdate(date
);
606 /**********************************************************************
607 * _wstrdate (MSVCRT.@)
609 MSVCRT_wchar_t
* CDECL
MSVCRT__wstrdate(MSVCRT_wchar_t
* date
)
611 static const WCHAR format
[] = { 'M','M','\'','/','\'','d','d','\'','/','\'','y','y',0 };
613 GetDateFormatW(LOCALE_NEUTRAL
, 0, NULL
, format
, date
, 9);
618 /**********************************************************************
619 * _wstrdate_s (MSVCRT.@)
621 int CDECL
_wstrdate_s(MSVCRT_wchar_t
* date
, MSVCRT_size_t size
)
627 *MSVCRT__errno() = MSVCRT_EINVAL
;
628 return MSVCRT_EINVAL
;
632 *MSVCRT__errno() = MSVCRT_ERANGE
;
633 return MSVCRT_ERANGE
;
636 MSVCRT__wstrdate(date
);
640 /*********************************************************************
641 * _strtime (MSVCRT.@)
643 char* CDECL
MSVCRT__strtime(char* time
)
645 static const char format
[] = "HH':'mm':'ss";
647 GetTimeFormatA(LOCALE_NEUTRAL
, 0, NULL
, format
, time
, 9);
652 /*********************************************************************
653 * _strtime_s (MSVCRT.@)
655 int CDECL
_strtime_s(char* time
, MSVCRT_size_t size
)
661 *MSVCRT__errno() = MSVCRT_EINVAL
;
662 return MSVCRT_EINVAL
;
666 *MSVCRT__errno() = MSVCRT_ERANGE
;
667 return MSVCRT_ERANGE
;
670 MSVCRT__strtime(time
);
674 /*********************************************************************
675 * _wstrtime (MSVCRT.@)
677 MSVCRT_wchar_t
* CDECL
MSVCRT__wstrtime(MSVCRT_wchar_t
* time
)
679 static const WCHAR format
[] = { 'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0 };
681 GetTimeFormatW(LOCALE_NEUTRAL
, 0, NULL
, format
, time
, 9);
686 /*********************************************************************
687 * _wstrtime_s (MSVCRT.@)
689 int CDECL
_wstrtime_s(MSVCRT_wchar_t
* time
, MSVCRT_size_t size
)
695 *MSVCRT__errno() = MSVCRT_EINVAL
;
696 return MSVCRT_EINVAL
;
700 *MSVCRT__errno() = MSVCRT_ERANGE
;
701 return MSVCRT_ERANGE
;
704 MSVCRT__wstrtime(time
);
708 /*********************************************************************
711 MSVCRT_clock_t CDECL
MSVCRT_clock(void)
713 static LONGLONG start_time
;
714 LARGE_INTEGER systime
;
717 KERNEL_USER_TIMES pti
;
719 /* while Linux's clock returns user time, Windows' clock
720 * returns wall-clock time from process start. cache the
721 * process start time since it won't change and to avoid
722 * wineserver round-trip overhead */
723 if(NtQueryInformationProcess(GetCurrentProcess(), ProcessTimes
, &pti
, sizeof(pti
), NULL
))
725 start_time
= pti
.CreateTime
.QuadPart
;
728 NtQuerySystemTime(&systime
);
729 return (systime
.QuadPart
- start_time
) * MSVCRT_CLOCKS_PER_SEC
/ TICKSPERSEC
;
732 /*********************************************************************
733 * _difftime64 (MSVCRT.@)
735 double CDECL
MSVCRT__difftime64(MSVCRT___time64_t time1
, MSVCRT___time64_t time2
)
737 return (double)(time1
- time2
);
740 /*********************************************************************
741 * _difftime32 (MSVCRT.@)
743 double CDECL
MSVCRT__difftime32(MSVCRT___time32_t time1
, MSVCRT___time32_t time2
)
745 return (double)(time1
- time2
);
748 /*********************************************************************
749 * difftime (MSVCRT.@)
752 double CDECL
MSVCRT_difftime(MSVCRT___time64_t time1
, MSVCRT___time64_t time2
)
754 return MSVCRT__difftime64( time1
, time2
);
757 double CDECL
MSVCRT_difftime(MSVCRT___time32_t time1
, MSVCRT___time32_t time2
)
759 return MSVCRT__difftime32( time1
, time2
);
763 /*********************************************************************
764 * _ftime64 (MSVCRT.@)
766 void CDECL
MSVCRT__ftime64(struct MSVCRT___timeb64
*buf
)
768 TIME_ZONE_INFORMATION tzinfo
;
772 DWORD tzid
= GetTimeZoneInformation(&tzinfo
);
773 GetSystemTimeAsFileTime(&ft
);
775 time
= ((ULONGLONG
)ft
.dwHighDateTime
<< 32) | ft
.dwLowDateTime
;
777 buf
->time
= time
/ TICKSPERSEC
- SECS_1601_TO_1970
;
778 buf
->millitm
= (time
% TICKSPERSEC
) / TICKSPERMSEC
;
779 buf
->timezone
= tzinfo
.Bias
+
780 ( tzid
== TIME_ZONE_ID_STANDARD
? tzinfo
.StandardBias
:
781 ( tzid
== TIME_ZONE_ID_DAYLIGHT
? tzinfo
.DaylightBias
: 0 ));
782 buf
->dstflag
= (tzid
== TIME_ZONE_ID_DAYLIGHT
?1:0);
785 /*********************************************************************
786 * _ftime64_s (MSVCRT.@)
788 int CDECL
MSVCRT__ftime64_s(struct MSVCRT___timeb64
*buf
)
790 if (!MSVCRT_CHECK_PMT( buf
!= NULL
)) return MSVCRT_EINVAL
;
791 MSVCRT__ftime64(buf
);
795 /*********************************************************************
796 * _ftime32 (MSVCRT.@)
798 void CDECL
MSVCRT__ftime32(struct MSVCRT___timeb32
*buf
)
800 struct MSVCRT___timeb64 buf64
;
802 MSVCRT__ftime64( &buf64
);
803 buf
->time
= buf64
.time
;
804 buf
->millitm
= buf64
.millitm
;
805 buf
->timezone
= buf64
.timezone
;
806 buf
->dstflag
= buf64
.dstflag
;
809 /*********************************************************************
810 * _ftime32_s (MSVCRT.@)
812 int CDECL
MSVCRT__ftime32_s(struct MSVCRT___timeb32
*buf
)
814 if (!MSVCRT_CHECK_PMT( buf
!= NULL
)) return MSVCRT_EINVAL
;
815 MSVCRT__ftime32(buf
);
819 /*********************************************************************
823 void CDECL
MSVCRT__ftime(struct MSVCRT___timeb64
*buf
)
825 MSVCRT__ftime64( buf
);
828 void CDECL
MSVCRT__ftime(struct MSVCRT___timeb32
*buf
)
830 MSVCRT__ftime32( buf
);
834 /*********************************************************************
837 MSVCRT___time64_t CDECL
MSVCRT__time64(MSVCRT___time64_t
*buf
)
839 MSVCRT___time64_t curtime
;
840 struct MSVCRT___timeb64 tb
;
842 MSVCRT__ftime64(&tb
);
845 return buf
? *buf
= curtime
: curtime
;
848 /*********************************************************************
851 MSVCRT___time32_t CDECL
MSVCRT__time32(MSVCRT___time32_t
*buf
)
853 MSVCRT___time32_t curtime
;
854 struct MSVCRT___timeb64 tb
;
856 MSVCRT__ftime64(&tb
);
859 return buf
? *buf
= curtime
: curtime
;
862 /*********************************************************************
866 MSVCRT___time64_t CDECL
MSVCRT_time(MSVCRT___time64_t
* buf
)
868 return MSVCRT__time64( buf
);
871 MSVCRT___time32_t CDECL
MSVCRT_time(MSVCRT___time32_t
* buf
)
873 return MSVCRT__time32( buf
);
877 /*********************************************************************
878 * __p_daylight (MSVCRT.@)
880 int * CDECL
MSVCRT___p__daylight(void)
882 return &MSVCRT___daylight
;
885 /*********************************************************************
886 * __p_dstbias (MSVCRT.@)
888 int * CDECL
__p__dstbias(void)
890 return &MSVCRT__dstbias
;
893 /*********************************************************************
894 * __p_timezone (MSVCRT.@)
896 MSVCRT_long
* CDECL
MSVCRT___p__timezone(void)
898 return &MSVCRT___timezone
;
901 /*********************************************************************
902 * _get_tzname (MSVCRT.@)
904 int CDECL
MSVCRT__get_tzname(MSVCRT_size_t
*ret
, char *buf
, MSVCRT_size_t bufsize
, int index
)
911 timezone
= tzname_std
;
914 timezone
= tzname_dst
;
917 *MSVCRT__errno() = MSVCRT_EINVAL
;
918 return MSVCRT_EINVAL
;
921 if(!ret
|| (!buf
&& bufsize
> 0) || (buf
&& !bufsize
))
923 *MSVCRT__errno() = MSVCRT_EINVAL
;
924 return MSVCRT_EINVAL
;
927 *ret
= strlen(timezone
)+1;
931 strcpy(buf
, timezone
);
935 /*********************************************************************
936 * __p_tzname (MSVCRT.@)
938 char ** CDECL
__p__tzname(void)
940 return MSVCRT__tzname
;
943 static inline BOOL
strftime_date(char *str
, MSVCRT_size_t
*pos
, MSVCRT_size_t max
,
944 BOOL alternate
, const struct MSVCRT_tm
*mstm
, MSVCRT___lc_time_data
*time_data
)
950 st
.wYear
= mstm
->tm_year
+ 1900;
951 st
.wMonth
= mstm
->tm_mon
+ 1;
952 st
.wDayOfWeek
= mstm
->tm_wday
;
953 st
.wDay
= mstm
->tm_mday
;
954 st
.wHour
= mstm
->tm_hour
;
955 st
.wMinute
= mstm
->tm_min
;
956 st
.wSecond
= mstm
->tm_sec
;
957 st
.wMilliseconds
= 0;
959 format
= alternate
? time_data
->str
.names
.date
: time_data
->str
.names
.short_date
;
960 ret
= GetDateFormatA(time_data
->lcid
, 0, &st
, format
, NULL
, 0);
961 if(ret
&& ret
<max
-*pos
)
962 ret
= GetDateFormatA(time_data
->lcid
, 0, &st
, format
, str
+*pos
, max
-*pos
);
965 *MSVCRT__errno() = MSVCRT_EINVAL
;
967 }else if(ret
> max
-*pos
) {
969 *MSVCRT__errno() = MSVCRT_ERANGE
;
976 static inline BOOL
strftime_time(char *str
, MSVCRT_size_t
*pos
, MSVCRT_size_t max
,
977 const struct MSVCRT_tm
*mstm
, MSVCRT___lc_time_data
*time_data
)
982 st
.wYear
= mstm
->tm_year
+ 1900;
983 st
.wMonth
= mstm
->tm_mon
+ 1;
984 st
.wDayOfWeek
= mstm
->tm_wday
;
985 st
.wDay
= mstm
->tm_mday
;
986 st
.wHour
= mstm
->tm_hour
;
987 st
.wMinute
= mstm
->tm_min
;
988 st
.wSecond
= mstm
->tm_sec
;
989 st
.wMilliseconds
= 0;
991 ret
= GetTimeFormatA(time_data
->lcid
, 0, &st
, time_data
->str
.names
.time
, NULL
, 0);
992 if(ret
&& ret
<max
-*pos
)
993 ret
= GetTimeFormatA(time_data
->lcid
, 0, &st
, time_data
->str
.names
.time
,
997 *MSVCRT__errno() = MSVCRT_EINVAL
;
999 }else if(ret
> max
-*pos
) {
1001 *MSVCRT__errno() = MSVCRT_ERANGE
;
1008 static inline BOOL
strftime_str(char *str
, MSVCRT_size_t
*pos
, MSVCRT_size_t max
, char *src
)
1010 MSVCRT_size_t len
= strlen(src
);
1011 if(len
> max
-*pos
) {
1013 *MSVCRT__errno() = MSVCRT_ERANGE
;
1017 memcpy(str
+*pos
, src
, len
);
1022 static inline BOOL
strftime_int(char *str
, MSVCRT_size_t
*pos
, MSVCRT_size_t max
,
1023 int src
, int prec
, int l
, int h
)
1027 if(src
<l
|| src
>h
) {
1029 *MSVCRT__errno() = MSVCRT_EINVAL
;
1033 len
= MSVCRT__snprintf(str
+*pos
, max
-*pos
, "%0*d", prec
, src
);
1036 *MSVCRT__errno() = MSVCRT_ERANGE
;
1044 /*********************************************************************
1045 * _Strftime (MSVCRT.@)
1047 MSVCRT_size_t CDECL
_Strftime(char *str
, MSVCRT_size_t max
, const char *format
,
1048 const struct MSVCRT_tm
*mstm
, MSVCRT___lc_time_data
*time_data
)
1050 MSVCRT_size_t ret
, tmp
;
1053 TRACE("(%p %ld %s %p %p)\n", str
, max
, format
, mstm
, time_data
);
1055 if(!str
|| !format
) {
1058 *MSVCRT__errno() = MSVCRT_EINVAL
;
1063 time_data
= get_locinfo()->lc_time_curr
;
1065 for(ret
=0; *format
&& ret
<max
; format
++) {
1066 if(*format
!= '%') {
1067 str
[ret
++] = *format
;
1072 if(*format
== '#') {
1084 if(!strftime_date(str
, &ret
, max
, alternate
, mstm
, time_data
))
1088 if(!strftime_time(str
, &ret
, max
, mstm
, time_data
))
1092 if(!strftime_date(str
, &ret
, max
, alternate
, mstm
, time_data
))
1096 if(!strftime_time(str
, &ret
, max
, mstm
, time_data
))
1100 if(mstm
->tm_wday
<0 || mstm
->tm_wday
>6)
1102 if(!strftime_str(str
, &ret
, max
, time_data
->str
.names
.short_wday
[mstm
->tm_wday
]))
1106 if(mstm
->tm_wday
<0 || mstm
->tm_wday
>6)
1108 if(!strftime_str(str
, &ret
, max
, time_data
->str
.names
.wday
[mstm
->tm_wday
]))
1112 if(mstm
->tm_mon
<0 || mstm
->tm_mon
>11)
1114 if(!strftime_str(str
, &ret
, max
, time_data
->str
.names
.short_mon
[mstm
->tm_mon
]))
1118 if(mstm
->tm_mon
<0 || mstm
->tm_mon
>11)
1120 if(!strftime_str(str
, &ret
, max
, time_data
->str
.names
.mon
[mstm
->tm_mon
]))
1124 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mday
, alternate
? 0 : 2, 0, 31))
1128 if(!strftime_int(str
, &ret
, max
, mstm
->tm_hour
, alternate
? 0 : 2, 0, 23))
1132 tmp
= mstm
->tm_hour
;
1137 if(!strftime_int(str
, &ret
, max
, tmp
, alternate
? 0 : 2, 1, 12))
1141 if(!strftime_int(str
, &ret
, max
, mstm
->tm_yday
+1, alternate
? 0 : 3, 1, 366))
1145 if(!strftime_int(str
, &ret
, max
, mstm
->tm_mon
+1, alternate
? 0 : 2, 1, 12))
1149 if(!strftime_int(str
, &ret
, max
, mstm
->tm_min
, alternate
? 0 : 2, 0, 59))
1153 if(mstm
->tm_hour
<0 || mstm
->tm_hour
>23)
1155 if(!strftime_str(str
, &ret
, max
, mstm
->tm_hour
<12 ?
1156 time_data
->str
.names
.am
: time_data
->str
.names
.pm
))
1160 if(!strftime_int(str
, &ret
, max
, mstm
->tm_sec
, alternate
? 0 : 2, 0, 59))
1164 if(!strftime_int(str
, &ret
, max
, mstm
->tm_wday
, 0, 0, 6))
1168 if(!strftime_int(str
, &ret
, max
, mstm
->tm_year
%100, alternate
? 0 : 2, 0, 99))
1172 tmp
= 1900+mstm
->tm_year
;
1173 if(!strftime_int(str
, &ret
, max
, tmp
, alternate
? 0 : 4, 0, 9999))
1179 if(MSVCRT__get_tzname(&tmp
, str
+ret
, max
-ret
, mstm
->tm_isdst
? 1 : 0))
1185 if(mstm
->tm_wday
<0 || mstm
->tm_wday
>6 || mstm
->tm_yday
<0 || mstm
->tm_yday
>365)
1188 tmp
= mstm
->tm_wday
;
1189 else if(!mstm
->tm_wday
)
1192 tmp
= mstm
->tm_wday
-1;
1194 tmp
= mstm
->tm_yday
/7 + (tmp
<=mstm
->tm_yday
%7);
1195 if(!strftime_int(str
, &ret
, max
, tmp
, alternate
? 0 : 2, 0, 53))
1202 WARN("unknown format %c\n", *format
);
1210 *MSVCRT__errno() = MSVCRT_ERANGE
;
1219 *MSVCRT__errno() = MSVCRT_EINVAL
;
1223 /*********************************************************************
1224 * strftime (MSVCRT.@)
1226 MSVCRT_size_t CDECL
MSVCRT_strftime( char *str
, MSVCRT_size_t max
, const char *format
,
1227 const struct MSVCRT_tm
*mstm
)
1229 return _Strftime(str
, max
, format
, mstm
, NULL
);
1232 /*********************************************************************
1233 * wcsftime (MSVCRT.@)
1235 MSVCRT_size_t CDECL
MSVCRT_wcsftime( MSVCRT_wchar_t
*str
, MSVCRT_size_t max
,
1236 const MSVCRT_wchar_t
*format
, const struct MSVCRT_tm
*mstm
)
1241 TRACE("%p %ld %s %p\n", str
, max
, debugstr_w(format
), mstm
);
1243 len
= WideCharToMultiByte( CP_UNIXCP
, 0, format
, -1, NULL
, 0, NULL
, NULL
);
1244 if (!(fmt
= MSVCRT_malloc( len
))) return 0;
1245 WideCharToMultiByte( CP_UNIXCP
, 0, format
, -1, fmt
, len
, NULL
, NULL
);
1247 if ((s
= MSVCRT_malloc( max
*4 )))
1249 if (!MSVCRT_strftime( s
, max
*4, fmt
, mstm
)) s
[0] = 0;
1250 len
= MultiByteToWideChar( CP_UNIXCP
, 0, s
, -1, str
, max
);
1260 static char* asctime_buf(char *buf
, const struct MSVCRT_tm
*mstm
)
1262 static const char wday
[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
1263 static const char month
[12][4] = {"Jan", "Feb", "Mar", "Apr", "May",
1264 "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1266 if (mstm
->tm_sec
<0 || mstm
->tm_sec
>59
1267 || mstm
->tm_min
<0 || mstm
->tm_min
>59
1268 || mstm
->tm_hour
<0 || mstm
->tm_hour
>23
1269 || mstm
->tm_mon
<0 || mstm
->tm_mon
>11
1270 || mstm
->tm_wday
<0 || mstm
->tm_wday
>6
1271 || mstm
->tm_year
<0 || mstm
->tm_mday
<0
1272 || mstm
->tm_mday
>MonthLengths
[IsLeapYear(1900+mstm
->tm_year
)][mstm
->tm_mon
]) {
1273 *MSVCRT__errno() = MSVCRT_EINVAL
;
1277 MSVCRT__snprintf(buf
, 26, "%s %s %02d %02d:%02d:%02d %c%03d\n", wday
[mstm
->tm_wday
],
1278 month
[mstm
->tm_mon
], mstm
->tm_mday
, mstm
->tm_hour
, mstm
->tm_min
,
1279 mstm
->tm_sec
, '1'+(mstm
->tm_year
+900)/1000, (900+mstm
->tm_year
)%1000);
1283 /*********************************************************************
1284 * asctime (MSVCRT.@)
1286 char * CDECL
MSVCRT_asctime(const struct MSVCRT_tm
*mstm
)
1288 thread_data_t
*data
= msvcrt_get_thread_data();
1290 /* asctime returns date in format that always has exactly 26 characters */
1291 if (!data
->asctime_buffer
) {
1292 data
->asctime_buffer
= MSVCRT_malloc(26);
1293 if (!data
->asctime_buffer
) {
1294 *MSVCRT__errno() = MSVCRT_ENOMEM
;
1299 return asctime_buf(data
->asctime_buffer
, mstm
);
1302 /*********************************************************************
1303 * asctime_s (MSVCRT.@)
1305 int CDECL
MSVCRT_asctime_s(char* time
, MSVCRT_size_t size
, const struct MSVCRT_tm
*mstm
)
1307 if (!MSVCRT_CHECK_PMT(time
!= NULL
)) return MSVCRT_EINVAL
;
1308 if (size
) time
[0] = 0;
1309 if (!MSVCRT_CHECK_PMT(size
>= 26)) return MSVCRT_EINVAL
;
1310 if (!MSVCRT_CHECK_PMT(mstm
!= NULL
)) return MSVCRT_EINVAL
;
1311 if (!MSVCRT_CHECK_PMT(mstm
->tm_sec
>= 0 && mstm
->tm_sec
< 60)) return MSVCRT_EINVAL
;
1312 if (!MSVCRT_CHECK_PMT(mstm
->tm_min
>= 0 && mstm
->tm_min
< 60)) return MSVCRT_EINVAL
;
1313 if (!MSVCRT_CHECK_PMT(mstm
->tm_hour
>= 0 && mstm
->tm_hour
< 24)) return MSVCRT_EINVAL
;
1314 if (!MSVCRT_CHECK_PMT(mstm
->tm_mon
>= 0 && mstm
->tm_mon
< 12)) return MSVCRT_EINVAL
;
1315 if (!MSVCRT_CHECK_PMT(mstm
->tm_wday
>= 0 && mstm
->tm_wday
< 7)) return MSVCRT_EINVAL
;
1316 if (!MSVCRT_CHECK_PMT(mstm
->tm_year
>= 0)) return MSVCRT_EINVAL
;
1317 if (!MSVCRT_CHECK_PMT(mstm
->tm_mday
>= 0)) return MSVCRT_EINVAL
;
1318 if (!MSVCRT_CHECK_PMT(mstm
->tm_mday
<= MonthLengths
[IsLeapYear(1900+mstm
->tm_year
)][mstm
->tm_mon
])) return MSVCRT_EINVAL
;
1320 asctime_buf(time
, mstm
);
1324 /*********************************************************************
1325 * _wasctime (MSVCRT.@)
1327 MSVCRT_wchar_t
* CDECL
MSVCRT__wasctime(const struct MSVCRT_tm
*mstm
)
1329 thread_data_t
*data
= msvcrt_get_thread_data();
1332 if(!data
->wasctime_buffer
) {
1333 data
->wasctime_buffer
= MSVCRT_malloc(26*sizeof(MSVCRT_wchar_t
));
1334 if(!data
->wasctime_buffer
) {
1335 *MSVCRT__errno() = MSVCRT_ENOMEM
;
1340 if(!asctime_buf(buffer
, mstm
))
1343 MultiByteToWideChar(CP_ACP
, 0, buffer
, -1, data
->wasctime_buffer
, 26);
1344 return data
->wasctime_buffer
;
1347 /*********************************************************************
1348 * _wasctime_s (MSVCRT.@)
1350 int CDECL
MSVCRT__wasctime_s(MSVCRT_wchar_t
* time
, MSVCRT_size_t size
, const struct MSVCRT_tm
*mstm
)
1355 if (!MSVCRT_CHECK_PMT(time
!= NULL
)) return MSVCRT_EINVAL
;
1356 if (size
) time
[0] = 0;
1357 if (!MSVCRT_CHECK_PMT(size
>= 26)) return MSVCRT_EINVAL
;
1358 if (!MSVCRT_CHECK_PMT(mstm
!= NULL
)) return MSVCRT_EINVAL
;
1360 ret
= MSVCRT_asctime_s(buffer
, sizeof(buffer
), mstm
);
1363 MultiByteToWideChar(CP_ACP
, 0, buffer
, -1, time
, size
);
1367 /*********************************************************************
1368 * _ctime64 (MSVCRT.@)
1370 char * CDECL
MSVCRT__ctime64(const MSVCRT___time64_t
*time
)
1372 struct MSVCRT_tm
*t
;
1373 t
= MSVCRT__localtime64( time
);
1374 if (!t
) return NULL
;
1375 return MSVCRT_asctime( t
);
1378 /*********************************************************************
1379 * _ctime64_s (MSVCRT.@)
1381 int CDECL
MSVCRT__ctime64_s(char *res
, MSVCRT_size_t len
, const MSVCRT___time64_t
*time
)
1383 struct MSVCRT_tm
*t
;
1385 if (!MSVCRT_CHECK_PMT( res
!= NULL
)) return MSVCRT_EINVAL
;
1386 if (!MSVCRT_CHECK_PMT( len
>= 26 )) return MSVCRT_EINVAL
;
1388 if (!MSVCRT_CHECK_PMT( time
!= NULL
)) return MSVCRT_EINVAL
;
1389 if (!MSVCRT_CHECK_PMT( *time
> 0 )) return MSVCRT_EINVAL
;
1391 t
= MSVCRT__localtime64( time
);
1392 strcpy( res
, MSVCRT_asctime( t
) );
1396 /*********************************************************************
1397 * _ctime32 (MSVCRT.@)
1399 char * CDECL
MSVCRT__ctime32(const MSVCRT___time32_t
*time
)
1401 struct MSVCRT_tm
*t
;
1402 t
= MSVCRT__localtime32( time
);
1403 if (!t
) return NULL
;
1404 return MSVCRT_asctime( t
);
1407 /*********************************************************************
1408 * _ctime32_s (MSVCRT.@)
1410 int CDECL
MSVCRT__ctime32_s(char *res
, MSVCRT_size_t len
, const MSVCRT___time32_t
*time
)
1412 struct MSVCRT_tm
*t
;
1414 if (!MSVCRT_CHECK_PMT( res
!= NULL
)) return MSVCRT_EINVAL
;
1415 if (!MSVCRT_CHECK_PMT( len
>= 26 )) return MSVCRT_EINVAL
;
1417 if (!MSVCRT_CHECK_PMT( time
!= NULL
)) return MSVCRT_EINVAL
;
1418 if (!MSVCRT_CHECK_PMT( *time
> 0 )) return MSVCRT_EINVAL
;
1420 t
= MSVCRT__localtime32( time
);
1421 strcpy( res
, MSVCRT_asctime( t
) );
1425 /*********************************************************************
1429 char * CDECL
MSVCRT_ctime(const MSVCRT___time64_t
*time
)
1431 return MSVCRT__ctime64( time
);
1434 char * CDECL
MSVCRT_ctime(const MSVCRT___time32_t
*time
)
1436 return MSVCRT__ctime32( time
);
1440 /*********************************************************************
1441 * _wctime64 (MSVCRT.@)
1443 MSVCRT_wchar_t
* CDECL
MSVCRT__wctime64(const MSVCRT___time64_t
*time
)
1445 return MSVCRT__wasctime( MSVCRT__localtime64(time
) );
1448 /*********************************************************************
1449 * _wctime32 (MSVCRT.@)
1451 MSVCRT_wchar_t
* CDECL
MSVCRT__wctime32(const MSVCRT___time32_t
*time
)
1453 return MSVCRT__wasctime( MSVCRT__localtime32(time
) );
1456 /*********************************************************************
1457 * _wctime (MSVCRT.@)
1460 MSVCRT_wchar_t
* CDECL
MSVCRT__wctime(const MSVCRT___time64_t
*time
)
1462 return MSVCRT__wctime64( time
);
1465 MSVCRT_wchar_t
* CDECL
MSVCRT__wctime(const MSVCRT___time32_t
*time
)
1467 return MSVCRT__wctime32( time
);