{"id":111643,"date":"2025-10-01T07:00:00","date_gmt":"2025-10-01T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111643"},"modified":"2025-10-01T09:45:02","modified_gmt":"2025-10-01T16:45:02","slug":"20251001-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20251001-00\/?p=111643","title":{"rendered":"How do I convert a <CODE>FILETIME<\/CODE> to a C++ clock like <CODE>std::system_clock<\/CODE> or <CODE>winrt::clock<\/CODE>?"},"content":{"rendered":"<p>The traditional Win32 data structure for holding a date\/time is the <code>FILETIME<\/code>. How do you interoperate between this and the C++ clocks like <code>std::system_clock<\/code> and <code>winrt::clock<\/code>?<\/p>\n<p>When C++ introduced the concept of clocks in C++11, it did not require clocks to have any particular epoch. In C++20, the rules were strengthened to require <code>system_<wbr \/>clock<\/code> to have an epoch of January 1, 1970 (so-called Unix Time). The period of the system clock remains unspecified, although you can inspect it at compile time via <code>std::<wbr \/>chrono::<wbr \/>system_clock::<wbr \/>period<\/code>.<\/p>\n<p>So how do you get a <code>FILETIME<\/code> into a C++ clock?<\/p>\n<p>C++\/WinRT&#8217;s <code>winrt::clock<\/code> comes to the rescue. This is the projection of the Windows Runtime <code>DateTime<\/code> structure, which is defined to be in the same units as <code>FILETIME<\/code>. Therefore, once you pack the two parts of the <code>FILETIME<\/code> into a single <code>int64_t<\/code>, the conversion between <code>FILETIME<\/code> and <code>winrt::clock<\/code> is mathematically trivial.<\/p>\n<p>It&#8217;s mathematically trivial, but you still have to do a bunch of typing:<\/p>\n<pre>winrt::clock::time_point winrt_clock_from_FILETIME(FILETIME ft)\r\n{\r\n    \/\/ First, pack it into a 64-bit integer\r\n    auto count = (static_cast&lt;long long&gt;(ft.dwHighDateTime) &lt;&lt; 32)\r\n               | ft.dwLowDateTime;\r\n\r\n    \/\/ Then place it inside a duration (aka TimeSpan) to represent\r\n    \/  time since epoch\r\n    auto span = winrt::clock::duration(count);\r\n    \/\/ Alternatively: auto span = winrt::Windows::Foundation::TimeSpan(count);\r\n\r\n    \/\/ Then create a winrt::clock::time_point from it   \r\n    return winrt::clock::time_point(span);\r\n    \/\/ Alternatively: return winrt::Windows::Foundation::DateTime(span);\r\n}\r\n<\/pre>\n<p>Fortunately, C++\/WinRT comes with helpers to make this easier.<\/p>\n<p>For example, the <code>winrt::<wbr \/>file_time<\/code> structure lets you convert between <code>FILETIME<\/code> and 64-bit integers.<\/p>\n<pre>winrt::clock::time_point winrt_clock_from_FILETIME(FILETIME ft)\r\n{\r\n    \/\/ First, pack it into a 64-bit integer\r\n    auto count = <span style=\"border: solid 1px currentcolor;\">winrt::file_time(ft).value;<\/span>\r\n\r\n    \/\/ Then place it inside a duration (aka TimeSpan) to represent\r\n    \/  time since epoch\r\n    auto span = winrt::clock::duration(count);\r\n    \/\/ Alternatively: auto span = winrt::Windows::Foundation::TimeSpan(count);\r\n\r\n    \/\/ Then create a winrt::clock::time_point from it   \r\n    return winrt::clock::time_point(span);\r\n    \/\/ Alternatively: return winrt::Windows::Foundation::DateTime(span);\r\n}\r\n<\/pre>\n<p>And the conversion to a duration, and then to a time point is handled by another helper:<\/p>\n<pre>winrt::clock::time_point winrt_clock_from_FILETIME(FILETIME ft)\r\n{\r\n    auto t = winrt::file_time(ft);\r\n    return winrt::clock::from_file_time(t);\r\n}\r\n<\/pre>\n<p>And the entire thing is handled by yet another helper:<\/p>\n<pre>winrt::clock::time_point winrt_clock_from_FILETIME(FILETIME ft)\r\n{\r\n    return winrt::clock::from_FILETIME(ft);\r\n}\r\n<\/pre>\n<p>So we didn&#8217;t need to write our function at all. C++\/WinRT came with it built-in.<\/p>\n<p>Once you&#8217;ve entered C++-land, you can use a clock cast to convert it to other C++ clocks.<\/p>\n<pre>template&lt;typename Clock&gt;\r\ntypename Clock::time_point\r\n    clock_from_FILETIME(FILETIME ft)\r\n{\r\n    return std::chrono::clock_cast&lt;Clock&gt;(\r\n            winrt::clock::from_FILETIME(ft));\r\n}\r\n\r\ntemplate&lt;typename TimePoint&gt;\r\nFILETIME\r\nFILETIME_from_clock(TimePoint const&amp; t)\r\n{\r\n    return winrt::clock::to_FILETIME(\r\n        std::chrono::clock_cast&lt;winrt::clock&gt;(t));        \r\n}<\/pre>\n<p><b>Bonus reading<\/b>: <a title=\"Converting between Windows FILETIME and Unix time_t without having to type the magic number 116444736000000000\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220602-00\/?p=106706\"> Converting between Windows FILETIME and Unix time_t without having to type the magic number 116444736000000000<\/a>. The <code>winrt::clock<\/code> also gets you out of the constants business.<\/p>\n<pre>magic1 = winrt::clock::from_time_t(0).time_since_epoch().count();\r\nmagic2 = winrt::clock::period::num \/ winrt::clock::period::den;\r\n<\/pre>\n<pre>\u00a0<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The <CODE>winrt::clock<\/CODE> has a conversion for you.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-111643","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The <CODE>winrt::clock<\/CODE> has a conversion for you.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111643","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=111643"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111643\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=111643"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111643"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111643"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}