time.c 26 KB
Newer Older
1 2 3 4 5 6 7
/*
 * msvcrt.dll date/time functions
 *
 * Copyright 1996,1998 Marcus Meissner
 * Copyright 1996 Jukka Iivonen
 * Copyright 1997,2000 Uwe Bonnes
 * Copyright 2000 Jon Griffiths
8
 * Copyright 2004 Hans Leidekker
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 26
#include "config.h"

27
#define _POSIX_PTHREAD_SEMANTICS /* switch to a 2 arg style asctime_r on Solaris */
28
#include <time.h>
29 30 31
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
32
#include <limits.h>
33

34
#include "msvcrt.h"
35
#include "mtdll.h"
36
#include "winbase.h"
37
#include "winnls.h"
38 39 40
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
41

42
static const int MonthLengths[2][12] =
43
{
44 45 46 47 48 49 50
    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};

static inline int IsLeapYear(int Year)
{
    return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
51 52
}

53 54 55 56 57 58 59 60 61 62 63 64 65 66
static inline void msvcrt_tm_to_unix( struct tm *dest, const struct MSVCRT_tm *src )
{
    memset( dest, 0, sizeof(*dest) );
    dest->tm_sec   = src->tm_sec;
    dest->tm_min   = src->tm_min;
    dest->tm_hour  = src->tm_hour;
    dest->tm_mday  = src->tm_mday;
    dest->tm_mon   = src->tm_mon;
    dest->tm_year  = src->tm_year;
    dest->tm_wday  = src->tm_wday;
    dest->tm_yday  = src->tm_yday;
    dest->tm_isdst = src->tm_isdst;
}

67 68 69 70 71 72 73 74 75 76 77 78 79 80
static inline void unix_tm_to_msvcrt( struct MSVCRT_tm *dest, const struct tm *src )
{
    memset( dest, 0, sizeof(*dest) );
    dest->tm_sec   = src->tm_sec;
    dest->tm_min   = src->tm_min;
    dest->tm_hour  = src->tm_hour;
    dest->tm_mday  = src->tm_mday;
    dest->tm_mon   = src->tm_mon;
    dest->tm_year  = src->tm_year;
    dest->tm_wday  = src->tm_wday;
    dest->tm_yday  = src->tm_yday;
    dest->tm_isdst = src->tm_isdst;
}

81 82 83 84 85 86 87 88 89 90 91 92 93
static inline void write_invalid_msvcrt_tm( struct MSVCRT_tm *tm )
{
    tm->tm_sec = -1;
    tm->tm_min = -1;
    tm->tm_hour = -1;
    tm->tm_mday = -1;
    tm->tm_mon = -1;
    tm->tm_year = -1;
    tm->tm_wday = -1;
    tm->tm_yday = -1;
    tm->tm_isdst = -1;
}

94 95 96 97 98 99 100
#define SECSPERDAY        86400
/* 1601 to 1970 is 369 years plus 89 leap days */
#define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
#define TICKSPERSEC       10000000
#define TICKSPERMSEC      10000
#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)

101
/**********************************************************************
102
 *		_mktime64 (MSVCRT.@)
103
 */
