某日在某个月份中不存在导致软件出现异常的问题排查(判断闰年以及月份中的天数,附完整源码)

目录

1、问题说明

2、日期不存在导致程序出现异常

3、判断某日在某月中是否存在

4、最后


       最近在开发支持多语言版本的新需求,对一个多年前开发的功能模块添加多语言支持,在测试时程序产生了异常。程序中因为没有判断查询日期的有效性,导致处理时间的C++类抛出异常,导致程序出异常。本文详细讲述一下这一问题的排查与解决过程,以供大家借鉴或参考。

C++软件异常排查从入门到精通系列教程(核心精品专栏,订阅量已达8000多个,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(重点专栏,专栏文章已更新500多篇,订阅量已达6000多个,欢迎订阅,持续更新中...)https://blog.csdn.net/chenlycly/article/details/140824370C++ 软件开发从入门到实战(重点专栏,专栏文章已更新300多篇,欢迎订阅,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_2276111.html

1、问题说明

       最近在对我们的软件添加多国语言的支持,在测试联调多年前实现的窗口时,出现了异常。负责开发的同事搞不清除是怎么回事,找到我,让我帮忙排查一下。

       出问题的是聊天消息查看窗口,支持查看多个时间段的聊天记录,比如最近一周、最近三个月、最近一年等:

当点击查看最近三个月聊天信息的按钮时,弹出了报错提示框:

点击重试按钮,代码中断如下的位置处:(遇到断言错误等报错提示框,直接点击重试按钮,代码就会跳转到问题代码处,这是基本的调试技巧,大家需要知道~

传入的月份数居然是137,明显是个异常值,于是报断言错误。 于是打开Visual Studio的函数调用堆栈窗口,根据异常发生时的函数调用堆栈,找到了出问题的代码,如下所示:

2、日期不存在导致程序出现异常

       根据异常时函数调用堆栈,问题发生在CTime类内部,查看传给CTime对象的SYSTEMTIME结构体数据中出现了异常的值,传入的月份值和日值都是非法值,是异常大的值!这是引发问题的直接原因。

       于是查看这段问题代码,看看COleDateTime对象返回的年月日时分秒的时间为啥会有问题。问题代码如下:

上述代码使用到了处理时间的COleDateTime和CTime类,将当天的年月日时间(2025-05-29)传给COleDateTime对象,然后获取年月日时分秒数,放到SYSTEMTIME结构体对象中,然后再把SYSTEMTIME对象传给CTime对象获取64位整型毫秒时间,然后使用该毫秒时间作为起始时间,以当前时间作为结束时间,到数据库中去查询这个时间段内的聊天记录。

       有点奇怪的是,这段代码是多年前写的,如果有问题,应该早就暴露出来了,为啥现在才出现呢?

       突然想到,今天到月底了,是5月29日,难道代码中去查询最近三个月的聊天记录时直接将月份减去3,得到2月29号,没有判断29号在今年2025年2月份是否存在?(当时写代码的同事,考虑问题不周全不严谨),进而将错误的年月日时间传给COleDateTime对象,导致COleDateTime对象处理时间时产生了异常?今年是2025年,不是闰年,所以今年(2025年)2月份是没有29号的,只有闰年的2月份才有29号,这肯定就是引发问题的原因了!

至于解析时间的COleDateTime类为什么解析时间失败,可以到deepseek中去搜索!

3、判断某日在某月中是否存在

       要查询最近三个月的聊天记录,在将今天的月份减去3之后得到三月前的月份,还要判断今天的日(当前出问题的是29号)在三月前的月份中是否存在!

       关于每个月份中有多少天的规则是这样的

1)除了2月份之外,其他月份的日数是固定的。如果年份是闰年,则2月份有29天;如果年份不是闰年,则2月份只有28天。
2)1月、3月、5月、7月、8月、10月和12月,都有31天。
3)4月、6月、9月、11月,都有30天。
4)对于2月份,如果年份是闰年,则有29天;如果年份不是闰年,则有28天。

        关于闰年的判断规则是这样的

1)能被4整除但不能被100整除的年份是闰年;
2)能被400整除的年份是闰年。

       所以,判断某日在某年某月中是否存在的实现代码如下:

