Page 1 of 1

Microsoft : Anybody Got The Time? Looks at time and provides a wrapper class for C++ Rate Topic: ***** 1 Votes

#1 Martyn.Rae  Icon User is offline

  • The programming dinosaur
  • member icon

Reputation: 540
  • View blog
  • Posts: 1,406
  • Joined: 22-August 09

Posted 17 March 2010 - 03:05 AM

Microsoft : Anybody Got The Time?

Introduction

Time is a very strange concept and Microsoft have made working with time even stranger. There are three ways of dealing with time when developing software for Windows. This tutorial introduces them to you and provides a C++ header file that supports the major functionality provided by them.

C/C++ Time

Most beginners are introduced to the time function very early on in their computing courses as it is in itself random enough to seed the pseudo-random number generator. This version of time is held as the number of seconds since midnight on the first of January 1970. It cannot represent dates or times before that point and cannot represent dates or times beyond the 31st December 3000 as it is held as a 64-bit unsigned integer (This is since the introduction of Visual Studio 2005). Details about the time management functions can be found here on MSDN. For C++ applications, you will need to include the ctime header file to access these routines.

System Time and File Time

System time provides a way of holding dates from the year 1601 through to the year 30827. The resolution for these date and time incarnations is 1 millisecond. For the File Time routines, the resolution is 100 nanoseconds so that provides very accurate representation. Routines exist to convert System Time to File Time and File Time to System Time. Details of these routines may be found here on MSDN.

Clock Ticks (Windows Time)

Windows time is the number of milliseconds since the system was last started. Details of there routines can be found here on MSDN.

High Performance Counters

Two routines exist that provide a very high resolution. The QueryPerformanceCounter routine returns a 64-bit value, which in itself, you cannot do very much with. The QueryPerformanceFrequency returns the resolution of the QueryPerformanceCounter value in ticks per second, so you always have to divide the value returned by the QueryPerformanceCounter routine by the QueryPerformanceFrequency value. An example of this has been included below.

LARGE_INTEGER start_time;
LARGE_INTEGER end_time;
LARGE_INTEGER frequency;
double time_taken;

...

  QueryPerformanceFrequency(&frequency);
  QueryPerformanceCounter(&start_time);

...

  QueryPerformanceCounter(&end_time);
  time_taken = ((double)end_time.QuadPart - (double)start_time.QuadPart))/(double)frequency.QuadPart;
  cout << "That took " << time_taken << " seconds" << endl;

...



System and File Time Wrapper Class

There is quite a choice of time representations that are on offer, and the method use chose to use for date and time representation is dependant on whether your code is going to be supported solely on the Windows platform, or on other platforms as well. To make the System and File API functions a little easier to handle in C++, I have written is a wrapper class, offering you most of the functionality you will need to use System and File Time routines. This is included at the end of the tutorial, but I will discuss it here.

The Time Class

This wrapper class allows you to get the system time or local time and get and set the year, month, day, hours, minutes, seconds and milliseconds. It should be noted however, that I have purposefully left out of this class an method for actually setting the system time as this requires administrator rights, and generally speaking is not something an application would so.

There are also methods for comparing two time classes, and adding and subtracting time from the class.

The Time Interval Class

This wrapper class allows you to obtain the time interval very accurately. Using the example given earlier, you would have:

    TimeInterval start;
    TimeInterval end;

    start.Mark();
    ...
    end.Mark();
    cout << "That took " << time_taken << " seconds" << endl;



The include file for the Time and TimeInterval wrapper classes

#ifndef __TIME_CLASSES_DEFINED__
#define __TIME_CLASSES_DEFINED__

#if defined (_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#ifndef _WINDOWS_
#include <Windows.h>
#endif

