相信积累的力量

windows,data time

 

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(&lt);
  
  wprintf(L"The local time is: %02d:%02d:%02d\n", 
    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(&lt);

The GetLocalTime() retrieves the current local date and time. It fills the members of the SYSTEMTIMEstructure with current date & time values.

wprintf(L"The local time is: %02d:%02d:%02d\n", 
  lt.wHour, lt.wMinute, lt.wSecond);

We print the current local time in the hh:mm:ss format.

C:\winapi\examples2\datetime\LocalTime>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\n", 
    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\n", 
  st.wHour, st.wMinute, st.wSecond);

The UTC time is printed to the console in the hh:mm:ss format.

C:\winapi\examples2\datetime\SystemTime>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\n", 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\n", st.wYear, st.wMonth, st.wDay);

The current date is printed to the console. We have chosen the Gregoriand big-endian date format.

C:\winapi\examples2\datetime\Today>Today.exe
Today is: 2012-10-07

Output of the program.

Determining a leap year

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\n", years[i]);
    } else {
      wprintf(L"%ld is not a leap year\n", 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\n", years[i]);
  } else {
    wprintf(L"%ld is not a leap year\n", 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:\winapi\examples2\datetime\LeapYear>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\n", 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:\winapi\examples2\datetime\Uptime>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\n", 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\n", dn[st.wDayOfWeek]);

These lines retrieve and print the current day of the week.

C:\winapi\examples2\datetime\WeekDay>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 FILETIMEstructure 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\n", 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 LowPartand 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\n", hns);

The value is printed to the console.

C:\winapi\examples2\datetime\Epoch>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\n (%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\n", days2xmas);
  } else if (days2xmas == 0) {
    wprintf(L"Today is Chritmas");
  } else {
    wprintf(L"There are %d days until Christmas\n", 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 FILETIMESYSTEMTIME 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:\winapi\examples2\datetime\DaysToXMas>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\n (%d)", 
      GetLastError());
    return 1;
  }
  
  bool r2 = SystemTimeToFileTime(&st2, &ft2);

  if (!r2) {
    wprintf(L"Failed to convert system time to file time\n (%d)", 
      GetLastError());
    return 1;
  }
    
  short ct = CompareFileTime(&ft1, &ft2);

  if (ct == -1) {
    wprintf(L"4/12/2012 comes before 5/12/2012\n");
  } else if (ct == 0) {
    wprintf(L"4/12/2012 is equal to 5/12/2012\n");
  } else if (ct == 1) {
    wprintf(L"4/12/2012 comes after 5/12/2012\n");
  }

  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\n (%d)", 
    GetLastError());
  return 1;
}

bool r2 = SystemTimeToFileTime(&st2, &ft2);

if (!r2) {
  wprintf(L"Failed to convert system time to file time\n (%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\n");
} else if (ct == 0) {
  wprintf(L"4/12/2012 is equal to 5/12/2012\n");
} else if (ct == 1) {
  wprintf(L"4/12/2012 comes after 5/12/2012\n");
}

Depending on the returned value, we print a message.

C:\winapi\examples2\datetime\CompareTime>CompareTime.exe
4/12/2012 comes before 5/12/2012

Output.

In this part of the Winapi tutorial, we have worked with date & time.

posted @ 2013-08-17 20:29  ThreeF  阅读(365)  评论(0编辑  收藏  举报

相信积累的力量