// 是否是闰年
bool IsLeapYear(int year) {
    if (year % 4 != 0) return false;
    else if (year % 100 != 0) return true;
    else return (year % 400 == 0);
}

// 判断某年某月某日是否存在
bool IsValidDate(int year, int month, int day) {
    if (year < 1 || month < 1 || month > 12 || day < 1) {
        return false;
    }

    int maxDay;
    switch (month) {
    case 1: case 3: case 5: case 7: case 8: case 10: case 12:
        maxDay = 31;
        break;
    case 4: case 6: case 9: case 11:
        maxDay = 30;
        break;
    case 2:
        maxDay = IsLeapYear(year) ? 29 : 28;
        break;
    default:
        return false; // 月份无效
    }

    return day <= maxDay;
}

       要查询最近3个月的聊天记录,将当前日期中的月份减去3得到查询开始时间的月份,然后判断日在开始月份中是否存在考虑到当天的日可能是29、30和31,在某些月份中是不存在的,如果日不存在,则自减,直到目标月份中日存在为止,代码如下:

// 查询最近三个月的聊天记录,将今天日期中的月份减去3,获取起始时间
wMonth -= 3;
if ( wMonth <= 0 )
{
    wMonth += 12;
    --wYear;
}

// 上面wMonth减去3,要确认当前的Day在wMonth-3的月份中是否存在
WORD wTmpDay = systime.wDay;
bool bValid = IsValidDate(wYear, wMonth, wTmpDay);
while ( !bValid )
{
    wTmpDay--;
    bValid = IsValidDate(wYear, wMonth, wTmpDay);
}

        在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:该精品技术专栏的订阅量已达到10000多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,已经更新到200篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法详细讲述了C++软件的调试方法与手段详细介绍分析C++软件问题的常用分析工具,以图文并茂的方式给出具体的项目问题实战分析实例(详细讲述分析排查过程,很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,订阅量已达8000多个,专栏文章已经更新到500多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法C++11及以上新特性(开源代码中可能会用到很多新特性(比如WebRTC开源库),日常编码中也会用到部分新特性,面试时也会频繁地涉及到,学习新特性很有必要)、常用C++开源库的介绍与使用(比如SQLite、libcurl、libwebsockets、libevent、jsoncpp/RapidJson、Redis、RabbitMQ、MongoDB、MQTT、ZooKeeper、OpenCV、FFmpeg、SDL、GStreamer、Live555、ReactOS等)、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(引发C++软件异常的常见原因分析与总结、排查C++软件异常的手段与方法、分析C++软件异常的基础知识、使用常用软件分析工具分析C++软件问题、多个项目实战问题分析案例分享等)、设计模式(单例模式、工厂模式、观察者模式、状态模式等)、网络基础知识与网络问题分析进阶内容(实战问题分析实例分享)等。本专栏的内容都是建立在项目实践的基础上,来源于项目实战,服务于项目实战,很有实战参考价值!

专栏3:  

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795

常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏4:   

VC++常用功能开发汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/124272585

将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。

专栏5: 

C++ 软件开发从入门到精通(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.html

根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。


4、最后

       当前这个问题之所以之前没有暴露出来,是因为这个问题具有隐蔽性和时间上的耦合性。测试人员在测试这个功能时,可能不是月底;也可能即便是月底,但三个月之前凑巧是存在这个日期的。虽然当前是在开发联调软件的多语言支持功能,但无意中发现了软件中隐藏较深的bug,还是很不错的!

遇到问题时,不仅仅要解决问题,要下意识地进行发散性思考,想想出问题的可能场景,想想之前为什么在测试环境中没有出现过,要看看能否从问题中得到一些收获或启示!我们要养成多思考、多想想为什么的习惯!

       这个问题也说明了,软件在大部分时间段没问题,或者在公司环境中没问题,不代表软件所有的功能都是ok的,只是某些隐藏较深的bug在没有被触发时没暴露出来。

问题虽然简单,但从问题中获取到的思考和启发,是很有价值的!

       此外,这个问题对于有经验的开发人员,排查起来不难,但有一定的趣味性和启发性,还是有必要分享一下的,于是就撰写了本篇文章给大家分享了。

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dvlinker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值