vb6 日期控件 bug_VC++不为人所知的时间编程Bug

VC++ 的MFC对时间的处理函数类,主要有两对:CTime和CTimeSpan与COleDateTime和COleDateTimeSpan。笔者在使用中,发现其在早期的VC++6.0版本中存在时间计算bug,如:计算2095年与2020年的时间间隔为负值,即 -1928125696秒,使得时光倒流。本文在此与大家分享微软VC++6.0 在使用CTime和CTimeSpan与COleDateTime和COleDateTimeSpan时出现的这个最大Bug。

1、先介绍VC++6.0的时间bug之一:用CTime类表示时间只能到2039年

CTime和CTimeSpan主要封装了ANSI time_t和关于time_t的Run-Time库的主要函数。CTime里面使用的成员变量是time_t类型,该类型是个long型:

#ifndef _TIME_T_DEFINED

typedef long time_t; /* time value */

#define _TIME_T_DEFINED /* avoid multiple def's of time_t */

#endif

由于long类型的原因,所以该类只能处理2的32次方16T的时间即:4294967296秒(16进制1 00 00 00 00H,long int是4个字节,32位)

约69年的数据,所以用CTime只能处理1970年到2039年的日期。

而在VS2010中,定义为64位长度的时间值:

#ifndef _TIME64_T_DEFINED

typedef __int64 __time64_t; /* 64-bit time value */

#define _TIME64_T_DEFINED

#endif

在VS2010中,定义为2的64次方秒,即16*1TB*1TB的大小,高枕无忧了。

2、用COleDateTimeSpan类计算时间间隔(单位为秒)

MFC同时提供了COleDateTime和COleDateTimeSpan类,使用该两个类完全可以代替CTime和CTimeSpan,COleDateTime和COleDateTimeSpan类所使用的成员变量是DATE类型,该类型是个double类型,而且使用的单位是日,所以可以处理到9999年12月31日的日期时间。

COleDateTimeSpan类是用于对COleDateTime类的两个时间的时间间隔的计算,COleDateTimeSpan类使用的成员变量COleDateTimeSpan::m_span是一个double类型是用于记录两个COleDateTime::m_dt的时间差,例如:

COleDateTime t1(2020,1,1,0,0,0);

COleDateTime t2(2040,1,1,0,0,0);

COleDateTimeSpan ts=t2-t1;

CString str;

str.Format("%f",ts.GetTotalSeconds());

AfxMessageBox(str);

此程序段在VC++6.0及VS2010上计算,结果一致,相当精准,如下图:

3150e45cda901459004aaaaf9a913cbe.png

3、这是不是意味着COleDateTimeSpan类的任何成员函数,执行程序都不会有问题呢?答案是否定的!

我们先分别在VC++6.0及VS2010上运行同一段程序,用2、的方法计算2095年与2020年的时间间隔,看看结果如何。

先在vc++6.0上做一按钮控件,执行如下程序段:

2ead46c06d2dd56ba97885baa3593909.png

这段程序在VC++6.0上进行运算输出结果是:-1928125696秒,这个结果明显是一个溢出。时光倒流!

计算结果截图如下:

a948522f09253767eb83c3db6ebb4d9f.png

同样一段程序,在VS2010上显示程序如下:

ee803677476af584b464f90c4fdf7f64.png

程序文本与VC++6.0的完全一样,但在VC2010上进行运算输出结果是:2366861600秒

75年,完美,非常正确的一个计算结果!

计算结果截图如下:

这到底是什么原因呢?

4、答案在COleDateTimeSpan类的成员GetTotalSeconds( )的原型定义上

VC++ 6.0 在使用COleDateTimeSpan类的GetTotalSeconds( )时,函数原型为:

double GetTotalSeconds( ) const;

返回值是double类型,但是,double GetTotalSeconds( ) const

在VC++ 6.0的MFC内部的原形定义却如下:

_AFXDISP_INLINE double COleDateTimeSpan::GetTotalSeconds() const

{

ASSERT(GetStatus() == valid);

long lReturns = (long)(m_span * 24 * 60 * 60 + AFX_OLE_DATETIME_HALFSECOND);

return lReturns;

}

哈哈!原因就出在返回的LONG上!与“1、时间bug之一”一样,计算大于69年的时间(单位为秒)间隔,时间差为负值!这是VC++ 6.0 MFC的又一个时间Bug!

幸好,微软在VS2010中作了改正。

在VS2010的时间定义文件 ATLCOMTIME.INL中,原型定义如下:

ATLCOMTIME_INLINE double COleDateTimeSpan::GetTotalSeconds() const throw()

{

ATLASSERT(GetStatus() == valid);

return (double)LONGLONG((m_span + (m_span < 0 ?

-OLE_DATETIME_HALFSECOND : OLE_DATETIME_HALFSECOND)) * (24 * 60 * 60));

}

很明显,在VS 2010中返回为double类型,double的定义为8个字节,是LONG的平方,可表示2的64次方。而在VC++ 6.0中,返回还是为long类。所以在使用函数GetTotalSeconds( )的时候,VC++ 6.0计算两个时间的间隔大于69年时就会溢出,VS 2010却安然无恙!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值