Date & time
In this part of the Windows API tutorial, we will work with date and time.
The SYSTEMTIME
structure is used to work with date and time in Windows API. The time can be either coordinated universal time (UTC) or local time. It has the following members:
WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds;
The SYSTEMTIME
structure is filled either with the GetSystemTime()
function or the GetLocalTime()
function. We can then access the members of the structure to get the current date or time.
The FILETIME
structure contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). With this value we are able to compute the Windows API epoch or the datetime differences.
DWORD dwLowDateTime; DWORD dwHighDateTime;
The FILETIME
structure has two members. The dwLowDateTime
is the low-order part of the file time. And the dwHighDateTime
is the high-order part of the file time. To get a single value from the two members, we utilize the LARGE_INTEGER
union.
The FileTimeToSystemTime()
and the SystemTimeToFileTime()
functions are used to convert between the two structures.
Local time
Local time is defined as the current time in the user's time zone.
#include <windows.h> #include <wchar.h> int wmain(void) { SYSTEMTIME lt; GetLocalTime(<); wprintf(L"The local time is: %02d:%02d:%02d ", lt.wHour, lt.wMinute, lt.wSecond); return 0; }
The program prints the local time.
SYSTEMTIME lt;
We declare the SYSTEMTIME
structure. The members of this structure are filled by calling a specific time function.
GetLocalTime(<);
The GetLocalTime()
retrieves the current local date and time. It fills the members of the SYSTEMTIME
structure with current date & time values.
wprintf(L"The local time is: %02d:%02d:%02d ", lt.wHour, lt.wMinute, lt.wSecond);
We print the current local time in the hh:mm:ss format.
C:winapiexamples2datetimeLocalTime>LocalTime.exe The local time is: 13:23:19
Sample output.
UTC time
Our planet is a sphere. It revolves round its axis. The Earth rotates towards the east. So the Sun rises at different times in different locations. The Earth rotates once in about 24 hours. Therefore, the world was divided into 24 time zones. In each time zone, there is a different local time. This local time is often further modified by the daylight saving.
There is a pragmatic need for one global time. One global time helps to avoid confusion about time zones and daylight saving time. The UTC (Universal Coordinated time) was chosen to be the primary time standard. UTC is used in aviation, weather forecasts, flight plans, air traffic control clearances and maps. Unlike local time, UTC does not change with a change of seasons.
The Windows API has the GetSystemTime()
function to get the UTC time.
#include <windows.h> #include <wchar.h> int wmain(void) { SYSTEMTIME st; GetSystemTime(&st); wprintf(L"The system time is: %02d:%02d:%02d ", st.wHour, st.wMinute, st.wSecond); return 0; }
In the example we compute the UTC time.
SYSTEMTIME st;
The UTC time will be stored in the SYSTEMTIME
structure.
GetSystemTime(&st);
We retrive the UTC time using the GetSystemTime()
function.
wprintf(L"The system time is: %02d:%02d:%02d ", st.wHour, st.wMinute, st.wSecond);
The UTC time is printed to the console in the hh:mm:ss format.
C:winapiexamples2datetimeSystemTime>SystemTime.exe The system time is: 21:11:13
Output.
Date
The GetLocalTime()
function is also used to determine the current date.
#include <windows.h> #include <wchar.h> int wmain(void) { SYSTEMTIME st; GetLocalTime(&st); wprintf(L"Today is: %d-%02d-%02d ", st.wYear, st.wMonth, st.wDay); return 0; }
The above program prints today's date.
SYSTEMTIME st;
We declare a SYSTEMTIME
structure.
GetLocalTime(&st);
We fill the SYSTEMTIME
members with current local time and date values.
wprintf(L"Today is: %d-%02d-%02d ", st.wYear, st.wMonth, st.wDay);
The current date is printed to the console. We have chosen the Gregoriand big-endian date format.
C:winapiexamples2datetimeToday>Today.exe Today is: 2012-10-07
Output of the program.
Determining a leap year
A leap year is a year containing an additional day. The reason for an extra day in the calendar is the difference between the astronomical and the calendar year. The calendar year has exactly 365 days, while the astronomical year, the time for the earth to make one revolution around the Sun, is 365.25 days. The difference is 6 hours which means that in four years time we are missing one day. Because we want to have our calendar synchronized with the seasons, we add one day to February each four years. (There are exceptions.) In the Gregorian calendar, February in a leap year has 29 days instead of the usual 28. And the year lasts 366 days instead of the usual 365.
#include <windows.h> #include <stdbool.h> #include <wchar.h> bool isLeapYear(int); int wmain(void) { int years[] = { 2000, 2002, 2004, 2008, 2012, 1900, 1800, 1600, 1200, 1000 }; int size = sizeof(years)/sizeof(int); for (int i=0; i<size; i++) { if (isLeapYear(years[i])) { wprintf(L"%ld is a leap year ", years[i]); } else { wprintf(L"%ld is not a leap year ", years[i]); } } return 0; } bool isLeapYear(int year) { if ((year % 100 == 0) && (year % 400 == 0)) { return true; } if ((year % 4 == 0) && (year % 100 !=0)) { return true; } return false; }
We have an array of years. We check all years if they are leap years or not. There is no built-in function to check for a leap year. We have created a custom isLeapYear()
function.
int years[] = { 2000, 2002, 2004, 2008, 2012, 1900, 1800, 1600, 1200, 1000 };
This is an array of years that we will check.
for (int i=0; i<size; i++) { if (isLeapYear(years[i])) { wprintf(L"%ld is a leap year ", years[i]); } else { wprintf(L"%ld is not a leap year ", years[i]); } }
With the for loop we traverse the array. We check if a year is a leap year using the isLeapYear()
function.
bool isLeapYear(int year) { if ((year % 100 == 0) && (year % 400 == 0)) { return true; } if ((year % 4 == 0) && (year % 100 !=0)) { return true; } return false; }
This is the function for determining a leap year. Leap years are integer multiples of 4. A year that is an integer multiple of 100 is not a leap year, unless it is also an integer multiple of 400, in which case it is also a leap year.
C:winapiexamples2datetimeLeapYear>LeapYear.exe 2000 is a leap year 2002 is not a leap year 2004 is a leap year 2008 is a leap year 2012 is a leap year 1900 is not a leap year 1800 is not a leap year 1600 is a leap year 1200 is a leap year 1000 is not a leap year
Output of the LeapYear.exe program.
Uptime
The GetTickCount()
function can be used to get the uptime of a computer. It retrieves the number of milliseconds that have elapsed since the system has started.
DWORD WINAPI GetTickCount(void);
The function returns a DWORD value, so the maximum number of days returned is 49.7. To get over this limitation, we can use the GetTickCount64()
. (Available from Windows Vista).
#include <windows.h> #include <wchar.h> int wmain(void) { DWORD tc = GetTickCount(); short seconds = tc / 1000 % 60; short minutes = tc / 1000 / 60 % 60; short hours = tc / 1000 / 60 / 60 % 24; short days = tc / 1000 / 60 / 60 / 24 % 7; short weeks = tc / 1000 / 60 / 60 / 24 / 7 % 52; wprintf(L"Computer has been running for: "); if (weeks > 0 && weeks != 1) { wprintf(L"%hi weeks ", weeks); } else if (weeks == 1) { wprintf(L"1 week "); } if (days > 0 && days != 1) { wprintf(L"%hi days ", days); } else if (days == 1) { wprintf(L"1 day "); } if (hours > 0 && hours != 1) { wprintf(L"%hi hours ", hours); } else if (hours == 1) { wprintf(L"1 hour "); } if (minutes > 0 && minutes != 1) { wprintf(L"%hi minutes ", minutes); } else if (minutes == 1) { wprintf(L"1 minute "); } wprintf(L"and %hi seconds ", seconds); return 0; }
The program prints the uptime of a computer. We use the GetTickCount()
function. It works correctly if the computer is running less than 49.71 days or 4294967296 ms. After that the DWORD value overflows.
DWORD tc = GetTickCount();
We get the number of milliseconds the computer is running. The maximum number a DWORD variable can store is ULONG_MAX
.
short seconds = tc / 1000 % 60; short minutes = tc / 1000 / 60 % 60; short hours = tc / 1000 / 60 / 60 % 24; short days = tc / 1000 / 60 / 60 / 24 % 7; short weeks = tc / 1000 / 60 / 60 / 24 / 7 % 52;
We compute the seconds, minutes, hours, days and weeks.
if (weeks > 0 && weeks != 1) { wprintf(L"%hi weeks ", weeks); } else if (weeks == 1) { wprintf(L"1 week "); }
If the computer is running one or more weeks, we either print the weeks variable or "1 week" string to the console.
C:winapiexamples2datetimeUptime>Uptime.exe Computer has been running for: 3 hours 31 minutes and 7 seconds
Sample output.
Day of week
The wDayOfWeek
member of the SYSTEMTIME
structure stores the day of the week. The values are 1..7 where 1 is Sunday, 2 Monday,... 7 Saturday.
#include <windows.h> #include <wchar.h> int wmain(void) { SYSTEMTIME st; wchar_t *dn[] = {L"Sunday", L"Monday", L"Tuesday", L"Wednesday", L"Thursday", L"Friday", L"Saturday"}; GetLocalTime(&st); wprintf(L"Today is %ls ", dn[st.wDayOfWeek]); return 0; }
The code prints the current day of the week to the console.
wchar_t *dn[] = {L"Sunday", L"Monday", L"Tuesday", L"Wednesday", L"Thursday", L"Friday", L"Saturday"};
We store the names of the days in a string array.
GetLocalTime(&st); wprintf(L"Today is %ls ", dn[st.wDayOfWeek]);
These lines retrieve and print the current day of the week.
C:winapiexamples2datetimeWeekDay>WeekDay.exe Today is Tuesday
Output.
The epoch
An epoch is an instant in time chosen as the origin of a particular era. For example in western Christian countries the time epoch starts from day 0, when Jesus was born (is believed to be born). Another example is the French Republican Calendar which was used for twelve years. The epoch was the beginning of the Republican Era which was proclaimed on September 22, 1792, the day the First Republic was declared and the monarchy abolished. Computers have their epochs too. One of the most popular is the Unix time. The Unix epoch is the time 00:00:00 UTC on 1 January 1970 (or 1970-01-01T00:00:00Z ISO 8601). The date and time in a computer is determined according to the number of seconds or clock ticks that have elapsed since the defined epoch for that computer or platform.
Windows operating system has several epochs. Microsoft Excel, MS SQL Server or FAT32 filesystem have different time epochs. The Windows API epoch is January 1, 1601, 00:00:00 UTC. The reason for choosing this date was the 400th anniversary of accepting of the Gregorian calendar. The anniversary falled at the time when Windows NT was designed. The FILETIME
structure contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
#include <windows.h> #include <wchar.h> int wmain(void) { FILETIME ft; GetSystemTimeAsFileTime(&ft); LARGE_INTEGER li; li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; long long int hns = li.QuadPart; wprintf(L"%lli hundreds of nanoseconds have elapsed " "since Windows API epoch ", hns); return 0; }
The code example computes the number of 100-nanosecond intervals elapsed from the Windows API epoch till this moment.
FILETIME ft;
We declare the FILETIME
structure. It has two members. The dwLowDateTime
holds the low-order part of the file time. The dwHighDateTime
holds the high-order part of the file time.
LARGE_INTEGER li;
The LARGE_INTEGER
is a union which helps us to convert the members of the FILETIME
structure to 100-nanosecond intervals.
li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime;
The values of the FILETIME
structure are copied to the large integer union members.
long long int hns = li.QuadPart;
The QuadPart
member stores the number of hundreds of nanoseconds determined from the LowPart
and HighPart
members. It is a huge number stored as a 64-bit integer.
wprintf(L"%lli hundreds of nanoseconds have elapsed " "since Windows API epoch ", hns);
The value is printed to the console.
C:winapiexamples2datetimeEpoch>Epoch.exe 129939979517540965 hundreds of nanoseconds have elapsed since Windows API epoch
Sample output.
Days until XMas
The Windows API does not have any functions to calcuate the difference between two days. We have to do the math ourselves.
#include <windows.h> #include <stdbool.h> #include <wchar.h> int wmain(void) { FILETIME ft1; FILETIME ft2; SYSTEMTIME st = {0}; LARGE_INTEGER li1; LARGE_INTEGER li2; st.wYear = 2012; st.wMonth = 12; st.wDay = 25; bool r = SystemTimeToFileTime(&st, &ft1); if (!r) { wprintf(L"Failed to convert system time to file time (%d)", GetLastError()); return 1; } GetSystemTimeAsFileTime(&ft2); li1.LowPart = ft1.dwLowDateTime; li1.HighPart = ft1.dwHighDateTime; li2.LowPart = ft2.dwLowDateTime; li2.HighPart = ft2.dwHighDateTime; long long int dif = li1.QuadPart - li2.QuadPart; int days2xmas = dif / 10000000L / 60 / 60 / 24; if (days2xmas == 1) { wprintf(L"There is one day until Christmas ", days2xmas); } else if (days2xmas == 0) { wprintf(L"Today is Chritmas"); } else { wprintf(L"There are %d days until Christmas ", days2xmas); } return 0; }
The code example computes the number of days until the Christmas.
FILETIME ft1; FILETIME ft2; SYSTEMTIME st = {0}; LARGE_INTEGER li1; LARGE_INTEGER li2;
We need FILETIME
, SYSTEMTIME
structures and LARGE_INTEGER
unions to do our computations.
st.wYear = 2012; st.wMonth = 12; st.wDay = 25;
The SYTEMTIME
structure is filled with the values for the Christmas day.
bool r = SystemTimeToFileTime(&st, &ft1);
The system time for the Christmas day is converted to file time.
GetSystemTimeAsFileTime(&ft2);
We get the current date as a file time using the GetSystemTimeAsFileTime()
function.
li1.LowPart = ft1.dwLowDateTime; li1.HighPart = ft1.dwHighDateTime; li2.LowPart = ft2.dwLowDateTime; li2.HighPart = ft2.dwHighDateTime;
We fill the two unions with the low-order and high-order parts of the file time.
long long int dif = li1.QuadPart - li2.QuadPart;
The difference between the two dates is computed.
int days2xmas = dif / 10000000L / 60 / 60 / 24;
The difference is expressed in 100-nanoseconds. This value is converted to days.
C:winapiexamples2datetimeDaysToXMas>DaysToXMas.exe There are 79 days until Christmas
Output.
Comparing times
The CompareFileTime()
function can be used to compare two file times. The function returns -1 when the first time specified is earlier. It returns 0, when the two times are equal. And it returns 1 when the first time is later than the second file time.
#include <windows.h> #include <stdbool.h> #include <wchar.h> int wmain(void) { SYSTEMTIME st1 = {0}; SYSTEMTIME st2 = {0}; FILETIME ft1; FILETIME ft2; st1.wYear = 2012; st1.wMonth = 4; st1.wDay = 12; st2.wYear = 2012; st2.wMonth = 5; st2.wDay = 12; bool r1 = SystemTimeToFileTime(&st1, &ft1); if (!r1) { wprintf(L"Failed to convert system time to file time (%d)", GetLastError()); return 1; } bool r2 = SystemTimeToFileTime(&st2, &ft2); if (!r2) { wprintf(L"Failed to convert system time to file time (%d)", GetLastError()); return 1; } short ct = CompareFileTime(&ft1, &ft2); if (ct == -1) { wprintf(L"4/12/2012 comes before 5/12/2012 "); } else if (ct == 0) { wprintf(L"4/12/2012 is equal to 5/12/2012 "); } else if (ct == 1) { wprintf(L"4/12/2012 comes after 5/12/2012 "); } return 0; }
We define two times. We use the CompareFileTime()
to figure out which time is earlier than the other one.
st1.wYear = 2012; st1.wMonth = 4; st1.wDay = 12; st2.wYear = 2012; st2.wMonth = 5; st2.wDay = 12;
The two times are defined.
bool r1 = SystemTimeToFileTime(&st1, &ft1); if (!r1) { wprintf(L"Failed to convert system time to file time (%d)", GetLastError()); return 1; } bool r2 = SystemTimeToFileTime(&st2, &ft2); if (!r2) { wprintf(L"Failed to convert system time to file time (%d)", GetLastError()); return 1; }
The system times are converted to file times using the SystemTimeToFileTime()
function calls.
short ct = CompareFileTime(&ft1, &ft2);
The two file times are compared with the CompareFileTime()
function.
if (ct == -1) { wprintf(L"4/12/2012 comes before 5/12/2012 "); } else if (ct == 0) { wprintf(L"4/12/2012 is equal to 5/12/2012 "); } else if (ct == 1) { wprintf(L"4/12/2012 comes after 5/12/2012 "); }
Depending on the returned value, we print a message.
C:winapiexamples2datetimeCompareTime>CompareTime.exe 4/12/2012 comes before 5/12/2012
Output.
In this part of the Winapi tutorial, we have worked with date & time.