104
MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
105
{
106 107 108 109 110 111 112 113
    time_t secs;
    struct tm tm;

    msvcrt_tm_to_unix( &tm, mstm );
    secs = mktime( &tm );
    unix_tm_to_msvcrt( mstm, &tm );

    return secs < 0 ? -1 : secs;
114 115
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/**********************************************************************
 *		_mktime32 (MSVCRT.@)
 */
MSVCRT___time32_t CDECL MSVCRT__mktime32(struct MSVCRT_tm *mstm)
{
    return MSVCRT__mktime64( mstm );
}

/**********************************************************************
 *		mktime (MSVCRT.@)
 */
#ifdef _WIN64
MSVCRT___time64_t CDECL MSVCRT_mktime(struct MSVCRT_tm *mstm)
{
    return MSVCRT__mktime64( mstm );
}
#else
MSVCRT___time32_t CDECL MSVCRT_mktime(struct MSVCRT_tm *mstm)
{
    return MSVCRT__mktime32( mstm );
}
#endif

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/**********************************************************************
 *		_mkgmtime64 (MSVCRT.@)
 *
 * time->tm_isdst value is ignored
 */
MSVCRT___time64_t CDECL MSVCRT__mkgmtime64(struct MSVCRT_tm *time)
{
    SYSTEMTIME st;
    FILETIME ft;
    MSVCRT___time64_t ret;
    int i;

    st.wMilliseconds = 0;
    st.wSecond = time->tm_sec;
    st.wMinute = time->tm_min;
    st.wHour = time->tm_hour;
    st.wDay = time->tm_mday;
    st.wMonth = time->tm_mon+1;
    st.wYear = time->tm_year+1900;

    if(!SystemTimeToFileTime(&st, &ft))
        return -1;

    FileTimeToSystemTime(&ft, &st);
    time->tm_wday = st.wDayOfWeek;

    for(i=time->tm_yday=0; i<st.wMonth-1; i++)
        time->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
    time->tm_yday += st.wDay-1;

    ret = ((MSVCRT___time64_t)ft.dwHighDateTime<<32)+ft.dwLowDateTime;
    ret = (ret-TICKS_1601_TO_1970)/TICKSPERSEC;
    return ret;
}

/**********************************************************************
 *		_mkgmtime32 (MSVCRT.@)
 */
MSVCRT___time32_t CDECL MSVCRT__mkgmtime32(struct MSVCRT_tm *time)
{
    return MSVCRT__mkgmtime64(time);
}

/**********************************************************************
 *		_mkgmtime (MSVCRT.@)
 */
#ifdef _WIN64
MSVCRT___time64_t CDECL MSVCRT__mkgmtime(struct MSVCRT_tm *time)
{
    return MSVCRT__mkgmtime64(time);
}
#else
MSVCRT___time32_t CDECL MSVCRT__mkgmtime(struct MSVCRT_tm *time)
{
    return MSVCRT__mkgmtime32(time);
}
#endif

197
/*********************************************************************
198
 *      _localtime64 (MSVCRT.@)
199
 */
200
struct MSVCRT_tm* CDECL MSVCRT__localtime64(const MSVCRT___time64_t* secs)
201
{
202
    struct tm *tm;
203
    thread_data_t *data;
204
    time_t seconds = *secs;
205

206 207
    if (seconds < 0) return NULL;

208 209 210 211 212
    _mlock(_TIME_LOCK);
    if (!(tm = localtime( &seconds))) {
        _munlock(_TIME_LOCK);
        return NULL;
    }
213 214

    data = msvcrt_get_thread_data();
215 216 217 218
    if(!data->time_buffer)
        data->time_buffer = MSVCRT_malloc(sizeof(struct MSVCRT_tm));

    unix_tm_to_msvcrt( data->time_buffer, tm );
219
    _munlock(_TIME_LOCK);
220

221
    return data->time_buffer;
222 223
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
/*********************************************************************
 *      _localtime64_s (MSVCRT.@)
 */
int CDECL _localtime64_s(struct MSVCRT_tm *time, const MSVCRT___time64_t *secs)
{
    struct tm *tm;
    time_t seconds;

    if (!time || !secs || *secs < 0 || *secs > _MAX__TIME64_T)
    {
        if (time)
            write_invalid_msvcrt_tm(time);

        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    seconds = *secs;

    _mlock(_TIME_LOCK);
    if (!(tm = localtime(&seconds)))
    {
        _munlock(_TIME_LOCK);
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    unix_tm_to_msvcrt(time, tm);
    _munlock(_TIME_LOCK);
    return 0;
}

256
/*********************************************************************
257
 *      _localtime32 (MSVCRT.@)
258
 */
259 260 261 262 263 264
struct MSVCRT_tm* CDECL MSVCRT__localtime32(const MSVCRT___time32_t* secs)
{
    MSVCRT___time64_t secs64 = *secs;
    return MSVCRT__localtime64( &secs64 );
}

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
/*********************************************************************
 *      _localtime32_s (MSVCRT.@)
 */
int CDECL _localtime32_s(struct MSVCRT_tm *time, const MSVCRT___time32_t *secs)
{
    MSVCRT___time64_t secs64;

    if (!time || !secs || *secs < 0)
    {
        if (time)
            write_invalid_msvcrt_tm(time);

        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    secs64 = *secs;
    return _localtime64_s(time, &secs64);
}

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
/*********************************************************************
 *      localtime (MSVCRT.@)
 */
#ifdef _WIN64
struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time64_t* secs)
{
    return MSVCRT__localtime64( secs );
}
#else
struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time32_t* secs)
{
    return MSVCRT__localtime32( secs );
}
#endif

/*********************************************************************
 *      _gmtime64 (MSVCRT.@)
 */
303
int CDECL MSVCRT__gmtime64_s(struct MSVCRT_tm *res, const MSVCRT___time64_t *secs)
304
{
305 306 307 308 309
    int i;
    FILETIME ft;
    SYSTEMTIME st;
    ULONGLONG time;

310 311 312
    if (!res || !secs || *secs < 0) {
        if (res) {
            write_invalid_msvcrt_tm(res);
313 314 315 316 317
        }

        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }
318

319
    time = *secs * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
320

321 322
    ft.dwHighDateTime = (UINT)(time >> 32);
    ft.dwLowDateTime  = (UINT)time;
323

324
    FileTimeToSystemTime(&ft, &st);
325

326 327 328 329 330 331 332 333 334 335
    res->tm_sec  = st.wSecond;
    res->tm_min  = st.wMinute;
    res->tm_hour = st.wHour;
    res->tm_mday = st.wDay;
    res->tm_year = st.wYear - 1900;
    res->tm_mon  = st.wMonth - 1;
    res->tm_wday = st.wDayOfWeek;
    for (i = res->tm_yday = 0; i < st.wMonth - 1; i++) {
        res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
    }
336

337 338
    res->tm_yday += st.wDay - 1;
    res->tm_isdst = 0;
339

340 341
    return 0;
}
342

343 344 345 346 347 348 349
/*********************************************************************
 *      _gmtime64 (MSVCRT.@)
 */
struct MSVCRT_tm* CDECL MSVCRT__gmtime64(const MSVCRT___time64_t *secs)
{
    thread_data_t * const data = msvcrt_get_thread_data();

350 351 352 353
    if(!data->time_buffer)
        data->time_buffer = MSVCRT_malloc(sizeof(struct MSVCRT_tm));

    if(MSVCRT__gmtime64_s(data->time_buffer, secs))
354
        return NULL;
355
    return data->time_buffer;
356 357 358 359 360 361 362 363 364 365 366 367 368 369
}

/*********************************************************************
 *      _gmtime32_s (MSVCRT.@)
 */
int CDECL MSVCRT__gmtime32_s(struct MSVCRT_tm *res, const MSVCRT___time32_t *secs)
{
    MSVCRT___time64_t secs64;

    if(secs) {
        secs64 = *secs;
        return MSVCRT__gmtime64_s(res, &secs64);
    }
    return MSVCRT__gmtime64_s(res, NULL);
370 371
}

372 373 374 375 376
/*********************************************************************
 *      _gmtime32 (MSVCRT.@)
 */
struct MSVCRT_tm* CDECL MSVCRT__gmtime32(const MSVCRT___time32_t* secs)
{
377 378 379 380 381 382
    MSVCRT___time64_t secs64;

    if(!secs)
        return NULL;

    secs64 = *secs;
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    return MSVCRT__gmtime64( &secs64 );
}

/*********************************************************************
 *      gmtime (MSVCRT.@)
 */
#ifdef _WIN64
struct MSVCRT_tm* CDECL MSVCRT_gmtime(const MSVCRT___time64_t* secs)
{
    return MSVCRT__gmtime64( secs );
}
#else
struct MSVCRT_tm* CDECL MSVCRT_gmtime(const MSVCRT___time32_t* secs)
{
    return MSVCRT__gmtime32( secs );
}
#endif

401 402 403
/**********************************************************************
 *		_strdate (MSVCRT.@)
 */
404
char* CDECL MSVCRT__strdate(char* date)
405
{
406
  static const char format[] = "MM'/'dd'/'yy";
407 408 409 410

  GetDateFormatA(LOCALE_NEUTRAL, 0, NULL, format, date, 9);

  return date;
411 412
}

413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
/**********************************************************************
 *              _strdate_s (MSVCRT.@)
 */
int CDECL _strdate_s(char* date, MSVCRT_size_t size)
{
    if(date && size)
        date[0] = '\0';

    if(!date) {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    if(size < 9) {
        *MSVCRT__errno() = MSVCRT_ERANGE;
        return MSVCRT_ERANGE;
    }

431
    MSVCRT__strdate(date);
432 433 434
    return 0;
}

435 436 437
/**********************************************************************
 *		_wstrdate (MSVCRT.@)
 */
438
MSVCRT_wchar_t* CDECL MSVCRT__wstrdate(MSVCRT_wchar_t* date)
439 440 441
{
  static const WCHAR format[] = { 'M','M','\'','/','\'','d','d','\'','/','\'','y','y',0 };

442
  GetDateFormatW(LOCALE_NEUTRAL, 0, NULL, format, date, 9);
443 444 445 446

  return date;
}

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
/**********************************************************************
 *              _wstrdate_s (MSVCRT.@)
 */
int CDECL _wstrdate_s(MSVCRT_wchar_t* date, MSVCRT_size_t size)
{
    if(date && size)
        date[0] = '\0';

    if(!date) {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    if(size < 9) {
        *MSVCRT__errno() = MSVCRT_ERANGE;
        return MSVCRT_ERANGE;
    }

465
    MSVCRT__wstrdate(date);
466 467 468
    return 0;
}

469 470 471
/*********************************************************************
 *		_strtime (MSVCRT.@)
 */
472
char* CDECL MSVCRT__strtime(char* time)
473
{
474
  static const char format[] = "HH':'mm':'ss";
475

476
  GetTimeFormatA(LOCALE_NEUTRAL, 0, NULL, format, time, 9); 
477

478 479 480
  return time;
}

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
/*********************************************************************
 *              _strtime_s (MSVCRT.@)
 */
int CDECL _strtime_s(char* time, MSVCRT_size_t size)
{
    if(time && size)
        time[0] = '\0';

    if(!time) {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    if(size < 9) {
        *MSVCRT__errno() = MSVCRT_ERANGE;
        return MSVCRT_ERANGE;
    }

499
    MSVCRT__strtime(time);
500 501 502
    return 0;
}

503 504 505
/*********************************************************************
 *		_wstrtime (MSVCRT.@)
 */
506
MSVCRT_wchar_t* CDECL MSVCRT__wstrtime(MSVCRT_wchar_t* time)
507 508 509
{
  static const WCHAR format[] = { 'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0 };

510
  GetTimeFormatW(LOCALE_NEUTRAL, 0, NULL, format, time, 9);
511 512

  return time;
513 514
}

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
/*********************************************************************
 *              _wstrtime_s (MSVCRT.@)
 */
int CDECL _wstrtime_s(MSVCRT_wchar_t* time, MSVCRT_size_t size)
{
    if(time && size)
        time[0] = '\0';

    if(!time) {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    if(size < 9) {
        *MSVCRT__errno() = MSVCRT_ERANGE;
        return MSVCRT_ERANGE;
    }

533
    MSVCRT__wstrtime(time);
534 535 536
    return 0;
}

537 538 539
/*********************************************************************
 *		clock (MSVCRT.@)
 */
540
MSVCRT_clock_t CDECL MSVCRT_clock(void)
541
{
542 543 544 545 546 547 548 549 550 551
  FILETIME ftc, fte, ftk, ftu;
  ULONGLONG utime, ktime;
 
  MSVCRT_clock_t clock;

  GetProcessTimes(GetCurrentProcess(), &ftc, &fte, &ftk, &ftu);

  ktime = ((ULONGLONG)ftk.dwHighDateTime << 32) | ftk.dwLowDateTime;
  utime = ((ULONGLONG)ftu.dwHighDateTime << 32) | ftu.dwLowDateTime;

552
  clock = (utime + ktime) / (TICKSPERSEC / MSVCRT_CLOCKS_PER_SEC);
553 554

  return clock;
555 556 557
}

/*********************************************************************
558
 *		_difftime64 (MSVCRT.@)
559
 */
560
double CDECL MSVCRT__difftime64(MSVCRT___time64_t time1, MSVCRT___time64_t time2)
561
{
562
  return (double)(time1 - time2);
563 564 565
}

/*********************************************************************
566
 *		_difftime32 (MSVCRT.@)
567
 */
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
double CDECL MSVCRT__difftime32(MSVCRT___time32_t time1, MSVCRT___time32_t time2)
{
  return (double)(time1 - time2);
}

/*********************************************************************
 *		difftime (MSVCRT.@)
 */
#ifdef _WIN64
double CDECL MSVCRT_difftime(MSVCRT___time64_t time1, MSVCRT___time64_t time2)
{
    return MSVCRT__difftime64( time1, time2 );
}
#else
double CDECL MSVCRT_difftime(MSVCRT___time32_t time1, MSVCRT___time32_t time2)
{
    return MSVCRT__difftime32( time1, time2 );
}
#endif

/*********************************************************************
 *		_ftime64 (MSVCRT.@)
 */
void CDECL MSVCRT__ftime64(struct MSVCRT___timeb64 *buf)
592
{
593 594 595 596 597 598 599 600 601 602 603
  TIME_ZONE_INFORMATION tzinfo;
  FILETIME ft;
  ULONGLONG time;

  DWORD tzid = GetTimeZoneInformation(&tzinfo);
  GetSystemTimeAsFileTime(&ft);

  time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;

  buf->time = time / TICKSPERSEC - SECS_1601_TO_1970;
  buf->millitm = (time % TICKSPERSEC) / TICKSPERMSEC;
604 605 606
  buf->timezone = tzinfo.Bias +
      ( tzid == TIME_ZONE_ID_STANDARD ? tzinfo.StandardBias :
      ( tzid == TIME_ZONE_ID_DAYLIGHT ? tzinfo.DaylightBias : 0 ));
607
  buf->dstflag = (tzid == TIME_ZONE_ID_DAYLIGHT?1:0);
608
}
609

610 611 612 613 614 615 616 617 618 619 620 621 622 623
/*********************************************************************
 *		_ftime64_s (MSVCRT.@)
 */
int CDECL MSVCRT__ftime64_s(struct MSVCRT___timeb64 *buf)
{
    if( !MSVCRT_CHECK_PMT( buf != NULL ) )
    {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }
    MSVCRT__ftime64(buf);
    return 0;
}

624
/*********************************************************************
625
 *		_ftime32 (MSVCRT.@)
626
 */
627
void CDECL MSVCRT__ftime32(struct MSVCRT___timeb32 *buf)
628
{
629
    struct MSVCRT___timeb64 buf64;
630

631 632 633 634 635 636
    MSVCRT__ftime64( &buf64 );
    buf->time     = buf64.time;
    buf->millitm  = buf64.millitm;
    buf->timezone = buf64.timezone;
    buf->dstflag  = buf64.dstflag;
}
637

638 639 640 641 642 643 644 645 646 647 648 649 650 651
/*********************************************************************
 *		_ftime32_s (MSVCRT.@)
 */
int CDECL MSVCRT__ftime32_s(struct MSVCRT___timeb32 *buf)
{
    if( !MSVCRT_CHECK_PMT( buf != NULL ) )
    {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }
    MSVCRT__ftime32(buf);
    return 0;
}

652 653 654 655 656 657
/*********************************************************************
 *		_ftime (MSVCRT.@)
 */
#ifdef _WIN64
void CDECL MSVCRT__ftime(struct MSVCRT___timeb64 *buf)
{
658
    MSVCRT__ftime64( buf );
659
}
660 661 662
#else
void CDECL MSVCRT__ftime(struct MSVCRT___timeb32 *buf)
{
663
    MSVCRT__ftime32( buf );
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
}
#endif

/*********************************************************************
 *		_time64 (MSVCRT.@)
 */
MSVCRT___time64_t CDECL MSVCRT__time64(MSVCRT___time64_t *buf)
{
    MSVCRT___time64_t curtime;
    struct MSVCRT___timeb64 tb;

    MSVCRT__ftime64(&tb);

    curtime = tb.time;
    return buf ? *buf = curtime : curtime;
}

/*********************************************************************
 *		_time32 (MSVCRT.@)
 */
MSVCRT___time32_t CDECL MSVCRT__time32(MSVCRT___time32_t *buf)
{
    MSVCRT___time32_t curtime;
    struct MSVCRT___timeb64 tb;

    MSVCRT__ftime64(&tb);

    curtime = tb.time;
    return buf ? *buf = curtime : curtime;
}

/*********************************************************************
 *		time (MSVCRT.@)
 */
#ifdef _WIN64
MSVCRT___time64_t CDECL MSVCRT_time(MSVCRT___time64_t* buf)
{
    return MSVCRT__time64( buf );
}
#else
MSVCRT___time32_t CDECL MSVCRT_time(MSVCRT___time32_t* buf)
{
    return MSVCRT__time32( buf );
}
#endif
709

710 711 712
/*********************************************************************
 *		_daylight (MSVCRT.@)
 */
713
int MSVCRT___daylight = 0;
714 715 716 717

/*********************************************************************
 *		__p_daylight (MSVCRT.@)
 */
718
int * CDECL MSVCRT___p__daylight(void)
719 720 721
{
	return &MSVCRT___daylight;
}
722

723 724 725 726 727 728 729 730
/*********************************************************************
 *		_dstbias (MSVCRT.@)
 */
int MSVCRT__dstbias = 0;

/*********************************************************************
 *		__p_dstbias (MSVCRT.@)
 */
731
int * CDECL __p__dstbias(void)
732 733 734 735
{
    return &MSVCRT__dstbias;
}

736 737 738
/*********************************************************************
 *		_timezone (MSVCRT.@)
 */
739
MSVCRT_long MSVCRT___timezone = 0;
740 741 742 743

/*********************************************************************
 *		__p_timezone (MSVCRT.@)
 */
744
MSVCRT_long * CDECL MSVCRT___p__timezone(void)
745 746 747 748
{
	return &MSVCRT___timezone;
}

749 750 751 752 753 754 755
/*********************************************************************
 *		_tzname (MSVCRT.@)
 * NOTES
 *  Some apps (notably Mozilla) insist on writing to these, so the buffer
 *  must be large enough.  The size is picked based on observation of
 *  Windows XP.
 */
756 757
static char tzname_std[64] = "PST";
static char tzname_dst[64] = "PDT";
758 759
char *MSVCRT__tzname[2] = { tzname_std, tzname_dst };

760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
/*********************************************************************
 *		_get_tzname (MSVCRT.@)
 */
int CDECL MSVCRT__get_tzname(MSVCRT_size_t *ret, char *buf, MSVCRT_size_t bufsize, int index)
{
    char *timezone;

    switch(index)
    {
    case 0:
        timezone = tzname_std;
        break;
    case 1:
        timezone = tzname_dst;
        break;
    default:
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    if(!ret || (!buf && bufsize > 0) || (buf && !bufsize))
    {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }

    *ret = strlen(timezone)+1;
    if(!buf && !bufsize)
        return 0;

    strcpy(buf, timezone);
    return 0;
}

794 795 796
/*********************************************************************
 *		__p_tzname (MSVCRT.@)
 */
797
char ** CDECL __p__tzname(void)
798 799 800
{
	return MSVCRT__tzname;
}
801 802 803 804

/*********************************************************************
 *		_tzset (MSVCRT.@)
 */
805
void CDECL MSVCRT__tzset(void)
806 807
{
    tzset();
808
#if defined(HAVE_TIMEZONE) && defined(HAVE_DAYLIGHT)
809 810
    MSVCRT___daylight = daylight;
    MSVCRT___timezone = timezone;
811 812 813 814 815
#else
    {
        static const time_t seconds_in_year = (365 * 24 + 6) * 3600;
        time_t t;
        struct tm *tmp;
816
        int zone_january, zone_july;
817

818
        _mlock(_TIME_LOCK);
819
        t = (time(NULL) / seconds_in_year) * seconds_in_year;
820 821 822 823 824
        tmp = localtime(&t);
        zone_january = -tmp->tm_gmtoff;
        t += seconds_in_year / 2;
        tmp = localtime(&t);
        zone_july = -tmp->tm_gmtoff;
825 826
        _munlock(_TIME_LOCK);

827 828 829 830
        MSVCRT___daylight = (zone_january != zone_july);
        MSVCRT___timezone = max(zone_january, zone_july);
    }
#endif
831 832 833 834 835
    lstrcpynA(tzname_std, tzname[0], sizeof(tzname_std));
    tzname_std[sizeof(tzname_std) - 1] = '\0';
    lstrcpynA(tzname_dst, tzname[1], sizeof(tzname_dst));
    tzname_dst[sizeof(tzname_dst) - 1] = '\0';
}
836 837

/*********************************************************************
838 839
 *		strftime (MSVCRT.@)
 */
840 841
MSVCRT_size_t CDECL MSVCRT_strftime( char *str, MSVCRT_size_t max, const char *format,
                                     const struct MSVCRT_tm *mstm )
842 843 844 845 846 847 848
{
    struct tm tm;

    msvcrt_tm_to_unix( &tm, mstm );
    return strftime( str, max, format, &tm );
}

849 850 851
/*********************************************************************
 *		wcsftime (MSVCRT.@)
 */
852 853
MSVCRT_size_t CDECL MSVCRT_wcsftime( MSVCRT_wchar_t *str, MSVCRT_size_t max,
                                     const MSVCRT_wchar_t *format, const struct MSVCRT_tm *mstm )
854
{
855 856
    char *s, *fmt;
    MSVCRT_size_t len;
857

858
    TRACE("%p %ld %s %p\n", str, max, debugstr_w(format), mstm );
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876

    len = WideCharToMultiByte( CP_UNIXCP, 0, format, -1, NULL, 0, NULL, NULL );
    if (!(fmt = MSVCRT_malloc( len ))) return 0;
    WideCharToMultiByte( CP_UNIXCP, 0, format, -1, fmt, len, NULL, NULL );

    if ((s = MSVCRT_malloc( max*4 )))
    {
        struct tm tm;
        msvcrt_tm_to_unix( &tm, mstm );
        if (!strftime( s, max*4, fmt, &tm )) s[0] = 0;
        len = MultiByteToWideChar( CP_UNIXCP, 0, s, -1, str, max );
        if (len) len--;
        MSVCRT_free( s );
    }
    else len = 0;

    MSVCRT_free( fmt );
    return len;
877 878
}

879 880 881
/*********************************************************************
 *		asctime (MSVCRT.@)
 */
882
char * CDECL MSVCRT_asctime(const struct MSVCRT_tm *mstm)
883
{
884 885 886
    char bufferA[30];
    WCHAR bufferW[30];

887 888 889 890 891 892 893 894 895
    thread_data_t *data = msvcrt_get_thread_data();
    struct tm tm;

    msvcrt_tm_to_unix( &tm, mstm );

    if (!data->asctime_buffer)
        data->asctime_buffer = MSVCRT_malloc( 30 ); /* ought to be enough */

#ifdef HAVE_ASCTIME_R
896
    asctime_r( &tm, bufferA );
897
#else
898
    strcpy( bufferA, asctime(&tm) );
899
#endif
900 901
    MultiByteToWideChar( CP_UNIXCP, 0, bufferA, -1, bufferW, 30 );
    WideCharToMultiByte( CP_ACP, 0, bufferW, -1, data->asctime_buffer, 30, NULL, NULL );
902 903 904 905 906
    return data->asctime_buffer;
}

/*********************************************************************
 *		_wasctime (MSVCRT.@)
907
 */
908
MSVCRT_wchar_t * CDECL MSVCRT__wasctime(const struct MSVCRT_tm *mstm)
909
{
910
    thread_data_t *data = msvcrt_get_thread_data();
911 912 913 914
    struct tm tm;
    char buffer[30];

    msvcrt_tm_to_unix( &tm, mstm );
915 916 917

    if (!data->wasctime_buffer)
        data->wasctime_buffer = MSVCRT_malloc( 30*sizeof(MSVCRT_wchar_t) ); /* ought to be enough */
918 919 920 921 922 923
#ifdef HAVE_ASCTIME_R
    asctime_r( &tm, buffer );
#else
    strcpy( buffer, asctime(&tm) );
#endif
    MultiByteToWideChar( CP_UNIXCP, 0, buffer, -1, data->wasctime_buffer, 30 );
924 925 926
    return data->wasctime_buffer;
}

927
/*********************************************************************
928 929 930 931 932 933 934 935 936 937
 *		_ctime64 (MSVCRT.@)
 */
char * CDECL MSVCRT__ctime64(const MSVCRT___time64_t *time)
{
    struct MSVCRT_tm *t;
    t = MSVCRT__localtime64( time );
    if (!t) return NULL;
    return MSVCRT_asctime( t );
}

938 939 940 941 942 943 944 945 946 947 948 949
/*********************************************************************
 *		_ctime64_s (MSVCRT.@)
 */
int CDECL MSVCRT__ctime64_s(char *res, MSVCRT_size_t len, const MSVCRT___time64_t *time)
{
    struct MSVCRT_tm *t;
    if( !MSVCRT_CHECK_PMT( res != NULL ) || !MSVCRT_CHECK_PMT( len >= 26 ) )
    {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }
    res[0] = '\0';
950
    if( !MSVCRT_CHECK_PMT( time != NULL ) || !MSVCRT_CHECK_PMT( *time > 0 ) )
951 952 953 954 955 956 957 958 959
    {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }
    t = MSVCRT__localtime64( time );
    strcpy( res, MSVCRT_asctime( t ) );
    return 0;
}

960 961
/*********************************************************************
 *		_ctime32 (MSVCRT.@)
962
 */
963
char * CDECL MSVCRT__ctime32(const MSVCRT___time32_t *time)
964
{
965
    struct MSVCRT_tm *t;
966
    t = MSVCRT__localtime32( time );
967 968
    if (!t) return NULL;
    return MSVCRT_asctime( t );
969 970
}

971 972 973 974 975 976 977 978 979 980 981 982
/*********************************************************************
 *		_ctime32_s (MSVCRT.@)
 */
int CDECL MSVCRT__ctime32_s(char *res, MSVCRT_size_t len, const MSVCRT___time32_t *time)
{
    struct MSVCRT_tm *t;
    if( !MSVCRT_CHECK_PMT( res != NULL ) || !MSVCRT_CHECK_PMT( len >= 26 ) )
    {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }
    res[0] = '\0';
983
    if( !MSVCRT_CHECK_PMT( time != NULL ) || !MSVCRT_CHECK_PMT( *time > 0 ) )
984 985 986 987 988 989 990 991 992
    {
        *MSVCRT__errno() = MSVCRT_EINVAL;
        return MSVCRT_EINVAL;
    }
    t = MSVCRT__localtime32( time );
    strcpy( res, MSVCRT_asctime( t ) );
    return 0;
}

993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
/*********************************************************************
 *		ctime (MSVCRT.@)
 */
#ifdef _WIN64
char * CDECL MSVCRT_ctime(const MSVCRT___time64_t *time)
{
    return MSVCRT__ctime64( time );
}
#else
char * CDECL MSVCRT_ctime(const MSVCRT___time32_t *time)
{
    return MSVCRT__ctime32( time );
}
#endif

/*********************************************************************
 *		_wctime64 (MSVCRT.@)
 */
MSVCRT_wchar_t * CDECL MSVCRT__wctime64(const MSVCRT___time64_t *time)
{
    return MSVCRT__wasctime( MSVCRT__localtime64(time) );
}

/*********************************************************************
 *		_wctime32 (MSVCRT.@)
 */
MSVCRT_wchar_t * CDECL MSVCRT__wctime32(const MSVCRT___time32_t *time)
{
    return MSVCRT__wasctime( MSVCRT__localtime32(time) );
}

1024 1025 1026
/*********************************************************************
 *		_wctime (MSVCRT.@)
 */
1027 1028
#ifdef _WIN64
MSVCRT_wchar_t * CDECL MSVCRT__wctime(const MSVCRT___time64_t *time)
1029
{
1030
    return MSVCRT__wctime64( time );
1031
}
1032 1033 1034 1035 1036 1037
#else
MSVCRT_wchar_t * CDECL MSVCRT__wctime(const MSVCRT___time32_t *time)
{
    return MSVCRT__wctime32( time );
}
#endif