Introduction
The C time routines such as time()
, 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 time_t
variable.
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)
{
LARGE_INTEGER li;
*pt*=SECS_TO_FT_MULT;
li.QuadPart=*pt;
pft->dwLowDateTime=li.LowPart;
pft->dwHighDateTime=li.HighPart;
}
static void FileTimeToT64(FILETIME *pft,t64 *pt)
{
LARGE_INTEGER li;
li.LowPart = pft->dwLowDateTime;
li.HighPart = pft->dwHighDateTime;
*pt=li.QuadPart;
*pt/=SECS_TO_FT_MULT;
}
static t64 FindTimeTBase(void)
{
t64 tbase;
SYSTEMTIME st;
FILETIME ft;
memset(&st,0,sizeof(st));
st.wYear=1970;
st.wMonth=1;
st.wDay=1;
SystemTimeToFileTime(&st, &ft);
FileTimeToT64(&ft,&tbase);
return tbase;
}
static void SystemTimeToT64(SYSTEMTIME *pst,t64 *pt)
{
FILETIME ft;
SystemTimeToFileTime(pst, &ft);
FileTimeToT64(&ft,pt);
*pt-=FindTimeTBase();
}
static void T64ToSystemTime(t64 *pt,SYSTEMTIME *pst)
{
FILETIME ft;
t64 t=*pt;
t+=FindTimeTBase();
T64ToFileTime(&t,&ft);
FileTimeToSystemTime(&ft,pst);
}
t64 time_64(t64 *pt)
{
t64 t;
SYSTEMTIME st;
GetSystemTime(&st);
SystemTimeToT64(&st,&t);
return t;
}
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.
History
- 30th July, 2003: First release
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.