GetDateFormat() fails on dates before 1/1/1601 - winapi

i am trying to format a date using Windows GetDateFormat API function:
nResult = GetDateFormat(
localeId, //0x409 for en-US, or LOCALE_USER_DEFAULT if you're not testing
0, //flags
dt, //a SYSTEMTIME structure
"M/d/yyyy", //the format we require
null, //the output buffer to contain string (null for now while we get the length)
0); //the length of the output buffer (zero while we get the length)
Now we pass it a date/time:
SYSTEMTIME dt;
dt.wYear = 1600;
dt.wMonth = 12;
dt.wDay = 31;
In this case nResult returns zero:
The function returns 0 if it does not succeed. To get extended error information, the application can call GetLastError, which can return one of the following error codes:
ERROR_INSUFFICIENT_BUFFER. A supplied buffer size was not large enough, or it was incorrectly set to NULL.
ERROR_INVALID_FLAGS. The values supplied for flags were not valid.
ERROR_INVALID_PARAMETER. Any of the parameter values was invalid.
If, however, i return a date one day later:
SYSTEMTIME dt;
dt.wYear = 1601;
dt.wMonth = 1;
dt.wDay = 1;
Then it works.
What am i doing wrong? How do i format dates?
e.g. the date of the birth of Christ:
12/25/0000
or the date when the universe started:
-10/22/4004 6:00 PM
or the date Caesar died:
-3/15/44
Bonus Reading
Sorting It All Out: GetDateFormat is Gregorian based
GetDateFormatEx function

This is actually a limitation on SystemTime.
...year/month/day/hour/minute/second/milliseconds value since 1 January 1601 00:00:00 UT... to 31 December 30827 23:59:59.999
I spent some time looking up how to get around this limitation, but since GetDateFormat() takes a SystemTime you'll probably have to bite the bullet and write your own format() method.

SYSTEMTIME struct is valid only from year 1601 through 30827, because in Windows machines, is system time counted from elapsed intervals from 1.1.1601 00:00. See
Wikipedia article.

Related

How to convert a hex TimeDateStamp DWORD value into human readable format?

Can anyone explain how to convert a Hex TimeDateStamp DWORD value into human readable format?
I'm just curious as to how a value such as 0x62444DB4 is converted into
"Wednesday, 30 March 2022 10:31:48 PM"
I tried googling of course and could not find any explanation. But there are online converters available.
But I'm just interested in converting these values for myself.
Your value is a 32-bit Timestamp.
Your datetime value is a 32-bit Unix Timestamp: The number of seconds since 1/1/1970.
See https://unixtime.org/
In most programming languages you can work with the hexadecimal notation directly.
Implementation should not be done by one person alone, since a lot of engineering goes into it. Leap years, even leap seconds, timezones, daylight savings time, UTC... all these things need to be addressed when working with a timestamp.
I have added my rough calculation below as a demonstration. Definitely use an existing package or library to work with timestamps.
See the JavaScript code below for demonstration.
There I multiply your value by 1000 because JavaScript works in Milliseconds. But otherwise this applies the same to other systems.
let timestamp = 0x62444DB4;
let dateTime = new Date(timestamp * 1000);
console.log('Timestamp in seconds:', timestamp);
console.log('Human-Readable:', dateTime.toDateString() + ' ' + dateTime.toTimeString());
// Rough output, just for the time.
// Year month and day get really messy with timezones, leap years, etc.
let hours = Math.floor(timestamp/3600) % 24;
let minutes = Math.floor(timestamp/60) % 60;
let seconds = Math.floor(timestamp) % 60;
console.log('Using our own time calculation:', hours + ':' + minutes + ':' + seconds);

Get time_t from microseconds in the past

Working on a c++ 11 function that returns a string from an epoch timestamp with millisecond resolution. Doing this with the current date seems straight forward:
auto currentTime = std::chrono::system_clock::now( );
const time_t time = std::chrono::system_clock::to_time_t( currentTime );
However, I'm having a hard time finding out to initialize without now() and instead using a timestamp from the past. Trying to do this using std library, but can't quite see how to initialize the time_point using a past timestamp.
How about using the std::chrono::duration class. Below is an example.
unsigned long noOfClockTicks = 10111111111; // Mar 16 10:31:59 2018
std::chrono::duration<unsigned long> duration(noOfClockTicks);
system_clock::time_point pastTime(duration);
Adjust noOfClockTicks to get the correct value you want or you can even calculate it from std::chrono::system_clock::now().

Subtract one second from given CTime

