WinAPI - simple operations with datetime

原创 2007年10月10日 15:22:00

Introduction

When I started to use WinAPI datetime - I found many classes and several functions, but didn't find an explanation for simple operations with datetime. I describe here two operations:

  1. Difference between two datetimes (datetime2-datetime1) and receiving weeks, days, hours, elapsed between them.
  2. Add/Subtract weeks, days, hours, to/from datetime and receiving new datetime.

With WinAPI we receive more then 29 thousand years for manipulation (start from 01.01.1601). To be more exact - 0x8000000000000000 100-nanoseconds intervals == from zero  [01 Jan 1601, 00:00:00] to 0x800...-1 [14 sep 30828, 02:48:05] where (1 sec = 1.000.000.000 nanoseconds)

WinAPI has two structs to store datetime - FILETIME and SYSTEMTIME. It was a surprise for me but SYSTEMTIME is only representation of datetime and for real operations with datetime we need to use FILETIME. (why did Microsoft title it FILE ? where is the logic ?)

SYSTEMTIME

Why do I say that SYSTEMTIME is only a representation?  Look at this:

typedef struct  _SYSTEMTIME
    {
    WORD wYear;
    WORD wMonth;
    WORD wDayOfWeek;
    WORD wDay;
    WORD wHour;
    WORD wMinute;
    WORD wSecond;
    WORD wMilliseconds;
    } SYSTEMTIME;

What do you see? Right - nothing says to us that SYSTEMTIME is ONLY a representation. But if you receive datetime to SYSTEMTIME:

SYSTEMTIME st;
GetSystemTime (&st);
and make such operation as add 100 days:
st.wDay += 100;
and than try to receive string representation of this new date:
GetDateFormat
 (
  LOCALE_USER_DEFAULT,
  NULL,
  &st,
  "yyyy MM dd",
  buff,     /*char buff[20];*/
  20
 );

You receive nothing. GetLastError returns number of error, GetDateFormat return 0. Of course, if you assign to wDay number valid for wMonth, you receive expected result (example - for Feb 2003 valid days from 1 to 28, if you assign wDay=29 you receive nothing). So, conclusion - SYSTEMTIME is not for above mentioned operations.

Ok, let us move to FILETIME. FILETIME contains two DWORD variables:

typedef struct  _FILETIME
    {
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
    } FILETIME;

Two DWORDs allow FILETIME to store 64 bit values. Value of FILETIME is equal to number of 100-nanosecond intervals since 01 Jan 1601, 00:00:00. So, if (FILETIME == 0) than we have 01 Jan 1601, 00:00:00. If (FILETIME == 10000000*60*60*24) we have 02 Jan 1601, 00:00:00.
(1 sec = 10000000 (100 nanoseconds) - in one min 60 secs, in one hour 60 mins and in one day 24 hours :)

64 bit value means that we can store 0xFFFFFFFFFFFFFFFF intervals ! But manipulate only 0x800..., in two times less. This restriction is superimposed by FileTimeToSystemTime. Read help:

The FileTimeToSystemTime function only works with FILETIME values that are less than 0x8000000000000000.


I think internals of this function use double (for convert to store double we need SIGNED __int64), and we lose 1 bit to sign, and receive in two times less max value. But I think it is not a tragedy :) - 29 thousand is enough.

Go to algorithms

Collapse
/*declare const that represent week,day,hour,minute,second*/

const __int64 nano100SecInWeek=(__int64)10000000*60*60*24*7;
const __int64 nano100SecInDay=(__int64)10000000*60*60*24;
const __int64 nano100SecInHour=(__int64)10000000*60*60;
const __int64 nano100SecInMin=(__int64)10000000*60;
const __int64 nano100SecInSec=(__int64)10000000; 
  
/*1. Diffence BETWEEN two datetime 
////////////
//equivalent of DATEDIFF function from SQLServer
//Returns the number of date and time boundaries crossed 
//between two specified dates. 
////////////*/
double     /* return count of period between pst1 and pst2*/
DT_PeriodsBetween
 (
 const __int64 datepart, /*datepart that we want to count, 
      {nano100SecInDay ...}*/
 const SYSTEMTIME* pst1, /*valid datetime*/
 const SYSTEMTIME* pst2  /*valid datetime*/
 )
{
 FILETIME ft1,ft2;
 __int64 *pi1,*pi2;
 
 /*convert SYSTEMTIME to FILETIME
 //SYSTEMTIME is only representation, so need convert to 
 //FILETIME for make some calculation*/
 SystemTimeToFileTime (pst1,&ft1);
 SystemTimeToFileTime (pst2,&ft2); 
 /*convert FILETIME to __int64
 //FILETIME is struct with two DWORD, for receive 
 //ability calculation we must reference to FILETIME as to int*/
 pi1 = (__int64*)&ft1;
 pi2 = (__int64*)&ft2; 
 /*compare two datetimes and (bigger date - smaller date)/period*/
 return (CompareFileTime(&ft1,&ft2)==1) ? 
    (((*pi1)-(*pi2))/(double)datepart) : (((*pi2)-(*pi1))/(double)datepart);
} 
  
