刷一些算法题时总能遇到计算日期间天数的问题,每每遇到这种情况,不是打开excel就是用系统自带的计算器。私以为这种问题及其简单以至于不需要自己动脑子,只要会调用工具就好。直到近些天在写一个日历程序的时候遇到了这个问题,不调用别人的API,那就只能自己动手了。

一、概述

天数计算问题的解法大致分为两类。一类是直接计算日期间的差值,另一类先是分别求得该日期到某一特殊时间点的差值,再两个差值相减得到两个日期间的差值。目前网络上大多都是第一类解法,直接从公元元年开始循环,简单粗暴。而另一种就较为少见了,得定义结构体等一系列繁琐的操作,结构较为臃肿。所以,如何在尽可能偷懒的情况下又使得代码变得优雅呢?在我试验过了多种不同的结构体后,我还是(无奈地)选择了<time.h>。

二、约束

此程序假定日期2018-1-1与日期2018-1-3的差值为一天。当然,为两天也没问题,在代码上做少量的改动就行[滑稽]。

三、关于<time.h>

作为C语言标准库里的时间和日期头文件,<time.h>也集成了一些简单、常用的类型及函数。虽然和JAVA等语言还是显得有些简陋,不过一个支点都能撬动地球,这点东西也够进行复杂的操作了。

    类型:time_t    表示时间的算术类型(日历时间)

而time_t的定义:

  1.     #ifndef _TIME_T_DEFINED  
  2. #define _TIME_T_DEFINED  
  3. #ifdef _USE_32BIT_TIME_T  
  4.   typedef __time32_t time_t;  
  5. #else  
  6.   typedef __time64_t time_t;  
  7. #endif  
  8. #endif  

__time32_t和__time64_t的定义:

  1. #ifndef _TIME32_T_DEFINED  
  2. #define _TIME32_T_DEFINED  
  3.   typedef long __time32_t;  
  4. #endif  
  5.     
  6. #ifndef _TIME64_T_DEFINED  
  7. #define _TIME64_T_DEFINED  
  8.   __MINGW_EXTENSION typedef __int64 __time64_t;  
  9. #endif  
    1. #define __int64 long long

      所以绕来绕去,time_t就是一个long类型的变量,记录的是从1970年1月1日00:00:00(UTC)开始,到目前为止经过的秒数,即日历时间。

      类型:struct tm    用于保存组成日历时间各个部分的结构类型

日历的各个组成部分被称为分解时间(broken-down time)。

  1. #ifndef _TM_DEFINED  
  2. #define _TM_DEFINED  
  3.   struct tm {  
  4.     int tm_sec;     //分后的秒   
  5.     int tm_min;     //小时后的分   
  6.     int tm_hour;    //午夜后的小时   
  7.     int tm_mday;    //月中的天   
  8.     int tm_mon;     //一月后的月数   
  9.     int tm_year;    //1900年后的年数   
  10.     int tm_wday;    //星期日以后的天数   
  11.     int tm_yday;    //一月一日后的天数   
  12.     int tm_isdst;   //夏令时标志   
  13.   };  
  14. #endif  

    函数:time_t mktime(struct tm *tmptr)    将tmptr指向的分解时间转换为日历时间

四、思路

在获得两组正确的时间后,分别求该日期所对应的日历时间,再相减,除以一天的秒数,即得到天数差值。

主要模块:

  1. bool review(const char str[][11]);  
  2. int error(int i,int result);  
  3. int timeparse(const char str[][11]);  
  4. time_t toTime_t(int year,int month,int day);  
  5.     
  6. int main (void)  
  7. {  
  8.     char str[2][11];  
  9.     int second = 0;  
  10.     int day = 0;  
  11.     do  
  12.     {  
  13.         for(int i = 0;i<2;i++)  
  14.         {  
  15.             printf("Please input a date,like xxxx xx xx:(%d/2)\n",i+1);  
  16.             gets(str[i]);  
  17.         }  
  18.     }while(review((const char(*)[11])str)==false);  
  19.         
  20.     second = timeparse((const char(*)[11])str);  
  21.     second = second>0?second:-second;  
  22.     day = second/24/3600;  
  23.     printf("day = %d\n",day-1);  
  24.         
  25.     return 0;     
  26. }  
