4

I am migrating some code from vc120 to vc140 and I am running into a problem with ftime64. The problem is similar to one mentioned on the Visual Studio dev community where ftime64 seems to have a year-2038 bug in 2015/2017 but where 2013 does not.

Here's some example code:

#include "stdafx.h"
#include <sys/timeb.h>
int main()
{
  __timeb64 testTime64;  
  _ftime64(&testTime64);  
  printf("%lld\n", testTime64.time);  
  return 0;
} 

With dates after 03:14:07 UTC on 2038/01/19, the time appears to wrap over the 32-bit boundary.

To test, compile the above code as ftime_check and run the following from an admin command prompt (note your numbers will vary due to the time of day on your clock):

date 1/18/2038 && ftime_check
2147474668
date 1/20/2038 && ftime_check
-2147319812

For reference, here is the (expected) output as seen under vc120:

date 1/18/2038 && ftime_check
2147482944
date 1/20/2038 && ftime_check
2147655752

I see the same issue with all of these functions ftime, _ftime, _ftime64, _ftime_s, and _ftime64_s

Is anyone else experiencing this, and how are you working around it?

syplex
  • 1,147
  • 6
  • 27
  • You might want to edit this into a [mcve] so we can try it without needing to add the missing bits or set our system clock to 2040 and mess up cookies, certs, licenses and such. – Dave S Jun 20 '17 at 23:02
  • According to [the documentation](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/ftime-ftime32-ftime64) `_timeb64` should be good through 12/31/3000. How are you arriving at the conclusion that it doesn't work? – Mark Ransom Jun 20 '17 at 23:03
  • @DaveS - I updated it with some additional steps. You will have to adjust your clock to test this. – syplex Jun 20 '17 at 23:56
  • `2526338561` looks a little suspicious as this corresponds to 2050-01-21 00:42:41 UTC. – Howard Hinnant Jun 21 '17 at 01:12
  • @HowardHinnant oops copy/paste fail. Updated post. – syplex Jun 21 '17 at 02:04
  • The Y2038 bug is still very much present in Windows. FILETIME is a good example of that. – Michaël Roy Jun 21 '17 at 02:32
  • It is a simple bug in the common_ftime_s() template function, it has a `static_cast<__time32_t>`, should have been TimeType. They'll get it fixed, call Microsoft Support if you can't wait. – Hans Passant Jun 21 '17 at 02:32
  • That's the plain _ftime64 function in the code above. – Michaël Roy Jun 21 '17 at 02:41
  • Here: https://github.com/HowardHinnant/date is a cross-platform date/time library that does not have the 2038 bug. Runs on VS-2015. I used it to catch your copy/paste fail. Might be useful for you, might not, you decide. – Howard Hinnant Jun 21 '17 at 03:25
  • Maybe you have `_USE_32BIT_TIME_T` defined by some way. – Andre Kampling Jun 21 '17 at 14:50
  • @HansPassant the interesting thing is the regression from vc120 that hasn't been caught yet. I will have to contact support as this bug causes major problems and doesn't pass contractual tests to guarantee functionality past 2038! How best to contact them? I wonder how many pieces of software being written right now will be in use in 2038 and fail unexpectedly (hopefully not many). – syplex Jun 21 '17 at 18:13
  • @AndreKampling _USE_32BIT_TIME_T is not defined. – syplex Jun 21 '17 at 18:14
  • It ought to be a bit obvious that nobody is using this. There just isn't much point in using these deprecated posix functions with their non-deprecated name, given that you have to type the underscore. You might as well use the standard C library function and get it over with. – Hans Passant Jun 21 '17 at 18:18
  • @HansPassant it doesn't seem to matter which version of ftime I call, it has the same result. What function do you think should be used instead? – syplex Jun 21 '17 at 18:27
  • The standard C library function, time(). time_t is a 64-bit type in the Microsoft CRT. – Hans Passant Jun 21 '17 at 18:31
  • @HansPassant we need time in milliseconds, time() is in seconds. – syplex Jun 21 '17 at 18:42
  • Do you need local time, or UTC? `system_clock::now()` will give you time since 1970-01-01 UTC in 1/10 microsecond precision, which you can then easily truncate (or round) to milliseconds, e.g. with `time_point_cast(system_clock::now())`. – Howard Hinnant Jun 21 '17 at 20:27
  • @HowardHinnant thanks. It looks like system_clock::now() isn't specified as UTC in the documentation. I do need time in UTC. Also this function is C++11, so I won't be able to use it across all supported platforms at this time, but I may still be able to use it in Windows. – syplex Jun 21 '17 at 22:41
  • It's true that the `system_clock` epoch is unspecified. I'm trying to get it specified (https://howardhinnant.github.io/date/d0355r3.html#time.clock.system), and I have the unofficial assurance of the std::lib implementors that they will not move off of this de facto standard in the interim. – Howard Hinnant Jun 21 '17 at 23:26

1 Answers1

3

After opening an issue with Microsoft Visual Studio support, they have confirmed this as a bug with Universal CRT that can be fixed by using an updated Windows SDK that is slated to release alongside Windows 10 Redstone 3 (aka Fall Creators Update). An updated UCRT will also be released alongside RS3.

Update 2018/05/08: The Fall Creator's Update (1709) fixed this for applications linking dynamically against the CRT (/MD and /MDd). But in order to fix this when linking statically against the CRT (/MT and /MTd), you must change the Target Platform Version to 10.0.16299.0 (or later) and rebuild the application.

The internal bug ID is: DevDiv.436129 , 437701

Workaround options:
GetSystemTime(SYSTEMTIME *lpSystemTime)
SystemTimeToFileTime(const SYSTEMTIME *lpSystemTime, FILETIME *lpFileTime)

Requires Windows 8 or above:
GetSystemTimePreciseAsFileTime(FILETIME *lpSystemTimeAsFileTime)

Convert SYSTEMTIME to FILETIME
SYSTEMTIME starts in year 1601 while time_t usually starts in year 1970. To convert to time_t you have to account for the difference in seconds between 1601 and 1970 (See: Convert Windows Filetime to second in Unix/Linux)

syplex
  • 1,147
  • 6
  • 27
  • On the upside, the UCRT is shipped as part of the OS, so you don't need to update redistributable components that are bundled with your application. – zneak Jul 18 '17 at 19:23
  • But on the downside, you have to force the end-user to install UCRT on the target machine. Also, if you are linking statically against the runtime (which I am to work around UCRT not being installed on the target machine, ie, Windows 7) you have to update your software deployment to get the fix. – syplex Jul 18 '17 at 20:49