/*2. Add/Subtract weeks,days,hours... to/from datetime 
    //and receiving new datetime. 
////////////
//equivalent of DATEADD function from SQLServer
//Returns a new datetime value based on adding an interval
// to the specified date.
////////////*/
SYSTEMTIME /*new datetime*/
DT_AddDiff
 (
 const __int64 datepart, /*datepart with we want to manipulate, 
    {nano100SecInDay ...}*/
 const __int64 num, /*value used to increment/decrement datepart*/
 const SYSTEMTIME* pst /*valid datetime which we want change*/
 )
{
 FILETIME ft;
 SYSTEMTIME st;
 __int64* pi; 

 SystemTimeToFileTime (pst,&ft); 
 pi = (__int64*)&ft; 
 (*pi) += (__int64)num*datepart; 

 /*convert FAILETIME to SYSTEMTIME*/
 FileTimeToSystemTime (&ft,&st); 

 /*now, st contain new valid datetime, so return it*/
 return st;
} 

SAMPLE use of functions

 /*1*/
 SYSTEMTIME s1={2003,11,0,28,12/*hours*/,0,0,0},s2={2003,12,0,1,0,0,0,0};
 printf("%f/n",DT_PeriodsBetween(nano100SecInDay,&s1,&s2));
 /*2*/
 char buff[100];
 s1=DT_AddDiff(nano100SecInDay,-1,&s2); //diff 1 day from s2
 
 /*WinAPI function GetDateFormat uses for receive string with 
   datetime in specifid format*/
 GetDateFormat
 (
  LOCALE_USER_DEFAULT,
  NULL,
  &s1,
  "yyyy MM dd", //my format
  buff,
  100
 );
 printf("20031201 - 1 day = %s/n",buff);
 
 

These functions can't be used for work with month, quarter, year because it they are not constants. For work with such time intervals you need to modify the above algorithms.

About AlexeyU


Alexey Utkin

Click here to view AlexeyU's online profile.

 

c++利用winapi实现简单多线程

#include #include #include using namespace std; DWORD WINAPI FUN1Proc(LPVOID lpParameter); //线程函数入...
  • u011575841
  • u011575841
  • 2016年11月10日 15:33
  • 1572

winapi消息大全

这几天一直在搞winapi 搞得头昏脑胀,找到了个消息大全感觉蛮好的,在此贴出: //////////////////////////////////////////////////////////...
  • xsg_BK
  • xsg_BK
  • 2015年09月18日 09:28
  • 1261

在函数前面加上WINAPI、CALLBACK

一直搞不懂为什么在函数前面加上WINAPI、CALLBACK等是什么意思 又不是返回值 为什么加在前面 今天终于知道了这是一个呼叫声明(姑且称之吧)。 引子: 看看这个函数: int PASCA...
  • qq_28098067
  • qq_28098067
  • 2016年01月26日 19:59
  • 1525

C语言中的一些winapi函数!

这篇文章,我将从最基本的开始谈起。但希望可以涉及更广的层面,而不仅仅是为你的程序除错(debug)。你将会看到,我认为除错(debugging)这个字的全部意义,并不只是通过ide的内建机制来运行的。...
  • u012402926
  • u012402926
  • 2015年10月23日 10:22
  • 456

2016年中国大学生程序设计竞赛(杭州) F Four Operations(暴力枚举)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5938 Four OperationsTime Limit: 2000/1000 MS (Java/O...
  • qq_32866009
  • qq_32866009
  • 2016年10月31日 10:35
  • 278

最简单的Windows窗口程序,使用main函数,隐藏控制台等,适合window编程入门

#include #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) //隐藏控制台用,注掉后...
  • fg5823820
  • fg5823820
  • 2013年11月22日 05:41
  • 3217

[WinAPI] 获取窗口句柄的几种方法

http://www.cnblogs.com/zjutlitao/p/3889900.html 1、使用FindWindow函数获取窗口句柄 示例:使用FindWindow函数获取窗口...
  • dszgf5717
  • dszgf5717
  • 2017年03月01日 14:57
  • 813

黑客常用WinAPI函数整理

黑客常用WinAPI函数整理   之前的博客写了很多关于Windows编程的内容,在Windows环境下的黑客必须熟练掌握底层API编程。为了使读者对黑客常用的Windows API有个更全面...
  • Chinamming
  • Chinamming
  • 2014年02月08日 21:25
  • 908

WinAPI编程入门笔记

今天写的这篇文章的主要意图就是给winAPI编程实践的一个小小的启发; 因为winAPI编程时,我们用到很多的函数都是带有很多的参数,而且有时要进行相应的强制类型转换,所以熟悉常用的一些类型是非常重...
  • fucumt
  • fucumt
  • 2013年01月27日 22:30
  • 9851

定时式获取鼠标处xy坐标和窗口对象(winapi)

看了一下.hook比较麻烦.反正弄个小东西,就使用了这个方式;  #include /* * ini解析模块 * 下载地址:http://ndevilla.free.fr/iniparser/ * 使...
  • qidizi
  • qidizi
  • 2013年04月09日 21:06
  • 652
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WinAPI - simple operations with datetime
举报原因:
原因补充:

(最多只允许输入30个字)