I am working on a VC++ project using MFC. There's a CTime object in my function that has a value of "10/11/2016 03:00:00".......something like that.
I want to subtract one second from the time part. So it will look like
"10/11/2016 02:59:59"
So for e.g., if the CTime value is "10/22/2016 07:45:50" then after subtraction by 1 second it should be "10/22/2016 07:45:49"
I tried,
CTime - 1, but this gives an error.
UPDATE:
I fixed this via,
time_t myTime= CTime.GetTime();
myTime= myTime - 1;
time_t gives the time in seconds and thus it's straight forward at this point.
To add or subtract to or from a CTime you need to use a CTimeSpan object to indicate the duration you want to add or subtract.
For example, to subtract a second:
CTime cNewTime = cOldTime - CTimeSpan(0, 0, 0, 1);

Why there is no inverse function for gmtime in libc?

In libc there are two functions to convert from system time to calendar time - gmtime and localtime, but only localtime has inverse function - mktime. Why there is no inverse function for gmtime, and if there shouldn't be any, why gmtime exists?
I've found this piece of code work satisfactorily:
namespace std {
time_t timegm(tm* _Tm)
{
auto t = mktime(_Tm);
return t + (mktime(localtime(&t)) - mktime(gmtime(&t)));
}
}
which satifies the test:
auto t1 = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto t2 = std::timegm(std::gmtime(&t1));
EXPECT_EQ(t1, t2);
To explain the existence of gmtime(), some context is required:
gmtime() will convert a timestamp representation (number of seconds since 1970-01-01 00:00:00) to broken-down time representation (aka, struct tm), assuming that the timestamp timezone is UTC:
The gmtime() function converts the calendar time timep to
broken-down time representation, expressed in Coordinated Universal
Time (UTC). It may return NULL when the year does not fit into an
integer. The return value points to a statically allocated struct
which might be overwritten by subsequent calls to any of the date
and time functions.
In the other hand, localtime() takes in consideration the [local] system timezone (including daylight saving):
The localtime() function converts the calendar time timep to
broken- down time representation, expressed relative to the user's
specified timezone. The function acts as if it called tzset(3) and
sets the external variables tzname with information about the
current timezone, timezone with the difference between Coordinated
Universal Time (UTC) and local standard time in seconds, and
daylight to a nonzero value if daylight savings time rules apply
during some part of the year.
Note that the number of seconds since 1970-01-01 00:00:00 differ from timezone to timezone (when it was 1970-01-01 00:00:00 in New York, it clearly wasn't in, for instance, Tokyo).
The mktime() converts a struct tm to a time_t value (number of seconds since 1970-01-01 00:00:00) based on the [local] system timezone, and should not be interpreted as the inverse of any particular function (such as localtime() or gmtime()), as the inverse term may be [wrongly] interpreted as a safe cross-system conversion:
The mktime() function converts a broken-down time structure,
expressed as local time, to calendar time representation. The
function ignores the values supplied by the caller in the tm_wday
and tm_yday fields. The value specified in the tm_isdst field informs
mktime() whether or not daylight saving time (DST) is in effect
for the time supplied in the tm structure: a positive value means DST
is in effect;
There is also a non-portable function (for GNU and BSD systems) called timegm(), which assumes a UTC timezone, such as gmtime() does.
References
Blockquoted text is retrieved from parts of release 3.74 of the Linux man-pages project.

mktime shifts a time by one hour

I faced with an interesting problem with mktime function. I use russian time zone (UTC+03:00) Волгоград, Москва, Санкт-Петербург (RTZ 2) / Volgograd, Moscow, Saint Petersburg/ and try to construct time_t for "7.01.2009 00:00:00"
tm localTM;
localTM.tm_sec = 0;
localTM.tm_min = 0;
localTM.tm_hour = 0;
localTM.tm_mday = 7;
localTM.tm_mon = 0;
localTM.tm_year = 109;
time_t t = mktime(&localTM);
After mktime execution date&time is changed to "6.01.2009 23:00:00".
I have no problems then I construct time for "06.01.2009 00:00:00" or "08.01.2009 00:00:00".
If I switch time zone to another one, I get no problems with "7.01.2009 00:00:00".
What can be a reason of this oddity, and how can I workaround the issue?
When performing conversion to time_t, mktime needs to guess if the input is DST (Daylight Saving Time) or not.
For that, tm.tm_isdst field is used. See from man mktime
tm_isdst A flag that indicates whether daylight saving time is in
effect at the time described. The value is positive if day-
light saving time is in effect, zero if it is not, and nega-
tive if the information is not available.
Since you do not initialize tm_isdst in your code, the default value (0) is used, making mktime think it's in NO-DST period.
To fix it in your code, simply add
localTM.tm_isdst = -1
Note - that logic is necessary as for some moments in time just the "wallclock" information stored in tm is not sufficient to determine the exact time.
And yes, the fact that the default behavior is like that is a bit messed up :)

Resources