bool review(const char str[][11]);     //对输入日期进行验证
int error(int i,int result);            //日期错误信息提示
int timeparse(const char str[][11]);    //对输入日期进行解析,为运算的主要函数
time_t toTime_t(int year,int month,int day);     //被int timeparse()调用,得到具体日历时间的子函数

五、实现

1.头文件的导入及宏

  1. #include <stdio.h>  
  2. #include <time.h>   
  3. #include <stdbool.h>  
  4. #define MIN_YEAR 1900  

2.日期的输入及验证

用个一do…while()结构接受日期,直到日期正确跳出循环。review函数对输入的日期进行验证,年份不得小于1900,天数得在该月所有天数内。对闰月的验证在天数验证的模块内。因为只需要看日期是否合法,所以并不用纠结日期内有几个闰月。

  1. int month_day[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};  
  2. char str[2][11];  
  3.     
  4. do  
  5. {  
  6.     for(int i = 0;i<2;i++)  
  7.     {  
  8.         printf("Please input a date,like xxxx xx xx:(%d/2)\n",i+1);  
  9.         gets(str[i]);  
  10.     }  
  11. }while(review((const char(*)[11])str)==false);  
    1. bool review(const char str[][11])  
    2. {  
    3.     int arr[2][3];  
    4.     int flag = 0;  
    5.         
    6.     for(int i = 0;i<2;i++)  
    7.     {  
    8.         sscanf(str[i],"%d %d %d",&arr[i][0],&arr[i][1],&arr[i][2]);  
    9.     }  
    10.         
    11.     for(int i = 0;i<2;i++)  
    12.     {  
    13.         if(arr[i][0]<MIN_YEAR)  
    14.             flag += error(i,0);  
    15.         if(arr[i][1]>12 || arr[i][1]<1)  
    16.             flag += error(i,1);  
    17.         if(arr[i][2]>month_day[arr[i][1]])  
    18.         {  
    19.             if((arr[i][0]%4==0 && arr[i][0]%100!=0) || arr[i][0]%400==0)  
    20.                 if(arr[i][1]==2 && arr[i][2]==month_day[arr[i][1]]+1)  
    21.                     continue;  
    22.             flag += error(i,2);  
    23.         }  
    24.     }  
    25.     
    26.     if(flag==0)   
    27.         return true;  
    28.     else  
    29.         return false;  
    30. }  
    31.     
    32. int error(int i,int result)  
    33. {  
    34.     char arr[3][20] = {  
    35.         "年份错误",  
    36.         "月份错误",  
    37.         "天数错误"  
    38.     };  
    39.     printf("第%d个日期%s\n",i+1,arr[result]);  
    40.         
    41.     return 1;  
    42. }  

      3.日期的计算

      timeparse()得到两个日期间相差的秒数,再对秒数做处理(转为天数)。

  12. int second = 0;  
  13. int day = 0;  
  14.     
  15. second = timeparse((const char(*)[11])str);  
  16. second = second>0?second:-second;  
  17. day = second/24/3600;  
  18. printf("day = %d\n",day-1);  

    toTime_t()求得一个日期的日历时间(s)。

  19. int timeparse(const char str[][11])  
  20. {  
  21.     int year,month,day;  
  22.     int s[2];  
  23.     for(int i = 0;i<2;i++)  
  24.     {  
  25.         sscanf(str[i],"%d %d %d",&year,&month,&day);  
  26.         s[i] = (int)toTime_t(year,month,day);  
  27.     }  
  28.         
  29.     return s[0]-s[1];  
  30. }  
  31.     
  32. time_t toTime_t(int year,int month,int day)  
  33. {  
  34.     struct tm ti = {0};  
  35.     ti.tm_year = year - 1900;  
  36.     ti.tm_mon = month -1;  
  37.     ti.tm_mday = day;  
  38.         
  39.     return mktime(&ti);  
  40. }  

六、总结

总共100行的代码,日期检验的子函数就占了40行,还有很大的优化空间。并且受制于time_t的特性,该程序并不能计算1900年前的日期,不具有通用性。另外关于相邻日期间隔几天的不同定义,在主函数的输出里做了处理,如果认为1-1与1-3相隔两天的话,把-1去掉就行。