class Time {
    private:    SYSTEMTIME systemTime;
                FILETIME fileTime;
    public:     Time() { 
                    memset(&systemTime, 0, sizeof(SYSTEMTIME)); 
                    ::SystemTimeToFileTime(&systemTime, &fileTime);
                };
                Time(Time& time) { 
                    memcpy(this, &time, sizeof(Time)); 
                };
                void SystemTime() { 
                    ::GetSystemTime(&systemTime); 
                    ::SystemTimeToFileTime(&systemTime, &fileTime); 
                };
                void LocalTime() { 
                    ::GetLocalTime(&systemTime); 
                    ::SystemTimeToFileTime(&systemTime, &fileTime); 
                };
                int GetYear() { 
                    return systemTime.wYear; 
                };
                int GetMonth() { 
                    return systemTime.wMonth; 
                };
                int GetDay() { 
                    return systemTime.wDay; 
                };
                int GetHour() { 
                    return systemTime.wHour; 
                };
                int GetMinute() { 
                    return systemTime.wMinute; 
                };
                int GetSecond() { 
                    return systemTime.wSecond; 
                };
                int GetMilliseconds() { 
                    return systemTime.wMilliseconds; 
                };
                int GetDayOfWeek() { 
                    return systemTime.wDayOfWeek; 
                };
                const FILETIME& GetFileTime() { 
                    return fileTime; 
                };
                void SetTime(FILETIME& file_time) { 
                    fileTime.dwLowDateTime = file_time.dwLowDateTime; 
                    fileTime.dwHighDateTime = file_time.dwHighDateTime;
                     ::FileTimeToSystemTime(&fileTime, &systemTime);
               }
               void SetTime(SYSTEMTIME& system_time) { 
                    memcpy(&systemTime, &system_time, sizeof(SYSTEMTIME));
                    ::SystemTimeToFileTime(&systemTime, &fileTime);
                }
               void SetTime(time_t this_time) { 
                    long long long_time = Int32x32To64(this_time, 10000000) + 116444736000000000;
                    fileTime.dwLowDateTime = (DWORD) long_time;
                    fileTime.dwHighDateTime = long_time >>32;
                    ::FileTimeToSystemTime(&fileTime, &systemTime);
                }
                void SetYear(int year) { 
                    systemTime.wYear = year; 
                };
                void SetMonth(int month) { 
                    systemTime.wMonth = month;
                };
                void SetDay(int day) { 
                    systemTime.wDay = day;
                };
                void SetHour(int hour) { 
                    systemTime.wHour = hour; 
                };
                void SetMinute(int minute) { 
                    systemTime.wMinute = minute;
                };
                void SetSecond(int second) { 
                    systemTime.wSecond = second; 
                };
                void SetMilliseconds(int milliseconds) { 
                    systemTime.wMilliseconds = milliseconds; 
                };
                void SetDayOfWeek(int dayOfWeek) { 
                    systemTime.wDayOfWeek = dayOfWeek; 
                };
                bool operator ==(Time& thisTime) { 
                    return ::CompareFileTime(&fileTime, &thisTime.fileTime) == 0 ? true : false; 
                };
                bool operator !=(Time& thisTime) { 
                    return ::CompareFileTime(&fileTime, &thisTime.fileTime) == 0 ? false : true; 
                };
                bool operator <(Time& thisTime) { 
                    return ::CompareFileTime(&fileTime, &thisTime.fileTime) == -1 ? true : false; 
                };
                bool operator <=(Time& thisTime) { 
                    return ::CompareFileTime(&fileTime, &thisTime.fileTime) == 1 ? false : true; 
                };
                bool operator >(Time& thisTime) { 
                    return ::CompareFileTime(&fileTime, &thisTime.fileTime) == 1 ? true : false; 
                };
                bool operator >=(Time& thisTime) { 
                    return ::CompareFileTime(&fileTime, &thisTime.fileTime) == -1 ? false : true; 
                };
                unsigned long long operator -(Time& thisTime) { 
                    ULARGE_INTEGER start, end;
                    start.LowPart = fileTime.dwLowDateTime;
                    start.HighPart = fileTime.dwHighDateTime;
                    end.LowPart = thisTime.fileTime.dwLowDateTime;
                    end.HighPart = thisTime.fileTime.dwHighDateTime;
                    return end.QuadPart - start.QuadPart;
                };
                Time& operator -(unsigned long long seconds) { 
                    ULARGE_INTEGER this_time;
                    this_time.LowPart = fileTime.dwLowDateTime;
                    this_time.HighPart = fileTime.dwHighDateTime;
                    this_time.QuadPart -= (seconds*10000000);
                    fileTime.dwLowDateTime = this_time.LowPart;
                    fileTime.dwHighDateTime = this_time.HighPart;
                    ::FileTimeToSystemTime(&fileTime, &systemTime);
                    return *this;
                };
                void operator -=(unsigned long long seconds) { 
                    ULARGE_INTEGER this_time;
                    this_time.LowPart = fileTime.dwLowDateTime;
                    this_time.HighPart = fileTime.dwHighDateTime;
                    this_time.QuadPart -= (seconds*10000000);
                    fileTime.dwLowDateTime = this_time.LowPart;
                    fileTime.dwHighDateTime = this_time.HighPart;
                    ::FileTimeToSystemTime(&fileTime, &systemTime);
                };
                Time& operator +(unsigned long long seconds) { 
                    ULARGE_INTEGER this_time;
                    this_time.LowPart = fileTime.dwLowDateTime;
                    this_time.HighPart = fileTime.dwHighDateTime;
                    this_time.QuadPart += (seconds*10000000);
                    fileTime.dwLowDateTime = this_time.LowPart;
                    fileTime.dwHighDateTime = this_time.HighPart;
                    ::FileTimeToSystemTime(&fileTime, &systemTime);
                    return *this;
                };
                void operator +=(unsigned long long seconds) { 
                    ULARGE_INTEGER this_time;
                    this_time.LowPart = fileTime.dwLowDateTime;
                    this_time.HighPart = fileTime.dwHighDateTime;
                    this_time.QuadPart += (seconds*10000000);
                    fileTime.dwLowDateTime = this_time.LowPart;
                    fileTime.dwHighDateTime = this_time.HighPart;
                    ::FileTimeToSystemTime(&fileTime, &systemTime);
                };
};

class TimeInterval {
    private:    LARGE_INTEGER time;
                LARGE_INTEGER frequency;
    public:     TimeInterval() { time.QuadPart = 0; QueryPerformanceFrequency(&frequency); };
                inline void Mark() { QueryPerformanceCounter(&time); };
                double operator -(TimeInterval& thisTime) { 
                    return ((double)time.QuadPart - (double)thisTime.time.QuadPart)/(double)frequency.QuadPart; 
                };
};

#endif



Is This A Good Question/Topic? 0
  • +

Page 1 of 1