1 /* 2 * Unit test suite for time functions. 3 * 4 * Copyright 2004 Uwe Bonnes 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "precomp.h" 22 23 #include <time.h> 24 25 #define _MAX__TIME64_T (((__time64_t)0x00000007 << 32) | 0x93406FFF) 26 27 #define SECSPERDAY 86400 28 #define SECSPERHOUR 3600 29 #define SECSPERMIN 60 30 #define MINSPERHOUR 60 31 #define HOURSPERDAY 24 32 33 static __time32_t (__cdecl *p_mkgmtime32)(struct tm*); 34 static struct tm* (__cdecl *p_gmtime32)(__time32_t*); 35 static struct tm* (__cdecl *p_gmtime)(time_t*); 36 static errno_t (__cdecl *p_gmtime32_s)(struct tm*, __time32_t*); 37 static errno_t (__cdecl *p_strtime_s)(char*,size_t); 38 static errno_t (__cdecl *p_strdate_s)(char*,size_t); 39 static errno_t (__cdecl *p_localtime32_s)(struct tm*, __time32_t*); 40 static errno_t (__cdecl *p_localtime64_s)(struct tm*, __time64_t*); 41 static int* (__cdecl *p__daylight)(void); 42 static int* (__cdecl *p___p__daylight)(void); 43 static long* (__cdecl *p___p__dstbias)(void); 44 static long* (__cdecl *p__dstbias)(void); 45 static long* (__cdecl *p___p__timezone)(void); 46 static size_t (__cdecl *p_strftime)(char *, size_t, const char *, const struct tm *); 47 static size_t (__cdecl *p_wcsftime)(wchar_t *, size_t, const wchar_t *, const struct tm *); 48 static char* (__cdecl *p_asctime)(const struct tm *); 49 50 static void init(void) 51 { 52 HMODULE hmod = LoadLibraryA("msvcrt.dll"); 53 54 p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32"); 55 p_gmtime = (void*)GetProcAddress(hmod, "gmtime"); 56 p_gmtime32_s = (void*)GetProcAddress(hmod, "_gmtime32_s"); 57 p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32"); 58 p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s"); 59 p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_s"); 60 p_localtime32_s = (void*)GetProcAddress(hmod, "_localtime32_s"); 61 p_localtime64_s = (void*)GetProcAddress(hmod, "_localtime64_s"); 62 p__daylight = (void*)GetProcAddress(hmod, "__daylight"); 63 p___p__daylight = (void*)GetProcAddress(hmod, "__p__daylight"); 64 p___p__dstbias = (void*)GetProcAddress(hmod, "__p__dstbias"); 65 p__dstbias = (void*)GetProcAddress(hmod, "__dstbias"); 66 p___p__timezone = (void*)GetProcAddress(hmod, "__p__timezone"); 67 p_strftime = (void*)GetProcAddress(hmod, "strftime"); 68 p_wcsftime = (void*)GetProcAddress(hmod, "wcsftime"); 69 p_asctime = (void*)GetProcAddress(hmod, "asctime"); 70 } 71 72 static int get_test_year(time_t *start) 73 { 74 time_t now = time(NULL); 75 struct tm *tm = localtime(&now); 76 77 /* compute start of year in seconds */ 78 *start = SECSPERDAY * ((tm->tm_year - 70) * 365 + 79 (tm->tm_year - 69) / 4 - 80 (tm->tm_year - 1) / 100 + 81 (tm->tm_year + 299) / 400); 82 return tm->tm_year; 83 } 84 85 static void test_ctime(void) 86 { 87 time_t badtime = -1; 88 char* ret; 89 ret = ctime(&badtime); 90 ok(ret == NULL, "expected ctime to return NULL, got %s\n", ret); 91 } 92 static void test_gmtime(void) 93 { 94 __time32_t valid, gmt; 95 struct tm* gmt_tm, gmt_tm_s; 96 errno_t err; 97 98 if(!p_gmtime32) { 99 win_skip("Skipping _gmtime32 tests\n"); 100 return; 101 } 102 103 gmt_tm = p_gmtime32(NULL); 104 ok(gmt_tm == NULL, "gmt_tm != NULL\n"); 105 106 gmt = -1; 107 gmt_tm = p_gmtime32(&gmt); 108 ok(gmt_tm==NULL || broken(gmt_tm->tm_year==70 && gmt_tm->tm_sec<0), "gmt_tm != NULL\n"); 109 110 gmt = valid = 0; 111 gmt_tm = p_gmtime32(&gmt); 112 if(!gmt_tm) { 113 ok(0, "_gmtime32() failed\n"); 114 return; 115 } 116 117 ok(((gmt_tm->tm_year == 70) && (gmt_tm->tm_mon == 0) && (gmt_tm->tm_yday == 0) && 118 (gmt_tm->tm_mday == 1) && (gmt_tm->tm_wday == 4) && (gmt_tm->tm_hour == 0) && 119 (gmt_tm->tm_min == 0) && (gmt_tm->tm_sec == 0) && (gmt_tm->tm_isdst == 0)), 120 "Wrong date:Year %4d mon %2d yday %3d mday %2d wday %1d hour%2d min %2d sec %2d dst %2d\n", 121 gmt_tm->tm_year, gmt_tm->tm_mon, gmt_tm->tm_yday, gmt_tm->tm_mday, gmt_tm->tm_wday, 122 gmt_tm->tm_hour, gmt_tm->tm_min, gmt_tm->tm_sec, gmt_tm->tm_isdst); 123 124 if(!p_mkgmtime32) { 125 win_skip("Skipping _mkgmtime32 tests\n"); 126 return; 127 } 128 129 gmt_tm->tm_wday = gmt_tm->tm_yday = 0; 130 gmt = p_mkgmtime32(gmt_tm); 131 ok(gmt == valid, "gmt = %u\n", gmt); 132 ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday); 133 ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday); 134 135 gmt_tm->tm_wday = gmt_tm->tm_yday = 0; 136 gmt_tm->tm_isdst = -1; 137 gmt = p_mkgmtime32(gmt_tm); 138 ok(gmt == valid, "gmt = %u\n", gmt); 139 ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday); 140 ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday); 141 142 gmt_tm->tm_wday = gmt_tm->tm_yday = 0; 143 gmt_tm->tm_isdst = 1; 144 gmt = p_mkgmtime32(gmt_tm); 145 ok(gmt == valid, "gmt = %u\n", gmt); 146 ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday); 147 ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday); 148 149 gmt = valid = 173921; 150 gmt_tm = p_gmtime32(&gmt); 151 if(!gmt_tm) { 152 ok(0, "_gmtime32() failed\n"); 153 return; 154 } 155 156 gmt_tm->tm_isdst = -1; 157 gmt = p_mkgmtime32(gmt_tm); 158 ok(gmt == valid, "gmt = %u\n", gmt); 159 ok(gmt_tm->tm_wday == 6, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday); 160 ok(gmt_tm->tm_yday == 2, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday); 161 162 gmt_tm->tm_isdst = 1; 163 gmt = p_mkgmtime32(gmt_tm); 164 ok(gmt == valid, "gmt = %u\n", gmt); 165 166 if(!p_gmtime32_s) { 167 win_skip("Skipping _gmtime32_s tests\n"); 168 return; 169 } 170 171 errno = 0; 172 gmt = 0; 173 err = p_gmtime32_s(NULL, &gmt); 174 ok(err == EINVAL, "err = %d\n", err); 175 ok(errno == EINVAL, "errno = %d\n", errno); 176 177 errno = 0; 178 gmt = -1; 179 err = p_gmtime32_s(&gmt_tm_s, &gmt); 180 ok(gmt_tm_s.tm_year == -1 || broken(gmt_tm_s.tm_year == 70 && gmt_tm_s.tm_sec < 0), 181 "tm_year = %d, tm_sec = %d\n", gmt_tm_s.tm_year, gmt_tm_s.tm_sec); 182 if(gmt_tm_s.tm_year == -1) { 183 ok(err==EINVAL, "err = %d\n", err); 184 ok(errno==EINVAL, "errno = %d\n", errno); 185 } 186 } 187 188 static void test_mktime(void) 189 { 190 TIME_ZONE_INFORMATION tzinfo; 191 DWORD res = GetTimeZoneInformation(&tzinfo); 192 struct tm my_tm, sav_tm; 193 time_t nulltime, local_time; 194 char TZ_env[256]; 195 char buffer[64]; 196 int year; 197 time_t ref, secs; 198 199 year = get_test_year( &ref ); 200 ref += SECSPERDAY; 201 202 ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n"); 203 WideCharToMultiByte( CP_ACP, 0, tzinfo.StandardName, -1, buffer, sizeof(buffer), NULL, NULL ); 204 trace( "bias %d std %d dst %d zone %s\n", 205 tzinfo.Bias, tzinfo.StandardBias, tzinfo.DaylightBias, buffer ); 206 /* Bias may be positive or negative, to use offset of one day */ 207 my_tm = *localtime(&ref); /* retrieve current dst flag */ 208 secs = SECSPERDAY - tzinfo.Bias * SECSPERMIN; 209 secs -= (my_tm.tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN; 210 my_tm.tm_mday = 1 + secs/SECSPERDAY; 211 secs = secs % SECSPERDAY; 212 my_tm.tm_hour = secs / SECSPERHOUR; 213 secs = secs % SECSPERHOUR; 214 my_tm.tm_min = secs / SECSPERMIN; 215 secs = secs % SECSPERMIN; 216 my_tm.tm_sec = secs; 217 218 my_tm.tm_year = year; 219 my_tm.tm_mon = 0; 220 221 sav_tm = my_tm; 222 223 local_time = mktime(&my_tm); 224 ok(local_time == ref, "mktime returned %u, expected %u\n", 225 (DWORD)local_time, (DWORD)ref); 226 /* now test some unnormalized struct tm's */ 227 my_tm = sav_tm; 228 my_tm.tm_sec += 60; 229 my_tm.tm_min -= 1; 230 local_time = mktime(&my_tm); 231 ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", 232 (DWORD)local_time, (DWORD)ref); 233 ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && 234 my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && 235 my_tm.tm_sec == sav_tm.tm_sec, 236 "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n", 237 my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday, 238 my_tm.tm_hour,my_tm.tm_sec, 239 sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday, 240 sav_tm.tm_hour,sav_tm.tm_sec); 241 my_tm = sav_tm; 242 my_tm.tm_min -= 60; 243 my_tm.tm_hour += 1; 244 local_time = mktime(&my_tm); 245 ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", 246 (DWORD)local_time, (DWORD)ref); 247 ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && 248 my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && 249 my_tm.tm_sec == sav_tm.tm_sec, 250 "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n", 251 my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday, 252 my_tm.tm_hour,my_tm.tm_sec, 253 sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday, 254 sav_tm.tm_hour,sav_tm.tm_sec); 255 my_tm = sav_tm; 256 my_tm.tm_mon -= 12; 257 my_tm.tm_year += 1; 258 local_time = mktime(&my_tm); 259 ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", 260 (DWORD)local_time, (DWORD)ref); 261 ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && 262 my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && 263 my_tm.tm_sec == sav_tm.tm_sec, 264 "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n", 265 my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday, 266 my_tm.tm_hour,my_tm.tm_sec, 267 sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday, 268 sav_tm.tm_hour,sav_tm.tm_sec); 269 my_tm = sav_tm; 270 my_tm.tm_mon += 12; 271 my_tm.tm_year -= 1; 272 local_time = mktime(&my_tm); 273 ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", 274 (DWORD)local_time, (DWORD)ref); 275 ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && 276 my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && 277 my_tm.tm_sec == sav_tm.tm_sec, 278 "mktime returned %2d-%02d-%02d %02d:%02d expected %2d-%02d-%02d %02d:%02d\n", 279 my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday, 280 my_tm.tm_hour,my_tm.tm_sec, 281 sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday, 282 sav_tm.tm_hour,sav_tm.tm_sec); 283 /* now a bad time example */ 284 my_tm = sav_tm; 285 my_tm.tm_year = 69; 286 local_time = mktime(&my_tm); 287 ok((local_time == -1), "(bad time) mktime returned %d, expected -1\n", (int)local_time); 288 289 my_tm = sav_tm; 290 /* TEST that we are independent from the TZ variable */ 291 /*Argh, msvcrt doesn't have setenv() */ 292 _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):"")); 293 putenv("TZ=GMT"); 294 nulltime = mktime(&my_tm); 295 ok(nulltime == ref,"mktime returned 0x%08x\n",(DWORD)nulltime); 296 putenv(TZ_env); 297 } 298 299 static void test_localtime(void) 300 { 301 TIME_ZONE_INFORMATION tzinfo; 302 DWORD res = GetTimeZoneInformation(&tzinfo); 303 time_t gmt, ref; 304 305 char TZ_env[256]; 306 struct tm* lt; 307 int year = get_test_year( &ref ); 308 int is_leap = !(year % 4) && ((year % 100) || !((year + 300) % 400)); 309 310 gmt = ref + SECSPERDAY + tzinfo.Bias * SECSPERMIN; 311 ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n"); 312 lt = localtime(&gmt); 313 gmt += (lt->tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN; 314 lt = localtime(&gmt); 315 ok(((lt->tm_year == year) && (lt->tm_mon == 0) && (lt->tm_yday == 1) && 316 (lt->tm_mday == 2) && (lt->tm_hour == 0) && 317 (lt->tm_min == 0) && (lt->tm_sec == 0)), 318 "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n", 319 lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, 320 lt->tm_min, lt->tm_sec, lt->tm_isdst); 321 322 _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):"")); 323 putenv("TZ=GMT"); 324 lt = localtime(&gmt); 325 ok(((lt->tm_year == year) && (lt->tm_mon == 0) && (lt->tm_yday == 1) && 326 (lt->tm_mday == 2) && (lt->tm_hour == 0) && 327 (lt->tm_min == 0) && (lt->tm_sec == 0)), 328 "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n", 329 lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, 330 lt->tm_min, lt->tm_sec, lt->tm_isdst); 331 putenv(TZ_env); 332 333 /* June 22 */ 334 gmt = ref + 202 * SECSPERDAY + tzinfo.Bias * SECSPERMIN; 335 lt = localtime(&gmt); 336 gmt += (lt->tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN; 337 lt = localtime(&gmt); 338 ok(((lt->tm_year == year) && (lt->tm_mon == 6) && (lt->tm_yday == 202) && 339 (lt->tm_mday == 22 - is_leap) && (lt->tm_hour == 0) && 340 (lt->tm_min == 0) && (lt->tm_sec == 0)), 341 "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n", 342 lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, 343 lt->tm_min, lt->tm_sec, lt->tm_isdst); 344 } 345 346 static void test_strdate(void) 347 { 348 char date[16], * result; 349 int month, day, year, count, len; 350 errno_t err; 351 352 result = _strdate(date); 353 ok(result == date, "Wrong return value\n"); 354 len = strlen(date); 355 ok(len == 8, "Wrong length: returned %d, should be 8\n", len); 356 count = sscanf(date, "%02d/%02d/%02d", &month, &day, &year); 357 ok(count == 3, "Wrong format: count = %d, should be 3\n", count); 358 359 if(!p_strdate_s) { 360 win_skip("Skipping _strdate_s tests\n"); 361 return; 362 } 363 364 errno = 0; 365 err = p_strdate_s(NULL, 1); 366 ok(err == EINVAL, "err = %d\n", err); 367 ok(errno == EINVAL, "errno = %d\n", errno); 368 369 date[0] = 'x'; 370 date[1] = 'x'; 371 err = p_strdate_s(date, 8); 372 ok(err == ERANGE, "err = %d\n", err); 373 ok(errno == ERANGE, "errno = %d\n", errno); 374 ok(date[0] == '\0', "date[0] != '\\0'\n"); 375 ok(date[1] == 'x', "date[1] != 'x'\n"); 376 377 err = p_strdate_s(date, 9); 378 ok(err == 0, "err = %x\n", err); 379 } 380 381 static void test_strtime(void) 382 { 383 char time[16], * result; 384 int hour, minute, second, count, len; 385 errno_t err; 386 387 result = _strtime(time); 388 ok(result == time, "Wrong return value\n"); 389 len = strlen(time); 390 ok(len == 8, "Wrong length: returned %d, should be 8\n", len); 391 count = sscanf(time, "%02d:%02d:%02d", &hour, &minute, &second); 392 ok(count == 3, "Wrong format: count = %d, should be 3\n", count); 393 394 if(!p_strtime_s) { 395 win_skip("Skipping _strtime_s tests\n"); 396 return; 397 } 398 399 errno = 0; 400 err = p_strtime_s(NULL, 0); 401 ok(err == EINVAL, "err = %d\n", err); 402 ok(errno == EINVAL, "errno = %d\n", errno); 403 404 err = p_strtime_s(NULL, 1); 405 ok(err == EINVAL, "err = %d\n", err); 406 ok(errno == EINVAL, "errno = %d\n", errno); 407 408 time[0] = 'x'; 409 err = p_strtime_s(time, 8); 410 ok(err == ERANGE, "err = %d\n", err); 411 ok(errno == ERANGE, "errno = %d\n", errno); 412 ok(time[0] == '\0', "time[0] != '\\0'\n"); 413 414 err = p_strtime_s(time, 9); 415 ok(err == 0, "err = %x\n", err); 416 } 417 418 static void test_wstrdate(void) 419 { 420 wchar_t date[16], * result; 421 int month, day, year, count, len; 422 wchar_t format[] = { '%','0','2','d','/','%','0','2','d','/','%','0','2','d',0 }; 423 424 result = _wstrdate(date); 425 ok(result == date, "Wrong return value\n"); 426 len = wcslen(date); 427 ok(len == 8, "Wrong length: returned %d, should be 8\n", len); 428 count = swscanf(date, format, &month, &day, &year); 429 ok(count == 3, "Wrong format: count = %d, should be 3\n", count); 430 } 431 432 static void test_wstrtime(void) 433 { 434 wchar_t time[16], * result; 435 int hour, minute, second, count, len; 436 wchar_t format[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',0 }; 437 438 result = _wstrtime(time); 439 ok(result == time, "Wrong return value\n"); 440 len = wcslen(time); 441 ok(len == 8, "Wrong length: returned %d, should be 8\n", len); 442 count = swscanf(time, format, &hour, &minute, &second); 443 ok(count == 3, "Wrong format: count = %d, should be 3\n", count); 444 } 445 446 static void test_localtime32_s(void) 447 { 448 struct tm tm; 449 __time32_t time; 450 errno_t err; 451 452 if (!p_localtime32_s) 453 { 454 win_skip("Skipping _localtime32_s tests\n"); 455 return; 456 } 457 458 errno = EBADF; 459 err = p_localtime32_s(NULL, NULL); 460 ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err); 461 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 462 463 errno = EBADF; 464 time = 0x12345678; 465 err = p_localtime32_s(NULL, &time); 466 ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err); 467 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 468 469 memset(&tm, 0, sizeof(tm)); 470 errno = EBADF; 471 err = p_localtime32_s(&tm, NULL); 472 ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err); 473 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 474 ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 && 475 tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 && 476 tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1, 477 "Expected tm structure members to be initialized to -1, got " 478 "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min, 479 tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, 480 tm.tm_isdst); 481 482 memset(&tm, 0, sizeof(tm)); 483 time = -1; 484 errno = EBADF; 485 err = p_localtime32_s(&tm, &time); 486 ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err); 487 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 488 ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 && 489 tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 && 490 tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1, 491 "Expected tm structure members to be initialized to -1, got " 492 "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min, 493 tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, 494 tm.tm_isdst); 495 } 496 497 static void test_localtime64_s(void) 498 { 499 struct tm tm; 500 __time64_t time; 501 errno_t err; 502 503 if (!p_localtime64_s) 504 { 505 win_skip("Skipping _localtime64_s tests\n"); 506 return; 507 } 508 509 errno = EBADF; 510 err = p_localtime64_s(NULL, NULL); 511 ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); 512 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 513 514 errno = EBADF; 515 time = 0xdeadbeef; 516 err = p_localtime64_s(NULL, &time); 517 ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); 518 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 519 520 memset(&tm, 0, sizeof(tm)); 521 errno = EBADF; 522 err = p_localtime64_s(&tm, NULL); 523 ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); 524 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 525 ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 && 526 tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 && 527 tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1, 528 "Expected tm structure members to be initialized to -1, got " 529 "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min, 530 tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, 531 tm.tm_isdst); 532 533 memset(&tm, 0, sizeof(tm)); 534 time = -1; 535 errno = EBADF; 536 err = p_localtime64_s(&tm, &time); 537 ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); 538 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 539 ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 && 540 tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 && 541 tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1, 542 "Expected tm structure members to be initialized to -1, got " 543 "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min, 544 tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, 545 tm.tm_isdst); 546 547 memset(&tm, 0, sizeof(tm)); 548 time = _MAX__TIME64_T + 1; 549 errno = EBADF; 550 err = p_localtime64_s(&tm, &time); 551 ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); 552 ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); 553 ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 && 554 tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 && 555 tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1, 556 "Expected tm structure members to be initialized to -1, got " 557 "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min, 558 tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, 559 tm.tm_isdst); 560 } 561 562 static void test_daylight(void) 563 { 564 int *ret1, *ret2; 565 566 if (!p__daylight) 567 { 568 win_skip("__daylight() not available\n"); 569 return; 570 } 571 572 if (!p___p__daylight) 573 { 574 win_skip("__p__daylight not available\n"); 575 return; 576 } 577 578 ret1 = p__daylight(); 579 ret2 = p___p__daylight(); 580 ok(ret1 && ret1 == ret2, "got %p\n", ret1); 581 } 582 583 static void test_strftime(void) 584 { 585 static const wchar_t cW[] = { '%','c',0 }; 586 static const char expected[] = "01/01/70 00:00:00"; 587 time_t gmt; 588 struct tm* gmt_tm; 589 char buf[256], bufA[256]; 590 WCHAR bufW[256]; 591 long retA, retW; 592 593 if (!p_strftime || !p_wcsftime || !p_gmtime) 594 { 595 win_skip("strftime, wcsftime or gmtime is not available\n"); 596 return; 597 } 598 599 setlocale(LC_TIME, "C"); 600 601 gmt = 0; 602 gmt_tm = p_gmtime(&gmt); 603 ok(gmt_tm != NULL, "gmtime failed\n"); 604 605 errno = 0xdeadbeef; 606 retA = strftime(NULL, 0, "copy", gmt_tm); 607 ok(retA == 0, "expected 0, got %ld\n", retA); 608 ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); 609 610 retA = strftime(bufA, 256, "copy", NULL); 611 ok(retA == 4, "expected 4, got %ld\n", retA); 612 ok(!strcmp(bufA, "copy"), "got %s\n", bufA); 613 614 retA = strftime(bufA, 256, "copy it", gmt_tm); 615 ok(retA == 7, "expected 7, got %ld\n", retA); 616 ok(!strcmp(bufA, "copy it"), "got %s\n", bufA); 617 618 errno = 0xdeadbeef; 619 retA = strftime(bufA, 2, "copy", gmt_tm); 620 ok(retA == 0, "expected 0, got %ld\n", retA); 621 ok(!strcmp(bufA, "") || broken(!strcmp(bufA, "copy it")), "got %s\n", bufA); 622 ok(errno==ERANGE || errno==0xdeadbeef, "errno = %d\n", errno); 623 624 errno = 0xdeadbeef; 625 retA = strftime(bufA, 256, "a%e", gmt_tm); 626 ok(retA==0 || broken(retA==1), "expected 0, got %ld\n", retA); 627 ok(!strcmp(bufA, "") || broken(!strcmp(bufA, "a")), "got %s\n", bufA); 628 ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); 629 630 if(0) { /* crashes on Win2k */ 631 errno = 0xdeadbeef; 632 retA = strftime(bufA, 256, "%c", NULL); 633 ok(retA == 0, "expected 0, got %ld\n", retA); 634 ok(!strcmp(bufA, ""), "got %s\n", bufA); 635 ok(errno == EINVAL, "errno = %d\n", errno); 636 } 637 638 retA = strftime(bufA, 256, "e%#%e", gmt_tm); 639 ok(retA == 3, "expected 3, got %ld\n", retA); 640 ok(!strcmp(bufA, "e%e"), "got %s\n", bufA); 641 642 retA = strftime(bufA, 256, "%c", gmt_tm); 643 ok(retA == 17, "expected 17, got %ld\n", retA); 644 ok(strcmp(bufA, expected) == 0, "expected %s, got %s\n", expected, bufA); 645 646 retW = wcsftime(bufW, 256, cW, gmt_tm); 647 ok(retW == 17, "expected 17, got %ld\n", retW); 648 ok(retA == retW, "expected %ld, got %ld\n", retA, retW); 649 buf[0] = 0; 650 retA = WideCharToMultiByte(CP_ACP, 0, bufW, retW, buf, 256, NULL, NULL); 651 buf[retA] = 0; 652 ok(strcmp(bufA, buf) == 0, "expected %s, got %s\n", bufA, buf); 653 654 retA = strftime(bufA, 256, "%x", gmt_tm); 655 ok(retA == 8, "expected 8, got %ld\n", retA); 656 ok(!strcmp(bufA, "01/01/70"), "got %s\n", bufA); 657 658 retA = strftime(bufA, 256, "%X", gmt_tm); 659 ok(retA == 8, "expected 8, got %ld\n", retA); 660 ok(!strcmp(bufA, "00:00:00"), "got %s\n", bufA); 661 662 retA = strftime(bufA, 256, "%a", gmt_tm); 663 ok(retA == 3, "expected 3, got %ld\n", retA); 664 ok(!strcmp(bufA, "Thu"), "got %s\n", bufA); 665 666 retA = strftime(bufA, 256, "%A", gmt_tm); 667 ok(retA == 8, "expected 8, got %ld\n", retA); 668 ok(!strcmp(bufA, "Thursday"), "got %s\n", bufA); 669 670 retA = strftime(bufA, 256, "%b", gmt_tm); 671 ok(retA == 3, "expected 3, got %ld\n", retA); 672 ok(!strcmp(bufA, "Jan"), "got %s\n", bufA); 673 674 retA = strftime(bufA, 256, "%B", gmt_tm); 675 ok(retA == 7, "expected 7, got %ld\n", retA); 676 ok(!strcmp(bufA, "January"), "got %s\n", bufA); 677 678 retA = strftime(bufA, 256, "%d", gmt_tm); 679 ok(retA == 2, "expected 2, got %ld\n", retA); 680 ok(!strcmp(bufA, "01"), "got %s\n", bufA); 681 682 retA = strftime(bufA, 256, "%#d", gmt_tm); 683 ok(retA == 1, "expected 1, got %ld\n", retA); 684 ok(!strcmp(bufA, "1"), "got %s\n", bufA); 685 686 retA = strftime(bufA, 256, "%H", gmt_tm); 687 ok(retA == 2, "expected 2, got %ld\n", retA); 688 ok(!strcmp(bufA, "00"), "got %s\n", bufA); 689 690 retA = strftime(bufA, 256, "%I", gmt_tm); 691 ok(retA == 2, "expected 2, got %ld\n", retA); 692 ok(!strcmp(bufA, "12"), "got %s\n", bufA); 693 694 retA = strftime(bufA, 256, "%j", gmt_tm); 695 ok(retA == 3, "expected 3, got %ld\n", retA); 696 ok(!strcmp(bufA, "001"), "got %s\n", bufA); 697 698 retA = strftime(bufA, 256, "%m", gmt_tm); 699 ok(retA == 2, "expected 2, got %ld\n", retA); 700 ok(!strcmp(bufA, "01"), "got %s\n", bufA); 701 702 retA = strftime(bufA, 256, "%#M", gmt_tm); 703 ok(retA == 1, "expected 1, got %ld\n", retA); 704 ok(!strcmp(bufA, "0"), "got %s\n", bufA); 705 706 retA = strftime(bufA, 256, "%p", gmt_tm); 707 ok(retA == 2, "expected 2, got %ld\n", retA); 708 ok(!strcmp(bufA, "AM"), "got %s\n", bufA); 709 710 retA = strftime(bufA, 256, "%U", gmt_tm); 711 ok(retA == 2, "expected 2, got %ld\n", retA); 712 ok(!strcmp(bufA, "00"), "got %s\n", bufA); 713 714 retA = strftime(bufA, 256, "%W", gmt_tm); 715 ok(retA == 2, "expected 2, got %ld\n", retA); 716 ok(!strcmp(bufA, "00"), "got %s\n", bufA); 717 718 gmt_tm->tm_wday = 0; 719 retA = strftime(bufA, 256, "%U", gmt_tm); 720 ok(retA == 2, "expected 2, got %ld\n", retA); 721 ok(!strcmp(bufA, "01"), "got %s\n", bufA); 722 723 retA = strftime(bufA, 256, "%W", gmt_tm); 724 ok(retA == 2, "expected 2, got %ld\n", retA); 725 ok(!strcmp(bufA, "00"), "got %s\n", bufA); 726 727 gmt_tm->tm_yday = 365; 728 retA = strftime(bufA, 256, "%U", gmt_tm); 729 ok(retA == 2, "expected 2, got %ld\n", retA); 730 ok(!strcmp(bufA, "53"), "got %s\n", bufA); 731 732 retA = strftime(bufA, 256, "%W", gmt_tm); 733 ok(retA == 2, "expected 2, got %ld\n", retA); 734 ok(!strcmp(bufA, "52"), "got %s\n", bufA); 735 736 gmt_tm->tm_mon = 1; 737 gmt_tm->tm_mday = 30; 738 retA = strftime(bufA, 256, "%c", gmt_tm); 739 todo_wine { 740 ok(retA == 17, "expected 17, got %ld\n", retA); 741 ok(!strcmp(bufA, "02/30/70 00:00:00"), "got %s\n", bufA); 742 } 743 744 if(!setlocale(LC_ALL, "Japanese_Japan.932")) { 745 win_skip("Japanese_Japan.932 locale not available\n"); 746 return; 747 } 748 749 /* test with multibyte character */ 750 retA = strftime(bufA, 256, "\x82%c", gmt_tm); 751 ok(retA == 3, "expected 3, got %ld\n", retA); 752 ok(!strcmp(bufA, "\x82%c"), "got %s\n", bufA); 753 } 754 755 static void test_asctime(void) 756 { 757 struct tm* gmt_tm; 758 time_t gmt; 759 char *ret; 760 761 if(!p_asctime || !p_gmtime) 762 { 763 win_skip("asctime or gmtime is not available\n"); 764 return; 765 } 766 767 gmt = 0; 768 gmt_tm = p_gmtime(&gmt); 769 ret = p_asctime(gmt_tm); 770 ok(!strcmp(ret, "Thu Jan 01 00:00:00 1970\n"), "asctime returned %s\n", ret); 771 772 gmt = 312433121; 773 gmt_tm = p_gmtime(&gmt); 774 ret = p_asctime(gmt_tm); 775 ok(!strcmp(ret, "Mon Nov 26 02:58:41 1979\n"), "asctime returned %s\n", ret); 776 777 /* Week day is only checked if it's in 0..6 range */ 778 gmt_tm->tm_wday = 3; 779 ret = p_asctime(gmt_tm); 780 ok(!strcmp(ret, "Wed Nov 26 02:58:41 1979\n"), "asctime returned %s\n", ret); 781 782 errno = 0xdeadbeef; 783 gmt_tm->tm_wday = 7; 784 ret = p_asctime(gmt_tm); 785 ok(!ret || broken(!ret[0]), "asctime returned %s\n", ret); 786 ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); 787 788 /* Year day is ignored */ 789 gmt_tm->tm_wday = 3; 790 gmt_tm->tm_yday = 1300; 791 ret = p_asctime(gmt_tm); 792 ok(!strcmp(ret, "Wed Nov 26 02:58:41 1979\n"), "asctime returned %s\n", ret); 793 794 /* Dates that can't be displayed using 26 characters are broken */ 795 gmt_tm->tm_mday = 28; 796 gmt_tm->tm_year = 8100; 797 ret = p_asctime(gmt_tm); 798 ok(!strcmp(ret, "Wed Nov 28 02:58:41 :000\n"), "asctime returned %s\n", ret); 799 800 gmt_tm->tm_year = 264100; 801 ret = p_asctime(gmt_tm); 802 ok(!strcmp(ret, "Wed Nov 28 02:58:41 :000\n"), "asctime returned %s\n", ret); 803 804 /* asctime works from year 1900 */ 805 errno = 0xdeadbeef; 806 gmt_tm->tm_year = -1; 807 ret = p_asctime(gmt_tm); 808 ok(!ret || broken(!strcmp(ret, "Wed Nov 28 02:58:41 190/\n")), "asctime returned %s\n", ret); 809 ok(errno==EINVAL || broken(errno == 0xdeadbeef), "errno = %d\n", errno); 810 811 errno = 0xdeadbeef; 812 gmt_tm->tm_mon = 1; 813 gmt_tm->tm_mday = 30; 814 gmt_tm->tm_year = 79; 815 ret = p_asctime(gmt_tm); 816 ok(!ret || broken(!strcmp(ret, "Wed Feb 30 02:58:41 1979\n")), "asctime returned %s\n", ret); 817 ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); 818 } 819 820 static void test__tzset(void) 821 { 822 char TZ_env[256]; 823 int ret; 824 825 if(!p___p__daylight || !p___p__timezone || !p___p__dstbias) { 826 win_skip("__p__daylight, __p__timezone or __p__dstbias is not available\n"); 827 return; 828 } 829 830 if (p__dstbias) { 831 ret = *p__dstbias(); 832 ok(ret == -3600, "*__dstbias() = %d\n", ret); 833 ret = *p___p__dstbias(); 834 ok(ret == -3600, "*__p__dstbias() = %d\n", ret); 835 } 836 else 837 win_skip("__dstbias() is not available.\n"); 838 839 _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):"")); 840 841 ret = *p___p__daylight(); 842 ok(ret == 1, "*__p__daylight() = %d\n", ret); 843 ret = *p___p__timezone(); 844 ok(ret == 28800, "*__p__timezone() = %d\n", ret); 845 ret = *p___p__dstbias(); 846 ok(ret == -3600, "*__p__dstbias() = %d\n", ret); 847 848 _putenv("TZ=xxx+1yyy"); 849 _tzset(); 850 ret = *p___p__daylight(); 851 ok(ret == 121, "*__p__daylight() = %d\n", ret); 852 ret = *p___p__timezone(); 853 ok(ret == 3600, "*__p__timezone() = %d\n", ret); 854 ret = *p___p__dstbias(); 855 ok(ret == -3600, "*__p__dstbias() = %d\n", ret); 856 857 *p___p__dstbias() = 0; 858 _putenv("TZ=xxx+1:3:5zzz"); 859 _tzset(); 860 ret = *p___p__daylight(); 861 ok(ret == 122, "*__p__daylight() = %d\n", ret); 862 ret = *p___p__timezone(); 863 ok(ret == 3785, "*__p__timezone() = %d\n", ret); 864 ret = *p___p__dstbias(); 865 ok(ret == 0, "*__p__dstbias() = %d\n", ret); 866 867 _putenv(TZ_env); 868 } 869 870 static void test_clock(void) 871 { 872 static const int THRESH = 100; 873 FILETIME start, cur; 874 int c, expect; 875 BOOL ret; 876 877 ret = GetProcessTimes(GetCurrentProcess(), &start, &cur, &cur, &cur); 878 ok(ret, "GetProcessTimes failed with error: %d\n", GetLastError()); 879 GetSystemTimeAsFileTime(&cur); 880 expect = (((LONGLONG)cur.dwHighDateTime<<32)+cur.dwLowDateTime - 881 ((LONGLONG)start.dwHighDateTime<<32)-start.dwLowDateTime) / 10000; 882 883 c = clock(); 884 ok(abs(c-expect) < THRESH, "clock() = %d, expected %d\n", c, expect); 885 } 886 887 START_TEST(time) 888 { 889 init(); 890 891 test__tzset(); 892 test_strftime(); 893 test_ctime(); 894 test_gmtime(); 895 test_mktime(); 896 test_localtime(); 897 test_strdate(); 898 test_strtime(); 899 test_wstrdate(); 900 test_wstrtime(); 901 test_localtime32_s(); 902 test_localtime64_s(); 903 test_daylight(); 904 test_asctime(); 905 test_clock(); 906 } 907