msvcrt: Added UTF8 support to read function.
[wine] / dlls / msvcrt / time.c
1 /*
2  * msvcrt.dll date/time functions
3  *
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
9  *
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.
14  *
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.
19  *
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
23  */
24
25 #include "config.h"
26
27 #include <stdlib.h>
28
29 #include "msvcrt.h"
30 #include "mtdll.h"
31 #include "winbase.h"
32 #include "winnls.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
37
38 static const int MonthLengths[2][12] =
39 {
40     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
41     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
42 };
43
44 static inline int IsLeapYear(int Year)
45 {
46     return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
47 }
48
49 static inline void write_invalid_msvcrt_tm( struct MSVCRT_tm *tm )
50 {
51     tm->tm_sec = -1;
52     tm->tm_min = -1;
53     tm->tm_hour = -1;
54     tm->tm_mday = -1;
55     tm->tm_mon = -1;
56     tm->tm_year = -1;
57     tm->tm_wday = -1;
58     tm->tm_yday = -1;
59     tm->tm_isdst = -1;
60 }
61
62 /*********************************************************************
63  *              _daylight (MSVCRT.@)
64  */
65 int MSVCRT___daylight = 1;
66
67 /*********************************************************************
68  *              _timezone (MSVCRT.@)
69  */
70 MSVCRT_long MSVCRT___timezone = 28800;
71
72 /*********************************************************************
73  *              _dstbias (MSVCRT.@)
74  */
75 int MSVCRT__dstbias = -3600;
76
77 /*********************************************************************
78  *              _tzname (MSVCRT.@)
79  * NOTES
80  *  Some apps (notably Mozilla) insist on writing to these, so the buffer
81  *  must be large enough.
82  */
83 static char tzname_std[64] = "PST";
84 static char tzname_dst[64] = "PDT";
85 char *MSVCRT__tzname[2] = { tzname_std, tzname_dst };
86
87 static TIME_ZONE_INFORMATION tzi = {0};
88 /*********************************************************************
89  *              _tzset (MSVCRT.@)
90  */
91 void CDECL MSVCRT__tzset(void)
92 {
93     char *tz = MSVCRT_getenv("TZ");
94     BOOL error;
95
96     _mlock(_TIME_LOCK);
97     if(tz && tz[0]) {
98         BOOL neg_zone = FALSE;
99
100         memset(&tzi, 0, sizeof(tzi));
101
102         /* Parse timezone information: tzn[+|-]hh[:mm[:ss]][dzn] */
103         lstrcpynA(MSVCRT__tzname[0], tz, 3);
104         tz += 3;
105
106         if(*tz == '-') {
107             neg_zone = TRUE;
108             tz++;
109         }else if(*tz == '+') {
110             tz++;
111         }
112         MSVCRT___timezone = strtol(tz, &tz, 10)*3600;
113         if(*tz == ':') {
114             MSVCRT___timezone += strtol(tz+1, &tz, 10)*60;
115             if(*tz == ':')
116                 MSVCRT___timezone += strtol(tz+1, &tz, 10);
117         }
118         if(neg_zone)
119             MSVCRT___timezone = -MSVCRT___timezone;
120
121         MSVCRT___daylight = *tz;
122         lstrcpynA(MSVCRT__tzname[1], tz, 3);
123     }else if(GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
124         MSVCRT___timezone = tzi.Bias*60;
125         if(tzi.StandardDate.wMonth)
126             MSVCRT___timezone += tzi.StandardBias*60;
127
128         if(tzi.DaylightDate.wMonth) {
129             MSVCRT___daylight = 1;
130             MSVCRT__dstbias = (tzi.DaylightBias-tzi.StandardBias)*60;
131         }else {
132             MSVCRT___daylight = 0;
133             MSVCRT__dstbias = 0;
134         }
135
136         if(!WideCharToMultiByte(CP_ACP, 0, tzi.StandardName, -1, MSVCRT__tzname[0],
137                     sizeof(tzname_std), NULL, &error) || error)
138             *MSVCRT__tzname[0] = 0;
139         if(!WideCharToMultiByte(CP_ACP, 0, tzi.DaylightName, -1, MSVCRT__tzname[1],
140                     sizeof(tzname_dst), NULL, &error) || error)
141             *MSVCRT__tzname[0] = 0;
142     }
143     _munlock(_TIME_LOCK);
144 }
145
146 static void _tzset_init(void)
147 {
148     static BOOL init = FALSE;
149
150     if(!init) {
151         _mlock(_TIME_LOCK);
152         if(!init) {
153             MSVCRT__tzset();
154             init = TRUE;
155         }
156         _munlock(_TIME_LOCK);
157     }
158 }
159
160 static BOOL is_dst(const SYSTEMTIME *st)
161 {
162     TIME_ZONE_INFORMATION tmp;
163     SYSTEMTIME out;
164
165     if(!MSVCRT___daylight)
166         return FALSE;
167
168     if(tzi.DaylightDate.wMonth) {
169         tmp = tzi;
170     }else if(st->wYear >= 2007) {
171         memset(&tmp, 0, sizeof(tmp));
172         tmp.StandardDate.wMonth = 11;
173         tmp.StandardDate.wDay = 1;
174         tmp.StandardDate.wHour = 2;
175         tmp.DaylightDate.wMonth = 3;
176         tmp.DaylightDate.wDay = 2;
177         tmp.DaylightDate.wHour = 2;
178     }else {
179         memset(&tmp, 0, sizeof(tmp));
180         tmp.StandardDate.wMonth = 10;
181         tmp.StandardDate.wDay = 5;
182         tmp.StandardDate.wHour = 2;
183         tmp.DaylightDate.wMonth = 4;
184         tmp.DaylightDate.wDay = 1;
185         tmp.DaylightDate.wHour = 2;
186     }
187
188     tmp.Bias = 0;
189     tmp.StandardBias = 0;
190     tmp.DaylightBias = MSVCRT__dstbias/60;
191     if(!SystemTimeToTzSpecificLocalTime(&tmp, st, &out))
192         return FALSE;
193
194     return memcmp(st, &out, sizeof(SYSTEMTIME));
195 }
196
197 #define SECSPERDAY        86400
198 /* 1601 to 1970 is 369 years plus 89 leap days */
199 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
200 #define TICKSPERSEC       10000000
201 #define TICKSPERMSEC      10000
202 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
203
204 static MSVCRT___time64_t mktime_helper(struct MSVCRT_tm *mstm, BOOL local)
205 {
206     SYSTEMTIME st;
207     FILETIME ft;
208     MSVCRT___time64_t ret = 0;
209     int i;
210     BOOL use_dst = FALSE;
211
212     ret = mstm->tm_year + mstm->tm_mon/12;
213     mstm->tm_mon %= 12;
214     if(mstm->tm_mon < 0) {
215         mstm->tm_mon += 12;
216         ret--;
217     }
218
219     if(ret<70 || ret>1100) {
220         *MSVCRT__errno() = MSVCRT_EINVAL;
221         return -1;
222     }
223
224     memset(&st, 0, sizeof(SYSTEMTIME));
225     st.wDay = 1;
226     st.wMonth = mstm->tm_mon+1;
227     st.wYear = ret+1900;
228
229     if(!SystemTimeToFileTime(&st, &ft)) {
230         *MSVCRT__errno() = MSVCRT_EINVAL;
231         return -1;
232     }
233
234     ret = ((MSVCRT___time64_t)ft.dwHighDateTime<<32)+ft.dwLowDateTime;
235     ret += (MSVCRT___time64_t)mstm->tm_sec*TICKSPERSEC;
236     ret += (MSVCRT___time64_t)mstm->tm_min*60*TICKSPERSEC;
237     ret += (MSVCRT___time64_t)mstm->tm_hour*60*60*TICKSPERSEC;
238     ret += (MSVCRT___time64_t)(mstm->tm_mday-1)*SECSPERDAY*TICKSPERSEC;
239
240     ft.dwLowDateTime = ret & 0xffffffff;
241     ft.dwHighDateTime = ret >> 32;
242     FileTimeToSystemTime(&ft, &st);
243
244     if(local) {
245         _tzset_init();
246         use_dst = is_dst(&st);
247         if((mstm->tm_isdst<=-1 && use_dst) || (mstm->tm_isdst>=1)) {
248             SYSTEMTIME tmp;
249
250             ret += (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
251
252             ft.dwLowDateTime = ret & 0xffffffff;
253             ft.dwHighDateTime = ret >> 32;
254             FileTimeToSystemTime(&ft, &tmp);
255
256             if(!is_dst(&tmp)) {
257                 st = tmp;
258                 use_dst = FALSE;
259             }else {
260                 use_dst = TRUE;
261             }
262         }else if(mstm->tm_isdst==0 && use_dst) {
263             ret -= (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
264             ft.dwLowDateTime = ret & 0xffffffff;
265             ft.dwHighDateTime = ret >> 32;
266             FileTimeToSystemTime(&ft, &st);
267             ret += (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
268         }
269         ret += (MSVCRT___time64_t)MSVCRT___timezone*TICKSPERSEC;
270     }
271
272     mstm->tm_sec = st.wSecond;
273     mstm->tm_min = st.wMinute;
274     mstm->tm_hour = st.wHour;
275     mstm->tm_mday = st.wDay;
276     mstm->tm_mon = st.wMonth-1;
277     mstm->tm_year = st.wYear-1900;
278     mstm->tm_wday = st.wDayOfWeek;
279     for(i=mstm->tm_yday=0; i<st.wMonth-1; i++)
280         mstm->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
281     mstm->tm_yday += st.wDay-1;
282     mstm->tm_isdst = use_dst ? 1 : 0;
283
284     if(ret < TICKS_1601_TO_1970) {
285         *MSVCRT__errno() = MSVCRT_EINVAL;
286         return -1;
287     }
288     ret = (ret-TICKS_1601_TO_1970)/TICKSPERSEC;
289     return ret;
290 }
291
292 /**********************************************************************
293  *              _mktime64 (MSVCRT.@)
294  */
295 MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
296 {
297     return mktime_helper(mstm, TRUE);
298 }
299
300 /**********************************************************************
301  *              _mktime32 (MSVCRT.@)
302  */
303 MSVCRT___time32_t CDECL MSVCRT__mktime32(struct MSVCRT_tm *mstm)
304 {
305     MSVCRT___time64_t ret = MSVCRT__mktime64( mstm );
306     return ret == (MSVCRT___time32_t)ret ? ret : -1;
307 }
308
309 /**********************************************************************
310  *              mktime (MSVCRT.@)
311  */
312 #ifdef _WIN64
313 MSVCRT___time64_t CDECL MSVCRT_mktime(struct MSVCRT_tm *mstm)
314 {
315     return MSVCRT__mktime64( mstm );
316 }
317 #else
318 MSVCRT___time32_t CDECL MSVCRT_mktime(struct MSVCRT_tm *mstm)
319 {
320     return MSVCRT__mktime32( mstm );
321 }
322 #endif
323
324 /**********************************************************************
325  *              _mkgmtime64 (MSVCRT.@)
326  *
327  * time->tm_isdst value is ignored
328  */
329 MSVCRT___time64_t CDECL MSVCRT__mkgmtime64(struct MSVCRT_tm *time)
330 {
331     return mktime_helper(time, FALSE);
332 }
333
334 /**********************************************************************
335  *              _mkgmtime32 (MSVCRT.@)
336  */
337 MSVCRT___time32_t CDECL MSVCRT__mkgmtime32(struct MSVCRT_tm *time)
338 {
339     MSVCRT___time64_t ret = MSVCRT__mkgmtime64(time);
340     return ret == (MSVCRT___time32_t)ret ? ret : -1;
341 }
342
343 /**********************************************************************
344  *              _mkgmtime (MSVCRT.@)
345  */
346 #ifdef _WIN64
347 MSVCRT___time64_t CDECL MSVCRT__mkgmtime(struct MSVCRT_tm *time)
348 {
349     return MSVCRT__mkgmtime64(time);
350 }
351 #else
352 MSVCRT___time32_t CDECL MSVCRT__mkgmtime(struct MSVCRT_tm *time)
353 {
354     return MSVCRT__mkgmtime32(time);
355 }
356 #endif
357
358 /*********************************************************************
359  *      _localtime64_s (MSVCRT.@)
360  */
361 int CDECL _localtime64_s(struct MSVCRT_tm *res, const MSVCRT___time64_t *secs)
362 {
363     int i;
364     FILETIME ft;
365     SYSTEMTIME st;
366     ULONGLONG time;
367
368     if (!res || !secs || *secs < 0 || *secs > _MAX__TIME64_T)
369     {
370         if (res)
371             write_invalid_msvcrt_tm(res);
372
373         *MSVCRT__errno() = MSVCRT_EINVAL;
374         return MSVCRT_EINVAL;
375     }
376
377     _tzset_init();
378     time = (*secs - MSVCRT___timezone) * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
379
380     ft.dwHighDateTime = (UINT)(time >> 32);
381     ft.dwLowDateTime  = (UINT)time;
382     FileTimeToSystemTime(&ft, &st);
383
384     res->tm_isdst = is_dst(&st) ? 1 : 0;
385     if(res->tm_isdst) {
386         time -= MSVCRT__dstbias * (ULONGLONG)TICKSPERSEC;
387         ft.dwHighDateTime = (UINT)(time >> 32);
388         ft.dwLowDateTime  = (UINT)time;
389         FileTimeToSystemTime(&ft, &st);
390     }
391
392     res->tm_sec  = st.wSecond;
393     res->tm_min  = st.wMinute;
394     res->tm_hour = st.wHour;
395     res->tm_mday = st.wDay;
396     res->tm_year = st.wYear - 1900;
397     res->tm_mon  = st.wMonth - 1;
398     res->tm_wday = st.wDayOfWeek;
399     for (i = res->tm_yday = 0; i < st.wMonth - 1; i++)
400         res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
401     res->tm_yday += st.wDay - 1;
402
403     return 0;
404 }
405
406 /*********************************************************************
407  *      _localtime64 (MSVCRT.@)
408  */
409 struct MSVCRT_tm* CDECL MSVCRT__localtime64(const MSVCRT___time64_t* secs)
410 {
411     thread_data_t *data = msvcrt_get_thread_data();
412
413     if(!data->time_buffer)
414         data->time_buffer = MSVCRT_malloc(sizeof(struct MSVCRT_tm));
415
416     if(_localtime64_s(data->time_buffer, secs))
417         return NULL;
418     return data->time_buffer;
419 }
420
421 /*********************************************************************
422  *      _localtime32 (MSVCRT.@)
423  */
424 struct MSVCRT_tm* CDECL MSVCRT__localtime32(const MSVCRT___time32_t* secs)
425 {
426     MSVCRT___time64_t secs64;
427
428     if(!secs)
429         return NULL;
430
431     secs64 = *secs;
432     return MSVCRT__localtime64( &secs64 );
433 }
434
435 /*********************************************************************
436  *      _localtime32_s (MSVCRT.@)
437  */
438 int CDECL _localtime32_s(struct MSVCRT_tm *time, const MSVCRT___time32_t *secs)
439 {
440     MSVCRT___time64_t secs64;
441
442     if (!time || !secs || *secs < 0)
443     {
444         if (time)
445             write_invalid_msvcrt_tm(time);
446
447         *MSVCRT__errno() = MSVCRT_EINVAL;
448         return MSVCRT_EINVAL;
449     }
450
451     secs64 = *secs;
452     return _localtime64_s(time, &secs64);
453 }
454
455 /*********************************************************************
456  *      localtime (MSVCRT.@)
457  */
458 #ifdef _WIN64
459 struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time64_t* secs)
460 {
461     return MSVCRT__localtime64( secs );
462 }
463 #else
464 struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time32_t* secs)
465 {
466     return MSVCRT__localtime32( secs );
467 }
468 #endif
469
470 /*********************************************************************
471  *      _gmtime64 (MSVCRT.@)
472  */
473 int CDECL MSVCRT__gmtime64_s(struct MSVCRT_tm *res, const MSVCRT___time64_t *secs)
474 {
475     int i;
476     FILETIME ft;
477     SYSTEMTIME st;
478     ULONGLONG time;
479
480     if (!res || !secs || *secs < 0 || *secs > _MAX__TIME64_T) {
481         if (res) {
482             write_invalid_msvcrt_tm(res);
483         }
484
485         *MSVCRT__errno() = MSVCRT_EINVAL;
486         return MSVCRT_EINVAL;
487     }
488
489     time = *secs * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
490
491     ft.dwHighDateTime = (UINT)(time >> 32);
492     ft.dwLowDateTime  = (UINT)time;
493
494     FileTimeToSystemTime(&ft, &st);
495
496     res->tm_sec  = st.wSecond;
497     res->tm_min  = st.wMinute;
498     res->tm_hour = st.wHour;
499     res->tm_mday = st.wDay;
500     res->tm_year = st.wYear - 1900;
501     res->tm_mon  = st.wMonth - 1;
502     res->tm_wday = st.wDayOfWeek;
503     for (i = res->tm_yday = 0; i < st.wMonth - 1; i++) {
504         res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
505     }
506
507     res->tm_yday += st.wDay - 1;
508     res->tm_isdst = 0;
509
510     return 0;
511 }
512
513 /*********************************************************************
514  *      _gmtime64 (MSVCRT.@)
515  */
516 struct MSVCRT_tm* CDECL MSVCRT__gmtime64(const MSVCRT___time64_t *secs)
517 {
518     thread_data_t * const data = msvcrt_get_thread_data();
519
520     if(!data->time_buffer)
521         data->time_buffer = MSVCRT_malloc(sizeof(struct MSVCRT_tm));
522
523     if(MSVCRT__gmtime64_s(data->time_buffer, secs))
524         return NULL;
525     return data->time_buffer;
526 }
527
528 /*********************************************************************
529  *      _gmtime32_s (MSVCRT.@)
530  */
531 int CDECL MSVCRT__gmtime32_s(struct MSVCRT_tm *res, const MSVCRT___time32_t *secs)
532 {
533     MSVCRT___time64_t secs64;
534
535     if(secs) {
536         secs64 = *secs;
537         return MSVCRT__gmtime64_s(res, &secs64);
538     }
539     return MSVCRT__gmtime64_s(res, NULL);
540 }
541
542 /*********************************************************************
543  *      _gmtime32 (MSVCRT.@)
544  */
545 struct MSVCRT_tm* CDECL MSVCRT__gmtime32(const MSVCRT___time32_t* secs)
546 {
547     MSVCRT___time64_t secs64;
548
549     if(!secs)
550         return NULL;
551
552     secs64 = *secs;
553     return MSVCRT__gmtime64( &secs64 );
554 }
555
556 /*********************************************************************
557  *      gmtime (MSVCRT.@)
558  */
559 #ifdef _WIN64
560 struct MSVCRT_tm* CDECL MSVCRT_gmtime(const MSVCRT___time64_t* secs)
561 {
562     return MSVCRT__gmtime64( secs );
563 }
564 #else
565 struct MSVCRT_tm* CDECL MSVCRT_gmtime(const MSVCRT___time32_t* secs)
566 {
567     return MSVCRT__gmtime32( secs );
568 }
569 #endif
570
571 /**********************************************************************
572  *              _strdate (MSVCRT.@)
573  */
574 char* CDECL MSVCRT__strdate(char* date)
575 {
576   static const char format[] = "MM'/'dd'/'yy";
577
578   GetDateFormatA(LOCALE_NEUTRAL, 0, NULL, format, date, 9);
579
580   return date;
581 }
582
583 /**********************************************************************
584  *              _strdate_s (MSVCRT.@)
585  */
586 int CDECL _strdate_s(char* date, MSVCRT_size_t size)
587 {
588     if(date && size)
589         date[0] = '\0';
590
591     if(!date) {
592         *MSVCRT__errno() = MSVCRT_EINVAL;
593         return MSVCRT_EINVAL;
594     }
595
596     if(size < 9) {
597         *MSVCRT__errno() = MSVCRT_ERANGE;
598         return MSVCRT_ERANGE;
599     }
600
601     MSVCRT__strdate(date);
602     return 0;
603 }
604
605 /**********************************************************************
606  *              _wstrdate (MSVCRT.@)
607  */
608 MSVCRT_wchar_t* CDECL MSVCRT__wstrdate(MSVCRT_wchar_t* date)
609 {
610   static const WCHAR format[] = { 'M','M','\'','/','\'','d','d','\'','/','\'','y','y',0 };
611
612   GetDateFormatW(LOCALE_NEUTRAL, 0, NULL, format, date, 9);
613
614   return date;
615 }
616
617 /**********************************************************************
618  *              _wstrdate_s (MSVCRT.@)
619  */
620 int CDECL _wstrdate_s(MSVCRT_wchar_t* date, MSVCRT_size_t size)
621 {
622     if(date && size)
623         date[0] = '\0';
624
625     if(!date) {
626         *MSVCRT__errno() = MSVCRT_EINVAL;
627         return MSVCRT_EINVAL;
628     }
629
630     if(size < 9) {
631         *MSVCRT__errno() = MSVCRT_ERANGE;
632         return MSVCRT_ERANGE;
633     }
634
635     MSVCRT__wstrdate(date);
636     return 0;
637 }
638
639 /*********************************************************************
640  *              _strtime (MSVCRT.@)
641  */
642 char* CDECL MSVCRT__strtime(char* time)
643 {
644   static const char format[] = "HH':'mm':'ss";
645
646   GetTimeFormatA(LOCALE_NEUTRAL, 0, NULL, format, time, 9); 
647
648   return time;
649 }
650
651 /*********************************************************************
652  *              _strtime_s (MSVCRT.@)
653  */
654 int CDECL _strtime_s(char* time, MSVCRT_size_t size)
655 {
656     if(time && size)
657         time[0] = '\0';
658
659     if(!time) {
660         *MSVCRT__errno() = MSVCRT_EINVAL;
661         return MSVCRT_EINVAL;
662     }
663
664     if(size < 9) {
665         *MSVCRT__errno() = MSVCRT_ERANGE;
666         return MSVCRT_ERANGE;
667     }
668
669     MSVCRT__strtime(time);
670     return 0;
671 }
672
673 /*********************************************************************
674  *              _wstrtime (MSVCRT.@)
675  */
676 MSVCRT_wchar_t* CDECL MSVCRT__wstrtime(MSVCRT_wchar_t* time)
677 {
678   static const WCHAR format[] = { 'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0 };
679
680   GetTimeFormatW(LOCALE_NEUTRAL, 0, NULL, format, time, 9);
681
682   return time;
683 }
684
685 /*********************************************************************
686  *              _wstrtime_s (MSVCRT.@)
687  */
688 int CDECL _wstrtime_s(MSVCRT_wchar_t* time, MSVCRT_size_t size)
689 {
690     if(time && size)
691         time[0] = '\0';
692
693     if(!time) {
694         *MSVCRT__errno() = MSVCRT_EINVAL;
695         return MSVCRT_EINVAL;
696     }
697
698     if(size < 9) {
699         *MSVCRT__errno() = MSVCRT_ERANGE;
700         return MSVCRT_ERANGE;
701     }
702
703     MSVCRT__wstrtime(time);
704     return 0;
705 }
706
707 /*********************************************************************
708  *              clock (MSVCRT.@)
709  */
710 MSVCRT_clock_t CDECL MSVCRT_clock(void)
711 {
712   FILETIME ftc, fte, ftk, ftu;
713   ULONGLONG utime, ktime;
714  
715   MSVCRT_clock_t clock;
716
717   GetProcessTimes(GetCurrentProcess(), &ftc, &fte, &ftk, &ftu);
718
719   ktime = ((ULONGLONG)ftk.dwHighDateTime << 32) | ftk.dwLowDateTime;
720   utime = ((ULONGLONG)ftu.dwHighDateTime << 32) | ftu.dwLowDateTime;
721
722   clock = (utime + ktime) / (TICKSPERSEC / MSVCRT_CLOCKS_PER_SEC);
723
724   return clock;
725 }
726
727 /*********************************************************************
728  *              _difftime64 (MSVCRT.@)
729  */
730 double CDECL MSVCRT__difftime64(MSVCRT___time64_t time1, MSVCRT___time64_t time2)
731 {
732   return (double)(time1 - time2);
733 }
734
735 /*********************************************************************
736  *              _difftime32 (MSVCRT.@)
737  */
738 double CDECL MSVCRT__difftime32(MSVCRT___time32_t time1, MSVCRT___time32_t time2)
739 {
740   return (double)(time1 - time2);
741 }
742
743 /*********************************************************************
744  *              difftime (MSVCRT.@)
745  */
746 #ifdef _WIN64
747 double CDECL MSVCRT_difftime(MSVCRT___time64_t time1, MSVCRT___time64_t time2)
748 {
749     return MSVCRT__difftime64( time1, time2 );
750 }
751 #else
752 double CDECL MSVCRT_difftime(MSVCRT___time32_t time1, MSVCRT___time32_t time2)
753 {
754     return MSVCRT__difftime32( time1, time2 );
755 }
756 #endif
757
758 /*********************************************************************
759  *              _ftime64 (MSVCRT.@)
760  */
761 void CDECL MSVCRT__ftime64(struct MSVCRT___timeb64 *buf)
762 {
763   TIME_ZONE_INFORMATION tzinfo;
764   FILETIME ft;
765   ULONGLONG time;
766
767   DWORD tzid = GetTimeZoneInformation(&tzinfo);
768   GetSystemTimeAsFileTime(&ft);
769
770   time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
771
772   buf->time = time / TICKSPERSEC - SECS_1601_TO_1970;
773   buf->millitm = (time % TICKSPERSEC) / TICKSPERMSEC;
774   buf->timezone = tzinfo.Bias +
775       ( tzid == TIME_ZONE_ID_STANDARD ? tzinfo.StandardBias :
776       ( tzid == TIME_ZONE_ID_DAYLIGHT ? tzinfo.DaylightBias : 0 ));
777   buf->dstflag = (tzid == TIME_ZONE_ID_DAYLIGHT?1:0);
778 }
779
780 /*********************************************************************
781  *              _ftime64_s (MSVCRT.@)
782  */
783 int CDECL MSVCRT__ftime64_s(struct MSVCRT___timeb64 *buf)
784 {
785     if (!MSVCRT_CHECK_PMT( buf != NULL )) return MSVCRT_EINVAL;
786     MSVCRT__ftime64(buf);
787     return 0;
788 }
789
790 /*********************************************************************
791  *              _ftime32 (MSVCRT.@)
792  */
793 void CDECL MSVCRT__ftime32(struct MSVCRT___timeb32 *buf)
794 {
795     struct MSVCRT___timeb64 buf64;
796
797     MSVCRT__ftime64( &buf64 );
798     buf->time     = buf64.time;
799     buf->millitm  = buf64.millitm;
800     buf->timezone = buf64.timezone;
801     buf->dstflag  = buf64.dstflag;
802 }
803
804 /*********************************************************************
805  *              _ftime32_s (MSVCRT.@)
806  */
807 int CDECL MSVCRT__ftime32_s(struct MSVCRT___timeb32 *buf)
808 {
809     if (!MSVCRT_CHECK_PMT( buf != NULL )) return MSVCRT_EINVAL;
810     MSVCRT__ftime32(buf);
811     return 0;
812 }
813
814 /*********************************************************************
815  *              _ftime (MSVCRT.@)
816  */
817 #ifdef _WIN64
818 void CDECL MSVCRT__ftime(struct MSVCRT___timeb64 *buf)
819 {
820     MSVCRT__ftime64( buf );
821 }
822 #else
823 void CDECL MSVCRT__ftime(struct MSVCRT___timeb32 *buf)
824 {
825     MSVCRT__ftime32( buf );
826 }
827 #endif
828
829 /*********************************************************************
830  *              _time64 (MSVCRT.@)
831  */
832 MSVCRT___time64_t CDECL MSVCRT__time64(MSVCRT___time64_t *buf)
833 {
834     MSVCRT___time64_t curtime;
835     struct MSVCRT___timeb64 tb;
836
837     MSVCRT__ftime64(&tb);
838
839     curtime = tb.time;
840     return buf ? *buf = curtime : curtime;
841 }
842
843 /*********************************************************************
844  *              _time32 (MSVCRT.@)
845  */
846 MSVCRT___time32_t CDECL MSVCRT__time32(MSVCRT___time32_t *buf)
847 {
848     MSVCRT___time32_t curtime;
849     struct MSVCRT___timeb64 tb;
850
851     MSVCRT__ftime64(&tb);
852
853     curtime = tb.time;
854     return buf ? *buf = curtime : curtime;
855 }
856
857 /*********************************************************************
858  *              time (MSVCRT.@)
859  */
860 #ifdef _WIN64
861 MSVCRT___time64_t CDECL MSVCRT_time(MSVCRT___time64_t* buf)
862 {
863     return MSVCRT__time64( buf );
864 }
865 #else
866 MSVCRT___time32_t CDECL MSVCRT_time(MSVCRT___time32_t* buf)
867 {
868     return MSVCRT__time32( buf );
869 }
870 #endif
871
872 /*********************************************************************
873  *              __p_daylight (MSVCRT.@)
874  */
875 int * CDECL MSVCRT___p__daylight(void)
876 {
877         return &MSVCRT___daylight;
878 }
879
880 /*********************************************************************
881  *              __p_dstbias (MSVCRT.@)
882  */
883 int * CDECL __p__dstbias(void)
884 {
885     return &MSVCRT__dstbias;
886 }
887
888 /*********************************************************************
889  *              __p_timezone (MSVCRT.@)
890  */
891 MSVCRT_long * CDECL MSVCRT___p__timezone(void)
892 {
893         return &MSVCRT___timezone;
894 }
895
896 /*********************************************************************
897  *              _get_tzname (MSVCRT.@)
898  */
899 int CDECL MSVCRT__get_tzname(MSVCRT_size_t *ret, char *buf, MSVCRT_size_t bufsize, int index)
900 {
901     char *timezone;
902
903     switch(index)
904     {
905     case 0:
906         timezone = tzname_std;
907         break;
908     case 1:
909         timezone = tzname_dst;
910         break;
911     default:
912         *MSVCRT__errno() = MSVCRT_EINVAL;
913         return MSVCRT_EINVAL;
914     }
915
916     if(!ret || (!buf && bufsize > 0) || (buf && !bufsize))
917     {
918         *MSVCRT__errno() = MSVCRT_EINVAL;
919         return MSVCRT_EINVAL;
920     }
921
922     *ret = strlen(timezone)+1;
923     if(!buf && !bufsize)
924         return 0;
925
926     strcpy(buf, timezone);
927     return 0;
928 }
929
930 /*********************************************************************
931  *              __p_tzname (MSVCRT.@)
932  */
933 char ** CDECL __p__tzname(void)
934 {
935         return MSVCRT__tzname;
936 }
937
938 static inline BOOL strftime_date(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max,
939         BOOL alternate, const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data)
940 {
941     char *format;
942     SYSTEMTIME st;
943     MSVCRT_size_t ret;
944
945     st.wYear = mstm->tm_year + 1900;
946     st.wMonth = mstm->tm_mon + 1;
947     st.wDayOfWeek = mstm->tm_wday;
948     st.wDay = mstm->tm_mday;
949     st.wHour = mstm->tm_hour;
950     st.wMinute = mstm->tm_min;
951     st.wSecond = mstm->tm_sec;
952     st.wMilliseconds = 0;
953
954     format = alternate ? time_data->str.names.date : time_data->str.names.short_date;
955     ret = GetDateFormatA(time_data->lcid, 0, &st, format, NULL, 0);
956     if(ret && ret<max-*pos)
957         ret = GetDateFormatA(time_data->lcid, 0, &st, format, str+*pos, max-*pos);
958     if(!ret) {
959         *str = 0;
960         *MSVCRT__errno() = MSVCRT_EINVAL;
961         return FALSE;
962     }else if(ret > max-*pos) {
963         *str = 0;
964         *MSVCRT__errno() = MSVCRT_ERANGE;
965         return FALSE;
966     }
967     *pos += ret-1;
968     return TRUE;
969 }
970
971 static inline BOOL strftime_time(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max,
972         const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data)
973 {
974     SYSTEMTIME st;
975     MSVCRT_size_t ret;
976
977     st.wYear = mstm->tm_year + 1900;
978     st.wMonth = mstm->tm_mon + 1;
979     st.wDayOfWeek = mstm->tm_wday;
980     st.wDay = mstm->tm_mday;
981     st.wHour = mstm->tm_hour;
982     st.wMinute = mstm->tm_min;
983     st.wSecond = mstm->tm_sec;
984     st.wMilliseconds = 0;
985
986     ret = GetTimeFormatA(time_data->lcid, 0, &st, time_data->str.names.time, NULL, 0);
987     if(ret && ret<max-*pos)
988         ret = GetTimeFormatA(time_data->lcid, 0, &st, time_data->str.names.time,
989                 str+*pos, max-*pos);
990     if(!ret) {
991         *str = 0;
992         *MSVCRT__errno() = MSVCRT_EINVAL;
993         return FALSE;
994     }else if(ret > max-*pos) {
995         *str = 0;
996         *MSVCRT__errno() = MSVCRT_ERANGE;
997         return FALSE;
998     }
999     *pos += ret-1;
1000     return TRUE;
1001 }
1002
1003 static inline BOOL strftime_str(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max, char *src)
1004 {
1005     MSVCRT_size_t len = strlen(src);
1006     if(len > max-*pos) {
1007         *str = 0;
1008         *MSVCRT__errno() = MSVCRT_ERANGE;
1009         return FALSE;
1010     }
1011
1012     memcpy(str+*pos, src, len);
1013     *pos += len;
1014     return TRUE;
1015 }
1016
1017 static inline BOOL strftime_int(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max,
1018         int src, int prec, int l, int h)
1019 {
1020     MSVCRT_size_t len;
1021
1022     if(src<l || src>h) {
1023         *str = 0;
1024         *MSVCRT__errno() = MSVCRT_EINVAL;
1025         return FALSE;
1026     }
1027
1028     len = MSVCRT__snprintf(str+*pos, max-*pos, "%0*d", prec, src);
1029     if(len == -1) {
1030         *str = 0;
1031         *MSVCRT__errno() = MSVCRT_ERANGE;
1032         return FALSE;
1033     }
1034
1035     *pos += len;
1036     return TRUE;
1037 }
1038
1039 /*********************************************************************
1040  *              _Strftime (MSVCRT.@)
1041  */
1042 MSVCRT_size_t CDECL _Strftime(char *str, MSVCRT_size_t max, const char *format,
1043         const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data)
1044 {
1045     MSVCRT_size_t ret, tmp;
1046     BOOL alternate;
1047
1048     TRACE("(%p %ld %s %p %p)\n", str, max, format, mstm, time_data);
1049
1050     if(!str || !format) {
1051         if(str && max)
1052             *str = 0;
1053         *MSVCRT__errno() = MSVCRT_EINVAL;
1054         return 0;
1055     }
1056
1057     if(!time_data)
1058         time_data = get_locinfo()->lc_time_curr;
1059
1060     for(ret=0; *format && ret<max; format++) {
1061         if(*format != '%') {
1062             str[ret++] = *format;
1063             continue;
1064         }
1065
1066         format++;
1067         if(*format == '#') {
1068             alternate = TRUE;
1069             format++;
1070         }else {
1071             alternate = FALSE;
1072         }
1073
1074         if(!mstm)
1075             goto einval_error;
1076
1077         switch(*format) {
1078         case 'c':
1079             if(!strftime_date(str, &ret, max, alternate, mstm, time_data))
1080                 return 0;
1081             if(ret < max)
1082                 str[ret++] = ' ';
1083             if(!strftime_time(str, &ret, max, mstm, time_data))
1084                 return 0;
1085             break;
1086         case 'x':
1087             if(!strftime_date(str, &ret, max, alternate, mstm, time_data))
1088                 return 0;
1089             break;
1090         case 'X':
1091             if(!strftime_time(str, &ret, max, mstm, time_data))
1092                 return 0;
1093             break;
1094         case 'a':
1095             if(mstm->tm_wday<0 || mstm->tm_wday>6)
1096                 goto einval_error;
1097             if(!strftime_str(str, &ret, max, time_data->str.names.short_wday[mstm->tm_wday]))
1098                 return 0;
1099             break;
1100         case 'A':
1101             if(mstm->tm_wday<0 || mstm->tm_wday>6)
1102                 goto einval_error;
1103             if(!strftime_str(str, &ret, max, time_data->str.names.wday[mstm->tm_wday]))
1104                 return 0;
1105             break;
1106         case 'b':
1107             if(mstm->tm_mon<0 || mstm->tm_mon>11)
1108                 goto einval_error;
1109             if(!strftime_str(str, &ret, max, time_data->str.names.short_mon[mstm->tm_mon]))
1110                 return 0;
1111             break;
1112         case 'B':
1113             if(mstm->tm_mon<0 || mstm->tm_mon>11)
1114                 goto einval_error;
1115             if(!strftime_str(str, &ret, max, time_data->str.names.mon[mstm->tm_mon]))
1116                 return 0;
1117             break;
1118         case 'd':
1119             if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 0, 31))
1120                 return 0;
1121             break;
1122         case 'H':
1123             if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
1124                 return 0;
1125             break;
1126         case 'I':
1127             tmp = mstm->tm_hour;
1128             if(tmp > 12)
1129                 tmp -= 12;
1130             else if(!tmp)
1131                 tmp = 12;
1132             if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 1, 12))
1133                 return 0;
1134             break;
1135         case 'j':
1136             if(!strftime_int(str, &ret, max, mstm->tm_yday+1, alternate ? 0 : 3, 1, 366))
1137                 return 0;
1138             break;
1139         case 'm':
1140             if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
1141                 return 0;
1142             break;
1143         case 'M':
1144             if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
1145                 return 0;
1146             break;
1147         case 'p':
1148             if(mstm->tm_hour<0 || mstm->tm_hour>23)
1149                 goto einval_error;
1150             if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ?
1151                         time_data->str.names.am : time_data->str.names.pm))
1152                 return 0;
1153             break;
1154         case 'S':
1155             if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, 59))
1156                 return 0;
1157             break;
1158         case 'w':
1159             if(!strftime_int(str, &ret, max, mstm->tm_wday, 0, 0, 6))
1160                 return 0;
1161             break;
1162         case 'y':
1163             if(!strftime_int(str, &ret, max, mstm->tm_year%100, alternate ? 0 : 2, 0, 99))
1164                 return 0;
1165             break;
1166         case 'Y':
1167             tmp = 1900+mstm->tm_year;
1168             if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 4, 0, 9999))
1169                 return 0;
1170             break;
1171         case 'z':
1172         case 'Z':
1173             MSVCRT__tzset();
1174             if(MSVCRT__get_tzname(&tmp, str+ret, max-ret, mstm->tm_isdst ? 1 : 0))
1175                 return 0;
1176             ret += tmp;
1177             break;
1178         case 'U':
1179         case 'W':
1180             if(mstm->tm_wday<0 || mstm->tm_wday>6 || mstm->tm_yday<0 || mstm->tm_yday>365)
1181                 goto einval_error;
1182             if(*format == 'U')
1183                 tmp = mstm->tm_wday;
1184             else if(!mstm->tm_wday)
1185                 tmp = 6;
1186             else
1187                 tmp = mstm->tm_wday-1;
1188
1189             tmp = mstm->tm_yday/7 + (tmp<=mstm->tm_yday%7);
1190             if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 0, 53))
1191                 return 0;
1192             break;
1193         case '%':
1194             str[ret++] = '%';
1195             break;
1196         default:
1197             WARN("unknown format %c\n", *format);
1198             goto einval_error;
1199         }
1200     }
1201
1202     if(ret == max) {
1203         if(max)
1204             *str = 0;
1205         *MSVCRT__errno() = MSVCRT_ERANGE;
1206         return 0;
1207     }
1208
1209     str[ret] = 0;
1210     return ret;
1211
1212 einval_error:
1213     *str = 0;
1214     *MSVCRT__errno() = MSVCRT_EINVAL;
1215     return 0;
1216 }
1217
1218 /*********************************************************************
1219  *              strftime (MSVCRT.@)
1220  */
1221 MSVCRT_size_t CDECL MSVCRT_strftime( char *str, MSVCRT_size_t max, const char *format,
1222                                      const struct MSVCRT_tm *mstm )
1223 {
1224     return _Strftime(str, max, format, mstm, NULL);
1225 }
1226
1227 /*********************************************************************
1228  *              wcsftime (MSVCRT.@)
1229  */
1230 MSVCRT_size_t CDECL MSVCRT_wcsftime( MSVCRT_wchar_t *str, MSVCRT_size_t max,
1231                                      const MSVCRT_wchar_t *format, const struct MSVCRT_tm *mstm )
1232 {
1233     char *s, *fmt;
1234     MSVCRT_size_t len;
1235
1236     TRACE("%p %ld %s %p\n", str, max, debugstr_w(format), mstm );
1237
1238     len = WideCharToMultiByte( CP_UNIXCP, 0, format, -1, NULL, 0, NULL, NULL );
1239     if (!(fmt = MSVCRT_malloc( len ))) return 0;
1240     WideCharToMultiByte( CP_UNIXCP, 0, format, -1, fmt, len, NULL, NULL );
1241
1242     if ((s = MSVCRT_malloc( max*4 )))
1243     {
1244         if (!MSVCRT_strftime( s, max*4, fmt, mstm )) s[0] = 0;
1245         len = MultiByteToWideChar( CP_UNIXCP, 0, s, -1, str, max );
1246         if (len) len--;
1247         MSVCRT_free( s );
1248     }
1249     else len = 0;
1250
1251     MSVCRT_free( fmt );
1252     return len;
1253 }
1254
1255 static char* asctime_buf(char *buf, const struct MSVCRT_tm *mstm)
1256 {
1257     static const char wday[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
1258     static const char month[12][4] = {"Jan", "Feb", "Mar", "Apr", "May",
1259         "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1260
1261     if (mstm->tm_sec<0 || mstm->tm_sec>59
1262             || mstm->tm_min<0 || mstm->tm_min>59
1263             || mstm->tm_hour<0 || mstm->tm_hour>23
1264             || mstm->tm_mon<0 || mstm->tm_mon>11
1265             || mstm->tm_wday<0 || mstm->tm_wday>6
1266             || mstm->tm_year<0 || mstm->tm_mday<0
1267             || mstm->tm_mday>MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon]) {
1268         *MSVCRT__errno() = MSVCRT_EINVAL;
1269         return NULL;
1270     }
1271
1272     MSVCRT__snprintf(buf, 26, "%s %s %02d %02d:%02d:%02d %c%03d\n", wday[mstm->tm_wday],
1273             month[mstm->tm_mon], mstm->tm_mday, mstm->tm_hour, mstm->tm_min,
1274             mstm->tm_sec, '1'+(mstm->tm_year+900)/1000, (900+mstm->tm_year)%1000);
1275     return buf;
1276 }
1277
1278 /*********************************************************************
1279  *              asctime (MSVCRT.@)
1280  */
1281 char * CDECL MSVCRT_asctime(const struct MSVCRT_tm *mstm)
1282 {
1283     thread_data_t *data = msvcrt_get_thread_data();
1284
1285     /* asctime returns date in format that always has exactly 26 characters */
1286     if (!data->asctime_buffer) {
1287         data->asctime_buffer = MSVCRT_malloc(26);
1288         if (!data->asctime_buffer) {
1289             *MSVCRT__errno() = MSVCRT_ENOMEM;
1290             return NULL;
1291         }
1292     }
1293
1294     return asctime_buf(data->asctime_buffer, mstm);
1295 }
1296
1297 /*********************************************************************
1298  *      asctime_s (MSVCRT.@)
1299  */
1300 int CDECL MSVCRT_asctime_s(char* time, MSVCRT_size_t size, const struct MSVCRT_tm *mstm)
1301 {
1302     if (!MSVCRT_CHECK_PMT(time != NULL)) return MSVCRT_EINVAL;
1303     if (size) time[0] = 0;
1304     if (!MSVCRT_CHECK_PMT(size >= 26)) return MSVCRT_EINVAL;
1305     if (!MSVCRT_CHECK_PMT(mstm != NULL)) return MSVCRT_EINVAL;
1306     if (!MSVCRT_CHECK_PMT(mstm->tm_sec >= 0 && mstm->tm_sec < 60)) return MSVCRT_EINVAL;
1307     if (!MSVCRT_CHECK_PMT(mstm->tm_min >= 0 && mstm->tm_min < 60)) return MSVCRT_EINVAL;
1308     if (!MSVCRT_CHECK_PMT(mstm->tm_hour >= 0 && mstm->tm_hour < 24)) return MSVCRT_EINVAL;
1309     if (!MSVCRT_CHECK_PMT(mstm->tm_mon >= 0 && mstm->tm_mon < 12)) return MSVCRT_EINVAL;
1310     if (!MSVCRT_CHECK_PMT(mstm->tm_wday >= 0 && mstm->tm_wday < 7)) return MSVCRT_EINVAL;
1311     if (!MSVCRT_CHECK_PMT(mstm->tm_year >= 0)) return MSVCRT_EINVAL;
1312     if (!MSVCRT_CHECK_PMT(mstm->tm_mday >= 0)) return MSVCRT_EINVAL;
1313     if (!MSVCRT_CHECK_PMT(mstm->tm_mday <= MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon])) return MSVCRT_EINVAL;
1314
1315     asctime_buf(time, mstm);
1316     return 0;
1317 }
1318
1319 /*********************************************************************
1320  *              _wasctime (MSVCRT.@)
1321  */
1322 MSVCRT_wchar_t * CDECL MSVCRT__wasctime(const struct MSVCRT_tm *mstm)
1323 {
1324     thread_data_t *data = msvcrt_get_thread_data();
1325     char buffer[26];
1326
1327     if(!data->wasctime_buffer) {
1328         data->wasctime_buffer = MSVCRT_malloc(26*sizeof(MSVCRT_wchar_t));
1329         if(!data->wasctime_buffer) {
1330             *MSVCRT__errno() = MSVCRT_ENOMEM;
1331             return NULL;
1332         }
1333     }
1334
1335     if(!asctime_buf(buffer, mstm))
1336         return NULL;
1337
1338     MultiByteToWideChar(CP_ACP, 0, buffer, -1, data->wasctime_buffer, 26);
1339     return data->wasctime_buffer;
1340 }
1341
1342 /*********************************************************************
1343  *      _wasctime_s (MSVCRT.@)
1344  */
1345 int CDECL MSVCRT__wasctime_s(MSVCRT_wchar_t* time, MSVCRT_size_t size, const struct MSVCRT_tm *mstm)
1346 {
1347     char buffer[26];
1348     int ret;
1349
1350     if (!MSVCRT_CHECK_PMT(time != NULL)) return MSVCRT_EINVAL;
1351     if (size) time[0] = 0;
1352     if (!MSVCRT_CHECK_PMT(size >= 26)) return MSVCRT_EINVAL;
1353     if (!MSVCRT_CHECK_PMT(mstm != NULL)) return MSVCRT_EINVAL;
1354
1355     ret = MSVCRT_asctime_s(buffer, sizeof(buffer), mstm);
1356     if(!ret)
1357         return ret;
1358     MultiByteToWideChar(CP_ACP, 0, buffer, -1, time, size);
1359     return 0;
1360 }
1361
1362 /*********************************************************************
1363  *              _ctime64 (MSVCRT.@)
1364  */
1365 char * CDECL MSVCRT__ctime64(const MSVCRT___time64_t *time)
1366 {
1367     struct MSVCRT_tm *t;
1368     t = MSVCRT__localtime64( time );
1369     if (!t) return NULL;
1370     return MSVCRT_asctime( t );
1371 }
1372
1373 /*********************************************************************
1374  *              _ctime64_s (MSVCRT.@)
1375  */
1376 int CDECL MSVCRT__ctime64_s(char *res, MSVCRT_size_t len, const MSVCRT___time64_t *time)
1377 {
1378     struct MSVCRT_tm *t;
1379
1380     if (!MSVCRT_CHECK_PMT( res != NULL )) return MSVCRT_EINVAL;
1381     if (!MSVCRT_CHECK_PMT( len >= 26 )) return MSVCRT_EINVAL;
1382     res[0] = '\0';
1383     if (!MSVCRT_CHECK_PMT( time != NULL )) return MSVCRT_EINVAL;
1384     if (!MSVCRT_CHECK_PMT( *time > 0 )) return MSVCRT_EINVAL;
1385
1386     t = MSVCRT__localtime64( time );
1387     strcpy( res, MSVCRT_asctime( t ) );
1388     return 0;
1389 }
1390
1391 /*********************************************************************
1392  *              _ctime32 (MSVCRT.@)
1393  */
1394 char * CDECL MSVCRT__ctime32(const MSVCRT___time32_t *time)
1395 {
1396     struct MSVCRT_tm *t;
1397     t = MSVCRT__localtime32( time );
1398     if (!t) return NULL;
1399     return MSVCRT_asctime( t );
1400 }
1401
1402 /*********************************************************************
1403  *              _ctime32_s (MSVCRT.@)
1404  */
1405 int CDECL MSVCRT__ctime32_s(char *res, MSVCRT_size_t len, const MSVCRT___time32_t *time)
1406 {
1407     struct MSVCRT_tm *t;
1408
1409     if (!MSVCRT_CHECK_PMT( res != NULL )) return MSVCRT_EINVAL;
1410     if (!MSVCRT_CHECK_PMT( len >= 26 )) return MSVCRT_EINVAL;
1411     res[0] = '\0';
1412     if (!MSVCRT_CHECK_PMT( time != NULL )) return MSVCRT_EINVAL;
1413     if (!MSVCRT_CHECK_PMT( *time > 0 )) return MSVCRT_EINVAL;
1414
1415     t = MSVCRT__localtime32( time );
1416     strcpy( res, MSVCRT_asctime( t ) );
1417     return 0;
1418 }
1419
1420 /*********************************************************************
1421  *              ctime (MSVCRT.@)
1422  */
1423 #ifdef _WIN64
1424 char * CDECL MSVCRT_ctime(const MSVCRT___time64_t *time)
1425 {
1426     return MSVCRT__ctime64( time );
1427 }
1428 #else
1429 char * CDECL MSVCRT_ctime(const MSVCRT___time32_t *time)
1430 {
1431     return MSVCRT__ctime32( time );
1432 }
1433 #endif
1434
1435 /*********************************************************************
1436  *              _wctime64 (MSVCRT.@)
1437  */
1438 MSVCRT_wchar_t * CDECL MSVCRT__wctime64(const MSVCRT___time64_t *time)
1439 {
1440     return MSVCRT__wasctime( MSVCRT__localtime64(time) );
1441 }
1442
1443 /*********************************************************************
1444  *              _wctime32 (MSVCRT.@)
1445  */
1446 MSVCRT_wchar_t * CDECL MSVCRT__wctime32(const MSVCRT___time32_t *time)
1447 {
1448     return MSVCRT__wasctime( MSVCRT__localtime32(time) );
1449 }
1450
1451 /*********************************************************************
1452  *              _wctime (MSVCRT.@)
1453  */
1454 #ifdef _WIN64
1455 MSVCRT_wchar_t * CDECL MSVCRT__wctime(const MSVCRT___time64_t *time)
1456 {
1457     return MSVCRT__wctime64( time );
1458 }
1459 #else
1460 MSVCRT_wchar_t * CDECL MSVCRT__wctime(const MSVCRT___time32_t *time)
1461 {
1462     return MSVCRT__wctime32( time );
1463 }
1464 #endif