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.

 

No operations defined in spec!

spingmvc整合swagger,所有配置都完成了,而且没有错误,服务可以正常启动,但是页面一直是No operations defined in spec! 详细整合步骤请参考文章http://...
  • wang_shuyu
  • wang_shuyu
  • 2017-10-17 14:58:09
  • 1390

swagger的使用

最近需要使用swagger实现自动生成接口文档的功能。 首先就是疯狂百度呀,结果搞了一天没出来,遇到各种坑。 废话以后再说,先说我做出来的成果。 1、配置 项目采用java注解的方式配置,无x...
  • Gyb_csdn
  • Gyb_csdn
  • 2017-07-14 16:29:51
  • 3227

SpringMVC整合swagger

1:首先添加maven依赖的jar,网上有的只给出1-2个jar,但是实际上以下的jar都是需要的 com.mangofactory swagger-springmvc 1.0.2 com.m...
  • wang_shuyu
  • wang_shuyu
  • 2017-10-17 15:00:55
  • 810

Java 堆、栈、方法区的区别

Java的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)也叫静态存储区。 堆区: 1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(clas...
  • y534560449
  • y534560449
  • 2017-04-28 09:43:33
  • 203

hdu5938Four Operations

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5938 题意:给一个只含'1'~'9'的字符串,要求按顺序插入'+','-','*','/',求运算结果中...
  • Fsss_7
  • Fsss_7
  • 2016-11-01 15:35:12
  • 379

swagger与springMVC、maven整合

最近使用swagger自动生成api文档遇到了不少坑,网上有许多教程,但都并不能顺利运行。现自己整理了一份,以备之后用到时使用。 在这之前需要注意的几个问题: 1.jar包是否引用完整; 2.是否...
  • baidu_36720706
  • baidu_36720706
  • 2017-11-14 20:18:00
  • 474

Spring mvc + mybatis+maven集成swagger ui自动生成api文档

最近由于项目需要所以需要集成swagger-ui这货进行api文档自动生成的功能,才去研究了好久,当然也踩了很多坑,算是总结了一些经验,希望可以帮助需要的同学少走弯路吧!,...
  • kacherylau
  • kacherylau
  • 2017-09-20 13:32:38
  • 181

springMVC整合swagger(亲自试验完全可用)

swagger是什么: Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。本文简单介绍了在项目中集成swagger的方法和一些常见问题。如果想深入分析项目源码,了解更多内...
  • y534560449
  • y534560449
  • 2016-12-16 16:35:09
  • 18776

HDU5938-Four Operations

Four Operations                                                                            Time Lim...
  • a664607530
  • a664607530
  • 2017-07-02 13:57:34
  • 144

Spinlocks

From : www.makelinux.net/ldd3/chp-5-sect-5  Semaphores are a useful tool for mutual exclusion,but...
  • robertsong2004
  • robertsong2004
  • 2014-07-30 14:29:45
  • 631
收藏助手
不良信息举报
您举报文章:WinAPI - simple operations with datetime
举报原因:
原因补充:

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