The C time routines such as
localtime() etc. represent time as seconds from 1st January 1970. The variable type
time_t is defined as a 32 bit signed integer - to permit negative times for the seconds difference between two times.
This means that if you use them in a 32-bit build, then normally the maximum time that can be represented is Tue Jan 19 03:14:07 2038. This is the C language equivalent of the Y2K bug - but is far more easily solved. You just need to do a 64 bit build to solve it.
However, maybe you want to do a 32 bit build for 32 bit operating systems. Maybe also you want your program to work fine beyond 2038 without a new build, in case anyone uses it still in those days as a legacy app. Well - this library solves the problem. The Windows operating system uses 64 bit times internally (in a rather eccentric format of 100 nanosecond intervals from 1st January 1601). So it is just a matter of interfacing with those properly, to make a 64 bit version of the C routines for Windows.
It is suitable for use with MSVC or any compiler that supports the
__int64 data type. If your compiler has a native 64 bit integer type, but it has some other name, then you need to edit the source code accordingly.
I am a pure C programmer and haven't used
CTime, but maybe if you include this library, then
CTime will also behave as desired - or maybe more work needs to be done. Comments welcome from C++ programmers. Anyone interested in converting this library to C++?
Using the code
Include the source code time64.c or time64.cpp for C++ programs as part of your program. Place the header time64.h at the head of every file that uses the time routines. All your
time_t variables will now be
__int64. However, if you need to use them in other routines you can convert them to
UINT, which will still be valid until the end of this century and beyond. Particularly,
UINT could be used for file input and output.
That's all there is to it.
See it in action
The zip for download includes an MSVC project to make a tiny app, that just displays the current time. Test that to see how it works - but first a few warnings are in order. It may sometimes cause a few problems if you vary the calendar on your computer.
Some programs with 30 day trial periods can behave crankily if you change the system time - may tell you that the trial period is over even after you adjust the time back again - so make sure you have no such programs running when you do it.
Others may crash if you go beyond 2038. That's because
time_t has to be non negative for the Windows implementation of most of the time routines. If you call them with negative values you may get an access violation. See for instance Problems Running Windows Media Player 7 or 7.1 with a Date that Is Later than January 18, 2038
Others may behave strangely if you change the date. For instance, probably it is best to close your browser, in case its history folder gets confused. So, close anything that might be sensitive to the date before varying the calendar date to test this library. If in doubt, use Ctrl Alt + Delete and close everything there except Explorer.
Check out my Work Log program for an example of an app that uses this library.
Points of interest
This library uses the Windows
FILETIME file type, which is 64 bit and represents time in 100 nanosecond intervals since Jan 1 1601. So the task was to make a wrapper for this type which will let one work with a 64 bit
For an introduction to the various time routines used in Windows, see the CodeProject page Date and Time in C++.
The main point to bear in mind to read the code is that
FILETIME can't be used directly but has to be converted into an
__int64 variable before you can use arithmetical operations with it. Then the Windows equivalent of the
tm structure is
SYSTEMTIME. Most fields are the same but the month starts at 1 instead of 0, and the year in the
tm structure is shown as years since 1900 so you need to subtract 1900 to convert a
SYSTEMTIME to a
tm and add it to get back again.
Also to convert a
FILETIME to a
time_t then you need to subtract the number of seconds between 1st Jan 1601 and 1st Jan 1970. Luckily we can do that quite easily by making a
SYSTEMTIME for 1st Jan 1970 and then use the routine
SystemTimeToFileTime to find what this date is in seconds.
The 64 bit variable type for
time_t is called
t64 internally in the library. So that should be enough to follow the code. Here is the heart of it - where the various data types get inter-converted:
#define SECS_TO_FT_MULT 10000000
static void T64ToFileTime(t64 *pt,FILETIME *pft)
static void FileTimeToT64(FILETIME *pft,t64 *pt)
li.LowPart = pft->dwLowDateTime;
li.HighPart = pft->dwHighDateTime;
static t64 FindTimeTBase(void)
static void SystemTimeToT64(SYSTEMTIME *pst,t64 *pt)
static void T64ToSystemTime(t64 *pt,SYSTEMTIME *pst)
t64 time_64(t64 *pt)
Then we also need to do those conversions just mentioned, to get from
SYSTEMTIME to / from
tm. That is easy to do - I will leave it for you to look at the file in the zip, if you want more information.
- First release 30th July 2003