{"id":29274969,"url":"https://github.com/ammaraskar/windows-mktime-issue","last_synced_at":"2025-07-05T05:09:52.447Z","repository":{"id":283373522,"uuid":"946209098","full_name":"ammaraskar/windows-mktime-issue","owner":"ammaraskar","description":"Recreation and description of a bug in window's implementation of mktime","archived":false,"fork":false,"pushed_at":"2025-03-10T19:31:57.000Z","size":18,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-04T21:52:11.042Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ammaraskar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-10T19:31:34.000Z","updated_at":"2025-03-10T19:32:01.000Z","dependencies_parsed_at":"2025-03-19T22:49:56.734Z","dependency_job_id":"14bc4e31-70a5-472d-bfc8-baf3c6c458f3","html_url":"https://github.com/ammaraskar/windows-mktime-issue","commit_stats":null,"previous_names":["ammaraskar/windows-mktime-issue"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ammaraskar/windows-mktime-issue","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ammaraskar%2Fwindows-mktime-issue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ammaraskar%2Fwindows-mktime-issue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ammaraskar%2Fwindows-mktime-issue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ammaraskar%2Fwindows-mktime-issue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ammaraskar","download_url":"https://codeload.github.com/ammaraskar/windows-mktime-issue/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ammaraskar%2Fwindows-mktime-issue/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263687157,"owners_count":23496090,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-05T05:09:50.729Z","updated_at":"2025-07-05T05:09:52.439Z","avatar_url":"https://github.com/ammaraskar.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Windows Time Issue\n\nRecreation for an issue with window's `mktime` and Daylight Savings Time\nhandling.\n\nRoot cause is that `mktime` with `tm.tm_isdst = -1` gives answers that are\ninconsistent and wrong compared to the equivalent win32 APIs because it does\nnot handle DST dynamically. It just uses the current DST cutover point for all\nyears.\n\nCutting to the chase, here is a basic recreation for a date in 2003 running on\nEastern Time.\n\n```c\n#include \u003ctime.h\u003e\n#include \u003cstdio.h\u003e\n\nint main() {\n    struct tm tm = {};\n    tm.tm_year = 2003 - 1900;\n    tm.tm_mon = 3 - 1;\n    tm.tm_mday = 22;\n    tm.tm_hour = 18;\n    tm.tm_min = 3;\n    tm.tm_sec = 5;\n    tm.tm_isdst = -1;\n    time_t local_timestamp = mktime(\u0026tm);\n\n    printf(\"time: %ld\\n\", local_timestamp);\n    printf(\"  tm_isdst: %d\\n\", tm.tm_isdst);\n        return 0;\n}\n```\n\n### Linux\n\n```\ntime: 1048374185\n  tm_isdst: 0\n```\n\n### Windows\n\n```\ntime: 1048370585\n  tm_isdst: 1\n```\n\nThat is a difference of 3600 seconds, or, 1 hour.\n\n## Context\n\nSince 2007, DST in the United States has started on the second Sunday of March.\n\nFrom 1987 to 2006 however, DST would begin at the first Sunday of April.\n\nHere is a calendar of March and April of 2003:\n\n--- \n### March 2003\n\n|\tSun\t|\tMon\t|\tTue\t|\tWed\t|\tThu\t|\tFri\t|\tSat\t|\n| :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n|\t\t|\t\t|\t\t|\t\t|\t\t|\t\t|\t1\t|\n|\t2\t|\t3\t|\t4\t|\t5\t|\t6\t|\t7\t|\t8\t|\n|\t**9**\t|\t10\t|\t11\t|\t12\t|\t13\t|\t14\t|\t15\t|\n|\t16\t|\t17\t|\t18\t|\t19\t|\t20\t|\t21\t|\t22\t|\n|\t23\t|\t24\t|\t25\t|\t26\t|\t27\t|\t28\t|\t29\t|\n|\t30\t|\t31\t|\t\t|\t\t|\t\t|\t\t|\t\t|\n\n### April 2003\n\n|\tSun\t|\tMon\t|\tTue\t|\tWed\t|\tThu\t|\tFri\t|\tSat\t|\n| :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n|\t\t|\t\t|\t1\t|\t2\t|\t3\t|\t4\t|\t5\t|\n|\t**6**\t|\t7\t|\t8\t|\t9\t|\t10\t|\t11\t|\t12\t|\n|\t13\t|\t14\t|\t15\t|\t16\t|\t17\t|\t18\t|\t19\t|\n|\t20\t|\t21\t|\t22\t|\t23\t|\t24\t|\t25\t|\t26\t|\n|\t27\t|\t28\t|\t29\t|\t30\t|\t\t|\t\t|\t\t|\n---\n\n## Workaround\n\nThere are win32 APIs that correctly figure out DST that seem to not have this\nissue. If we take the recreation above and do:\n\n```c\nSYSTEMTIME localTime;\nlocalTime.wYear = 2003;\nlocalTime.wMonth = 2;\nlocalTime.wDay = 22;\nlocalTime.wHour = 18;\nlocalTime.wMinute = 3;\nlocalTime.wSecond = 5;\nlocalTime.wMilliseconds = 0;\n\nSYSTEMTIME systemTime;\nTzSpecificLocalTimeToSystemTime(NULL, \u0026localTime, \u0026systemTime);\n\nFILETIME reLocal;\nSystemTimeToFileTime(\u0026systemTime, \u0026reLocal);\n\ntime_t unix_time_seconds = winrt::clock::to_time_t(winrt::clock::from_file_time(reLocal));\nstd::cout \u003c\u003c \"win32:  \" \u003c\u003c unix_time_seconds;\n```\n\nUsing this, we can get the correct timestamp out of Windows as well.\n\n```\nwin32:  1048374185\n```\n\nThis seems to work because `TzSpecificLocalTimeToSystemTime` actually looks at the\ndynamic DST information available:\n\n![syscall Trace of TzSpecificLocalTimeToSystemTime](images/TZSpecificLocalTimeTrace.png)\n\nAs opposed to `mktime`, which eventually calls into the CRT's `_isindst_nolock`,\nat the time of writing it does:\n\n```c\nstatic void __cdecl tzset_from_system_nolock() throw() {\n    ...\n    if (GetTimeZoneInformation(\u0026tz_info) != 0xFFFFFFFF) {\n        // ...\n    }\n}\n\nstatic int __cdecl _isindst_nolock(tm* const tb) throw() {\n    ...\n    // Convert the start of daylight savings time to dststart:\n    if (tz_info.DaylightDate.wYear == 0)\n    {\n        cvtdate(\n            transition_type::start_of_dst,\n            date_type::day_in_month,\n            tb-\u003etm_year,\n            tz_info.DaylightDate.wMonth,\n            tz_info.DaylightDate.wDay,\n            tz_info.DaylightDate.wDayOfWeek,\n            0,\n            tz_info.DaylightDate.wHour,\n            tz_info.DaylightDate.wMinute,\n            tz_info.DaylightDate.wSecond,\n            tz_info.DaylightDate.wMilliseconds);\n    }\n    ...\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fammaraskar%2Fwindows-mktime-issue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fammaraskar%2Fwindows-mktime-issue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fammaraskar%2Fwindows-mktime-issue/lists"}