[C语言]日期间天数差值的计算的更多相关文章

  1. [Xcode 实际操作]九、实用进阶-(4)计算两个日期间的差值

    目录:[Swift]Xcode实际操作 本文将演示如何计算两个日期之间的差值. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class ...

  2. js计算两个日期的天数差值

    js计算两个日期的天数差值 通过两个日期计算这两个日期之间的天数差值 /** * 计算天数差的函数,通用 * @param sDate1 * @param sDate2 * @returns {Num ...

  3. C#中如何获得两个日期之间的天数差 ( c# 计算两个日期之间相差的天数 )

    DateTime dtLast = new DateTime(Convert.ToInt32(LastMenses.Year), Convert.ToInt32(LastMenses.Month), ...

  4. javascript 计算两个日期的差值

    代码 Typescript版 /** * TimeSpan just like the class TimpSpan in C# ,represent the time difference * @c ...

  5. Java 两个日期间的天数计算

    在Java中计算两个日期间的天数,大致有2种方法:一是使用原生JDK进行计算,在JDK8中提供了更为直接和完善的方法:二是使用第三方库. 1.使用原生的JDK private static long  ...

  6. Oracle计算两天两个日期间相差的天数

    Oracle计算两天两个日期间相差的天数: select to_date('19930411','yyyymmdd')-to_date('19890507','yyyymmdd') from dual ...

  7. C 语言实例 - 计算两个时间段的差值

    C 语言实例 - 计算两个时间段的差值 C 语言实例 C 语言实例 计算两个时间段的差值. 实例 #include <stdio.h> struct TIME { int seconds; ...

  8. JS循环解决任意日期间的间隔天数

    用JS循环解决任意日期间的间隔天数,并求截止日期是周几 y1=1900 m1=1 d1=1 y2=2000 m2=5 d2=3 days=0 ydays=0 mdays=0 ddays=d2-d1 f ...

  9. Jquery计算时间戳之间的差值,可返回年,月,日,小时等

    /** * 计算时间戳之间的差值 * @param startTime 开始时间戳 * @param endTime 结束时间戳 * @param type 返回指定类型差值(year, month, ...

随机推荐

  1. Java Web系列:JAAS认证和授权基础

    1.认证和授权概述 (1)认证:对用户的身份进行验证. .NET基于的RBS(参考1)的认证和授权相关的核心是2个接口System.Security.Principal.IPrincipal和Syst ...

  2. asp.net——XML格式导出Excel

    下面介绍一种导出Excel的方法: 此方法不需要在服务器上安装Excel,采用生成xml以excel方式输出到客户端,可能需要客户机安装excel,所以也不会有乱七八糟的权限设定,和莫名其妙的版本问题 ...

  3. 在.net中创建Access数据库

    static void Main(string[] args) { //环境要求 //安装 access 2003, //引用com组件:Microsoft ADO Ext. 2.8 for DDL ...

  4. mac下MySQL Workbench安装

    参见:http://www.cnblogs.com/macro-cheng/archive/2011/10/25/mysql-001.html 去mysql官网下载社区的.dmg安装包 分别安装: 分 ...

  5. 回去看linux的指令1

    SYNC CL : MSM8953 @ CL#:12212299 PROJECT PATH : // Platform / N / NILE / COMBINATION / MSM8953 Cross ...

  6. springmvc执行流程 源码分析

    进入DispatcherServlet 执行onRefresh,然后执行初始化方法initStrategies.然后调用doService——>doDispatch. 根据继承关系执行Servl ...

  7. 正则表达式的Wed验证应用(40)

    电子邮件地址的校验 <?php /* 校验邮件地址*/ function checkMail($email) { //用户名,由“\w”格式字符.“-”或“.”组成 $email_name= & ...

  8. Spring Boot启动过程(六):内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动

    看代码有助于线上出现预料之外的事的时候,不至于心慌... StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程 ...

  9. 利用PHP的curl批量导出文件

    场景 1.需要从网站中导出大量的文件,包括有图片格式,文档格式等附件内容. 2.分文件夹来导出不同的数据 <?php header("Content-Type:text/html;ch ...

  10. tomcat运行springboot项目war包

    以最简单的spring boot demo项目来演示如何发布项目war包到tomcat,并成功运行(有很多小伙伴会出现404错误) 一.准备一个最简单的demo项目 在IDEA中新建一个项目,一直ne ...