d3d8: Merge vertex and index buffer implementations into a single file.
[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 #define _POSIX_PTHREAD_SEMANTICS /* switch to a 2 arg style asctime_r on Solaris */
28 #include <time.h>
29 #ifdef HAVE_SYS_TIMES_H
30 # include <sys/times.h>
31 #endif
32 #include <limits.h>
33
34 #include "msvcrt.h"
35 #include "mtdll.h"
36 #include "winbase.h"
37 #include "winnls.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
41
42 static const int MonthLengths[2][12] =
43 {
44     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
45     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
46 };
47
48 static inline int IsLeapYear(int Year)
49 {
50     return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
51 }
52
53 static inline void msvcrt_tm_to_unix( struct tm *dest, const struct MSVCRT_tm *src )
54 {
55     memset( dest, 0, sizeof(*dest) );
56     dest->tm_sec   = src->tm_sec;
57     dest->tm_min   = src->tm_min;
58     dest->tm_hour  = src->tm_hour;
59     dest->tm_mday  = src->tm_mday;
60     dest->tm_mon   = src->tm_mon;
61     dest->tm_year  = src->tm_year;
62     dest->tm_wday  = src->tm_wday;
63     dest->tm_yday  = src->tm_yday;
64     dest->tm_isdst = src->tm_isdst;
65 }
66
67 static inline void unix_tm_to_msvcrt( struct MSVCRT_tm *dest, const struct tm *src )
68 {
69     memset( dest, 0, sizeof(*dest) );
70     dest->tm_sec   = src->tm_sec;
71     dest->tm_min   = src->tm_min;
72     dest->tm_hour  = src->tm_hour;
73     dest->tm_mday  = src->tm_mday;
74     dest->tm_mon   = src->tm_mon;
75     dest->tm_year  = src->tm_year;
76     dest->tm_wday  = src->tm_wday;
77     dest->tm_yday  = src->tm_yday;
78     dest->tm_isdst = src->tm_isdst;
79 }
80
81 #define SECSPERDAY        86400
82 /* 1601 to 1970 is 369 years plus 89 leap days */
83 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
84 #define TICKSPERSEC       10000000
85 #define TICKSPERMSEC      10000
86 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
87
88 /**********************************************************************
89  *              _mktime64 (MSVCRT.@)
90  */
91 MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
92 {
93     time_t secs;
94     struct tm tm;
95
96     msvcrt_tm_to_unix( &tm, mstm );
97     secs = mktime( &tm );
98     unix_tm_to_msvcrt( mstm, &tm );
99
100     return secs < 0 ? -1 : secs;
101 }
102
103 /**********************************************************************
104  *              _mktime32 (MSVCRT.@)
105  */
106 MSVCRT___time32_t CDECL MSVCRT__mktime32(struct MSVCRT_tm *mstm)
107 {
108     return MSVCRT__mktime64( mstm );
109 }
110
111 /**********************************************************************
112  *              mktime (MSVCRT.@)
113  */
114 #ifdef _WIN64
115 MSVCRT___time64_t CDECL MSVCRT_mktime(struct MSVCRT_tm *mstm)
116 {
117     return MSVCRT__mktime64( mstm );
118 }
119 #else
120 MSVCRT___time32_t CDECL MSVCRT_mktime(struct MSVCRT_tm *mstm)
121 {
122     return MSVCRT__mktime32( mstm );
123 }
124 #endif
125
126 /**********************************************************************
127  *              _mkgmtime64 (MSVCRT.@)
128  *
129  * time->tm_isdst value is ignored
130  */
131 MSVCRT___time64_t CDECL MSVCRT__mkgmtime64(struct MSVCRT_tm *time)
132 {
133     SYSTEMTIME st;
134     FILETIME ft;
135     MSVCRT___time64_t ret;
136     int i;
137
138     st.wMilliseconds = 0;
139     st.wSecond = time->tm_sec;
140     st.wMinute = time->tm_min;
141     st.wHour = time->tm_hour;
142     st.wDay = time->tm_mday;
143     st.wMonth = time->tm_mon+1;
144     st.wYear = time->tm_year+1900;
145
146     if(!SystemTimeToFileTime(&st, &ft))
147         return -1;
148
149     FileTimeToSystemTime(&ft, &st);
150     time->tm_wday = st.wDayOfWeek;
151
152     for(i=time->tm_yday=0; i<st.wMonth-1; i++)
153         time->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
154     time->tm_yday += st.wDay-1;
155
156     ret = ((MSVCRT___time64_t)ft.dwHighDateTime<<32)+ft.dwLowDateTime;
157     ret = (ret-TICKS_1601_TO_1970)/TICKSPERSEC;
158     return ret;
159 }
160
161 /**********************************************************************
162  *              _mkgmtime32 (MSVCRT.@)
163  */
164 MSVCRT___time32_t CDECL MSVCRT__mkgmtime32(struct MSVCRT_tm *time)
165 {
166     return MSVCRT__mkgmtime64(time);
167 }
168
169 /**********************************************************************
170  *              _mkgmtime (MSVCRT.@)
171  */
172 #ifdef _WIN64
173 MSVCRT___time64_t CDECL MSVCRT__mkgmtime(struct MSVCRT_tm *time)
174 {
175     return MSVCRT__mkgmtime64(time);
176 }
177 #else
178 MSVCRT___time32_t CDECL MSVCRT__mkgmtime(struct MSVCRT_tm *time)
179 {
180     return MSVCRT__mkgmtime32(time);
181 }
182 #endif
183
184 /*********************************************************************
185  *      _localtime64 (MSVCRT.@)
186  */
187 struct MSVCRT_tm* CDECL MSVCRT__localtime64(const MSVCRT___time64_t* secs)
188 {
189     struct tm *tm;
190     thread_data_t *data;
191     time_t seconds = *secs;
192
193     if (seconds < 0) return NULL;
194
195     _mlock(_TIME_LOCK);
196     if (!(tm = localtime( &seconds))) {
197         _munlock(_TIME_LOCK);
198         return NULL;
199     }
200
201     data = msvcrt_get_thread_data();
202     unix_tm_to_msvcrt( &data->time_buffer, tm );
203     _munlock(_TIME_LOCK);
204
205     return &data->time_buffer;
206 }
207
208 /*********************************************************************
209  *      _localtime32 (MSVCRT.@)
210  */
211 struct MSVCRT_tm* CDECL MSVCRT__localtime32(const MSVCRT___time32_t* secs)
212 {
213     MSVCRT___time64_t secs64 = *secs;
214     return MSVCRT__localtime64( &secs64 );
215 }
216
217 /*********************************************************************
218  *      localtime (MSVCRT.@)
219  */
220 #ifdef _WIN64
221 struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time64_t* secs)
222 {
223     return MSVCRT__localtime64( secs );
224 }
225 #else
226 struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time32_t* secs)
227 {
228     return MSVCRT__localtime32( secs );
229 }
230 #endif
231
232 /*********************************************************************
233  *      _gmtime64 (MSVCRT.@)
234  */
235 int CDECL MSVCRT__gmtime64_s(struct MSVCRT_tm *res, const MSVCRT___time64_t *secs)
236 {
237     int i;
238     FILETIME ft;
239     SYSTEMTIME st;
240     ULONGLONG time;
241
242     if(!res || !secs || *secs<0) {
243         if(res) {
244             res->tm_sec = -1;
245             res->tm_min = -1;
246             res->tm_hour = -1;
247             res->tm_mday = -1;
248             res->tm_year = -1;
249             res->tm_mon = -1;
250             res->tm_wday = -1;
251             res->tm_yday = -1;
252             res->tm_isdst = -1;
253         }
254
255         *MSVCRT__errno() = MSVCRT_EINVAL;
256         return MSVCRT_EINVAL;
257     }
258
259     time = *secs * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
260
261     ft.dwHighDateTime = (UINT)(time >> 32);
262     ft.dwLowDateTime  = (UINT)time;
263
264     FileTimeToSystemTime(&ft, &st);
265
266     res->tm_sec  = st.wSecond;
267     res->tm_min  = st.wMinute;
268     res->tm_hour = st.wHour;
269     res->tm_mday = st.wDay;
270     res->tm_year = st.wYear - 1900;
271     res->tm_mon  = st.wMonth - 1;
272     res->tm_wday = st.wDayOfWeek;
273     for (i = res->tm_yday = 0; i < st.wMonth - 1; i++) {
274         res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
275     }
276
277     res->tm_yday += st.wDay - 1;
278     res->tm_isdst = 0;
279
280     return 0;
281 }
282
283 /*********************************************************************
284  *      _gmtime64 (MSVCRT.@)
285  */
286 struct MSVCRT_tm* CDECL MSVCRT__gmtime64(const MSVCRT___time64_t *secs)
287 {
288     thread_data_t * const data = msvcrt_get_thread_data();
289
290     if(MSVCRT__gmtime64_s(&data->time_buffer, secs))
291         return NULL;
292     return &data->time_buffer;
293 }
294
295 /*********************************************************************
296  *      _gmtime32_s (MSVCRT.@)
297  */
298 int CDECL MSVCRT__gmtime32_s(struct MSVCRT_tm *res, const MSVCRT___time32_t *secs)
299 {
300     MSVCRT___time64_t secs64;
301
302     if(secs) {
303         secs64 = *secs;
304         return MSVCRT__gmtime64_s(res, &secs64);
305     }
306     return MSVCRT__gmtime64_s(res, NULL);
307 }
308
309 /*********************************************************************
310  *      _gmtime32 (MSVCRT.@)
311  */
312 struct MSVCRT_tm* CDECL MSVCRT__gmtime32(const MSVCRT___time32_t* secs)
313 {
314     MSVCRT___time64_t secs64;
315
316     if(!secs)
317         return NULL;
318
319     secs64 = *secs;
320     return MSVCRT__gmtime64( &secs64 );
321 }
322
323 /*********************************************************************
324  *      gmtime (MSVCRT.@)
325  */
326 #ifdef _WIN64
327 struct MSVCRT_tm* CDECL MSVCRT_gmtime(const MSVCRT___time64_t* secs)
328 {
329     return MSVCRT__gmtime64( secs );
330 }
331 #else
332 struct MSVCRT_tm* CDECL MSVCRT_gmtime(const MSVCRT___time32_t* secs)
333 {
334     return MSVCRT__gmtime32( secs );
335 }
336 #endif
337
338 /**********************************************************************
339  *              _strdate (MSVCRT.@)
340  */
341 char* CDECL _strdate(char* date)
342 {
343   static const char format[] = "MM'/'dd'/'yy";
344
345   GetDateFormatA(LOCALE_NEUTRAL, 0, NULL, format, date, 9);
346
347   return date;
348 }
349
350 /**********************************************************************
351  *              _strdate_s (MSVCRT.@)
352  */
353 int CDECL _strdate_s(char* date, MSVCRT_size_t size)
354 {
355     if(date && size)
356         date[0] = '\0';
357
358     if(!date) {
359         *MSVCRT__errno() = MSVCRT_EINVAL;
360         return MSVCRT_EINVAL;
361     }
362
363     if(size < 9) {
364         *MSVCRT__errno() = MSVCRT_ERANGE;
365         return MSVCRT_ERANGE;
366     }
367
368     _strdate(date);
369     return 0;
370 }
371
372 /**********************************************************************
373  *              _wstrdate (MSVCRT.@)
374  */
375 MSVCRT_wchar_t* CDECL _wstrdate(MSVCRT_wchar_t* date)
376 {
377   static const WCHAR format[] = { 'M','M','\'','/','\'','d','d','\'','/','\'','y','y',0 };
378
379   GetDateFormatW(LOCALE_NEUTRAL, 0, NULL, format, date, 9);
380
381   return date;
382 }
383
384 /**********************************************************************
385  *              _wstrdate_s (MSVCRT.@)
386  */
387 int CDECL _wstrdate_s(MSVCRT_wchar_t* date, MSVCRT_size_t size)
388 {
389     if(date && size)
390         date[0] = '\0';
391
392     if(!date) {
393         *MSVCRT__errno() = MSVCRT_EINVAL;
394         return MSVCRT_EINVAL;
395     }
396
397     if(size < 9) {
398         *MSVCRT__errno() = MSVCRT_ERANGE;
399         return MSVCRT_ERANGE;
400     }
401
402     _wstrdate(date);
403     return 0;
404 }
405
406 /*********************************************************************
407  *              _strtime (MSVCRT.@)
408  */
409 char* CDECL _strtime(char* time)
410 {
411   static const char format[] = "HH':'mm':'ss";
412
413   GetTimeFormatA(LOCALE_NEUTRAL, 0, NULL, format, time, 9); 
414
415   return time;
416 }
417
418 /*********************************************************************
419  *              _strtime_s (MSVCRT.@)
420  */
421 int CDECL _strtime_s(char* time, MSVCRT_size_t size)
422 {
423     if(time && size)
424         time[0] = '\0';
425
426     if(!time) {
427         *MSVCRT__errno() = MSVCRT_EINVAL;
428         return MSVCRT_EINVAL;
429     }
430
431     if(size < 9) {
432         *MSVCRT__errno() = MSVCRT_ERANGE;
433         return MSVCRT_ERANGE;
434     }
435
436     _strtime(time);
437     return 0;
438 }
439
440 /*********************************************************************
441  *              _wstrtime (MSVCRT.@)
442  */
443 MSVCRT_wchar_t* CDECL _wstrtime(MSVCRT_wchar_t* time)
444 {
445   static const WCHAR format[] = { 'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0 };
446
447   GetTimeFormatW(LOCALE_NEUTRAL, 0, NULL, format, time, 9);
448
449   return time;
450 }
451
452 /*********************************************************************
453  *              _wstrtime_s (MSVCRT.@)
454  */
455 int CDECL _wstrtime_s(MSVCRT_wchar_t* time, MSVCRT_size_t size)
456 {
457     if(time && size)
458         time[0] = '\0';
459
460     if(!time) {
461         *MSVCRT__errno() = MSVCRT_EINVAL;
462         return MSVCRT_EINVAL;
463     }
464
465     if(size < 9) {
466         *MSVCRT__errno() = MSVCRT_ERANGE;
467         return MSVCRT_ERANGE;
468     }
469
470     _wstrtime(time);
471     return 0;
472 }
473
474 /*********************************************************************
475  *              clock (MSVCRT.@)
476  */
477 MSVCRT_clock_t CDECL MSVCRT_clock(void)
478 {
479   FILETIME ftc, fte, ftk, ftu;
480   ULONGLONG utime, ktime;
481  
482   MSVCRT_clock_t clock;
483
484   GetProcessTimes(GetCurrentProcess(), &ftc, &fte, &ftk, &ftu);
485
486   ktime = ((ULONGLONG)ftk.dwHighDateTime << 32) | ftk.dwLowDateTime;
487   utime = ((ULONGLONG)ftu.dwHighDateTime << 32) | ftu.dwLowDateTime;
488
489   clock = (utime + ktime) / (TICKSPERSEC / MSVCRT_CLOCKS_PER_SEC);
490
491   return clock;
492 }
493
494 /*********************************************************************
495  *              _difftime64 (MSVCRT.@)
496  */
497 double CDECL MSVCRT__difftime64(MSVCRT___time64_t time1, MSVCRT___time64_t time2)
498 {
499   return (double)(time1 - time2);
500 }
501
502 /*********************************************************************
503  *              _difftime32 (MSVCRT.@)
504  */
505 double CDECL MSVCRT__difftime32(MSVCRT___time32_t time1, MSVCRT___time32_t time2)
506 {
507   return (double)(time1 - time2);
508 }
509
510 /*********************************************************************
511  *              difftime (MSVCRT.@)
512  */
513 #ifdef _WIN64
514 double CDECL MSVCRT_difftime(MSVCRT___time64_t time1, MSVCRT___time64_t time2)
515 {
516     return MSVCRT__difftime64( time1, time2 );
517 }
518 #else
519 double CDECL MSVCRT_difftime(MSVCRT___time32_t time1, MSVCRT___time32_t time2)
520 {
521     return MSVCRT__difftime32( time1, time2 );
522 }
523 #endif
524
525 /*********************************************************************
526  *              _ftime64 (MSVCRT.@)
527  */
528 void CDECL MSVCRT__ftime64(struct MSVCRT___timeb64 *buf)
529 {
530   TIME_ZONE_INFORMATION tzinfo;
531   FILETIME ft;
532   ULONGLONG time;
533
534   DWORD tzid = GetTimeZoneInformation(&tzinfo);
535   GetSystemTimeAsFileTime(&ft);
536
537   time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
538
539   buf->time = time / TICKSPERSEC - SECS_1601_TO_1970;
540   buf->millitm = (time % TICKSPERSEC) / TICKSPERMSEC;
541   buf->timezone = tzinfo.Bias +
542       ( tzid == TIME_ZONE_ID_STANDARD ? tzinfo.StandardBias :
543       ( tzid == TIME_ZONE_ID_DAYLIGHT ? tzinfo.DaylightBias : 0 ));
544   buf->dstflag = (tzid == TIME_ZONE_ID_DAYLIGHT?1:0);
545 }
546
547 /*********************************************************************
548  *              _ftime32 (MSVCRT.@)
549  */
550 void CDECL MSVCRT__ftime32(struct MSVCRT___timeb32 *buf)
551 {
552     struct MSVCRT___timeb64 buf64;
553
554     MSVCRT__ftime64( &buf64 );
555     buf->time     = buf64.time;
556     buf->millitm  = buf64.millitm;
557     buf->timezone = buf64.timezone;
558     buf->dstflag  = buf64.dstflag;
559 }
560
561 /*********************************************************************
562  *              _ftime (MSVCRT.@)
563  */
564 #ifdef _WIN64
565 void CDECL MSVCRT__ftime(struct MSVCRT___timeb64 *buf)
566 {
567     return MSVCRT__ftime64( buf );
568 }
569 #else
570 void CDECL MSVCRT__ftime(struct MSVCRT___timeb32 *buf)
571 {
572     return MSVCRT__ftime32( buf );
573 }
574 #endif
575
576 /*********************************************************************
577  *              _time64 (MSVCRT.@)
578  */
579 MSVCRT___time64_t CDECL MSVCRT__time64(MSVCRT___time64_t *buf)
580 {
581     MSVCRT___time64_t curtime;
582     struct MSVCRT___timeb64 tb;
583
584     MSVCRT__ftime64(&tb);
585
586     curtime = tb.time;
587     return buf ? *buf = curtime : curtime;
588 }
589
590 /*********************************************************************
591  *              _time32 (MSVCRT.@)
592  */
593 MSVCRT___time32_t CDECL MSVCRT__time32(MSVCRT___time32_t *buf)
594 {
595     MSVCRT___time32_t curtime;
596     struct MSVCRT___timeb64 tb;
597
598     MSVCRT__ftime64(&tb);
599
600     curtime = tb.time;
601     return buf ? *buf = curtime : curtime;
602 }
603
604 /*********************************************************************
605  *              time (MSVCRT.@)
606  */
607 #ifdef _WIN64
608 MSVCRT___time64_t CDECL MSVCRT_time(MSVCRT___time64_t* buf)
609 {
610     return MSVCRT__time64( buf );
611 }
612 #else
613 MSVCRT___time32_t CDECL MSVCRT_time(MSVCRT___time32_t* buf)
614 {
615     return MSVCRT__time32( buf );
616 }
617 #endif
618
619 /*********************************************************************
620  *              _daylight (MSVCRT.@)
621  */
622 int MSVCRT___daylight = 0;
623
624 /*********************************************************************
625  *              __p_daylight (MSVCRT.@)
626  */
627 int * CDECL MSVCRT___p__daylight(void)
628 {
629         return &MSVCRT___daylight;
630 }
631
632 /*********************************************************************
633  *              _dstbias (MSVCRT.@)
634  */
635 int MSVCRT__dstbias = 0;
636
637 /*********************************************************************
638  *              __p_dstbias (MSVCRT.@)
639  */
640 int * CDECL __p__dstbias(void)
641 {
642     return &MSVCRT__dstbias;
643 }
644
645 /*********************************************************************
646  *              _timezone (MSVCRT.@)
647  */
648 MSVCRT_long MSVCRT___timezone = 0;
649
650 /*********************************************************************
651  *              __p_timezone (MSVCRT.@)
652  */
653 MSVCRT_long * CDECL MSVCRT___p__timezone(void)
654 {
655         return &MSVCRT___timezone;
656 }
657
658 /*********************************************************************
659  *              _tzname (MSVCRT.@)
660  * NOTES
661  *  Some apps (notably Mozilla) insist on writing to these, so the buffer
662  *  must be large enough.  The size is picked based on observation of
663  *  Windows XP.
664  */
665 static char tzname_std[64] = "";
666 static char tzname_dst[64] = "";
667 char *MSVCRT__tzname[2] = { tzname_std, tzname_dst };
668
669 /*********************************************************************
670  *              __p_tzname (MSVCRT.@)
671  */
672 char ** CDECL __p__tzname(void)
673 {
674         return MSVCRT__tzname;
675 }
676
677 /*********************************************************************
678  *              _tzset (MSVCRT.@)
679  */
680 void CDECL MSVCRT__tzset(void)
681 {
682     tzset();
683 #if defined(HAVE_TIMEZONE) && defined(HAVE_DAYLIGHT)
684     MSVCRT___daylight = daylight;
685     MSVCRT___timezone = timezone;
686 #else
687     {
688         static const time_t seconds_in_year = (365 * 24 + 6) * 3600;
689         time_t t;
690         struct tm *tmp;
691         int zone_january, zone_july;
692
693         _mlock(_TIME_LOCK);
694         t = (time(NULL) / seconds_in_year) * seconds_in_year;
695         tmp = localtime(&t);
696         zone_january = -tmp->tm_gmtoff;
697         t += seconds_in_year / 2;
698         tmp = localtime(&t);
699         zone_july = -tmp->tm_gmtoff;
700         _munlock(_TIME_LOCK);
701
702         MSVCRT___daylight = (zone_january != zone_july);
703         MSVCRT___timezone = max(zone_january, zone_july);
704     }
705 #endif
706     lstrcpynA(tzname_std, tzname[0], sizeof(tzname_std));
707     tzname_std[sizeof(tzname_std) - 1] = '\0';
708     lstrcpynA(tzname_dst, tzname[1], sizeof(tzname_dst));
709     tzname_dst[sizeof(tzname_dst) - 1] = '\0';
710 }
711
712 /*********************************************************************
713  *              strftime (MSVCRT.@)
714  */
715 MSVCRT_size_t CDECL MSVCRT_strftime( char *str, MSVCRT_size_t max, const char *format,
716                                      const struct MSVCRT_tm *mstm )
717 {
718     struct tm tm;
719
720     msvcrt_tm_to_unix( &tm, mstm );
721     return strftime( str, max, format, &tm );
722 }
723
724 /*********************************************************************
725  *              wcsftime (MSVCRT.@)
726  */
727 MSVCRT_size_t CDECL MSVCRT_wcsftime( MSVCRT_wchar_t *str, MSVCRT_size_t max,
728                                      const MSVCRT_wchar_t *format, const struct MSVCRT_tm *mstm )
729 {
730     char *s, *fmt;
731     MSVCRT_size_t len;
732
733     TRACE("%p %ld %s %p\n", str, max, debugstr_w(format), mstm );
734
735     len = WideCharToMultiByte( CP_UNIXCP, 0, format, -1, NULL, 0, NULL, NULL );
736     if (!(fmt = MSVCRT_malloc( len ))) return 0;
737     WideCharToMultiByte( CP_UNIXCP, 0, format, -1, fmt, len, NULL, NULL );
738
739     if ((s = MSVCRT_malloc( max*4 )))
740     {
741         struct tm tm;
742         msvcrt_tm_to_unix( &tm, mstm );
743         if (!strftime( s, max*4, fmt, &tm )) s[0] = 0;
744         len = MultiByteToWideChar( CP_UNIXCP, 0, s, -1, str, max );
745         if (len) len--;
746         MSVCRT_free( s );
747     }
748     else len = 0;
749
750     MSVCRT_free( fmt );
751     return len;
752 }
753
754 /*********************************************************************
755  *              asctime (MSVCRT.@)
756  */
757 char * CDECL MSVCRT_asctime(const struct MSVCRT_tm *mstm)
758 {
759     thread_data_t *data = msvcrt_get_thread_data();
760     struct tm tm;
761
762     msvcrt_tm_to_unix( &tm, mstm );
763
764     if (!data->asctime_buffer)
765         data->asctime_buffer = MSVCRT_malloc( 30 ); /* ought to be enough */
766
767     /* FIXME: may want to map from Unix codepage to CP_ACP */
768 #ifdef HAVE_ASCTIME_R
769     asctime_r( &tm, data->asctime_buffer );
770 #else
771     strcpy( data->asctime_buffer, asctime(&tm) );
772 #endif
773     return data->asctime_buffer;
774 }
775
776 /*********************************************************************
777  *              _wasctime (MSVCRT.@)
778  */
779 MSVCRT_wchar_t * CDECL MSVCRT__wasctime(const struct MSVCRT_tm *mstm)
780 {
781     thread_data_t *data = msvcrt_get_thread_data();
782     struct tm tm;
783     char buffer[30];
784
785     msvcrt_tm_to_unix( &tm, mstm );
786
787     if (!data->wasctime_buffer)
788         data->wasctime_buffer = MSVCRT_malloc( 30*sizeof(MSVCRT_wchar_t) ); /* ought to be enough */
789 #ifdef HAVE_ASCTIME_R
790     asctime_r( &tm, buffer );
791 #else
792     strcpy( buffer, asctime(&tm) );
793 #endif
794     MultiByteToWideChar( CP_UNIXCP, 0, buffer, -1, data->wasctime_buffer, 30 );
795     return data->wasctime_buffer;
796 }
797
798 /*********************************************************************
799  *              _ctime64 (MSVCRT.@)
800  */
801 char * CDECL MSVCRT__ctime64(const MSVCRT___time64_t *time)
802 {
803     struct MSVCRT_tm *t;
804     t = MSVCRT__localtime64( time );
805     if (!t) return NULL;
806     return MSVCRT_asctime( t );
807 }
808
809 /*********************************************************************
810  *              _ctime32 (MSVCRT.@)
811  */
812 char * CDECL MSVCRT__ctime32(const MSVCRT___time32_t *time)
813 {
814     struct MSVCRT_tm *t;
815     t = MSVCRT__localtime32( time );
816     if (!t) return NULL;
817     return MSVCRT_asctime( t );
818 }
819
820 /*********************************************************************
821  *              ctime (MSVCRT.@)
822  */
823 #ifdef _WIN64
824 char * CDECL MSVCRT_ctime(const MSVCRT___time64_t *time)
825 {
826     return MSVCRT__ctime64( time );
827 }
828 #else
829 char * CDECL MSVCRT_ctime(const MSVCRT___time32_t *time)
830 {
831     return MSVCRT__ctime32( time );
832 }
833 #endif
834
835 /*********************************************************************
836  *              _wctime64 (MSVCRT.@)
837  */
838 MSVCRT_wchar_t * CDECL MSVCRT__wctime64(const MSVCRT___time64_t *time)
839 {
840     return MSVCRT__wasctime( MSVCRT__localtime64(time) );
841 }
842
843 /*********************************************************************
844  *              _wctime32 (MSVCRT.@)
845  */
846 MSVCRT_wchar_t * CDECL MSVCRT__wctime32(const MSVCRT___time32_t *time)
847 {
848     return MSVCRT__wasctime( MSVCRT__localtime32(time) );
849 }
850
851 /*********************************************************************
852  *              _wctime (MSVCRT.@)
853  */
854 #ifdef _WIN64
855 MSVCRT_wchar_t * CDECL MSVCRT__wctime(const MSVCRT___time64_t *time)
856 {
857     return MSVCRT__wctime64( time );
858 }
859 #else
860 MSVCRT_wchar_t * CDECL MSVCRT__wctime(const MSVCRT___time32_t *time)
861 {
862     return MSVCRT__wctime32( time );
863 }
864 #endif