[C语言]日期间天数差值的计算
刷一些算法题时总能遇到计算日期间天数的问题,每每遇到这种情况,不是打开excel就是用系统自带的计算器。私以为这种问题及其简单以至于不需要自己动脑子,只要会调用工具就好。直到近些天在写一个日历程序的时候遇到了这个问题,不调用别人的API,那就只能自己动手了。
一、概述
天数计算问题的解法大致分为两类。一类是直接计算日期间的差值,另一类先是分别求得该日期到某一特殊时间点的差值,再两个差值相减得到两个日期间的差值。目前网络上大多都是第一类解法,直接从公元元年开始循环,简单粗暴。而另一种就较为少见了,得定义结构体等一系列繁琐的操作,结构较为臃肿。所以,如何在尽可能偷懒的情况下又使得代码变得优雅呢?在我试验过了多种不同的结构体后,我还是(无奈地)选择了<time.h>。
二、约束
此程序假定日期2018-1-1与日期2018-1-3的差值为一天。当然,为两天也没问题,在代码上做少量的改动就行[滑稽]。
三、关于<time.h>
作为C语言标准库里的时间和日期头文件,<time.h>也集成了一些简单、常用的类型及函数。虽然和JAVA等语言还是显得有些简陋,不过一个支点都能撬动地球,这点东西也够进行复杂的操作了。
类型:time_t 表示时间的算术类型(日历时间)
而time_t的定义:
- #ifndef _TIME_T_DEFINED
- #define _TIME_T_DEFINED
- #ifdef _USE_32BIT_TIME_T
- typedef __time32_t time_t;
- #else
- typedef __time64_t time_t;
- #endif
- #endif
__time32_t和__time64_t的定义:
- #ifndef _TIME32_T_DEFINED
- #define _TIME32_T_DEFINED
- typedef long __time32_t;
- #endif
- #ifndef _TIME64_T_DEFINED
- #define _TIME64_T_DEFINED
- __MINGW_EXTENSION typedef __int64 __time64_t;
- #endif
- #define __int64 long long
所以绕来绕去,time_t就是一个long类型的变量,记录的是从1970年1月1日00:00:00(UTC)开始,到目前为止经过的秒数,即日历时间。
类型:struct tm 用于保存组成日历时间各个部分的结构类型
日历的各个组成部分被称为分解时间(broken-down time)。
- #ifndef _TM_DEFINED
- #define _TM_DEFINED
- struct tm {
- int tm_sec; //分后的秒
- int tm_min; //小时后的分
- int tm_hour; //午夜后的小时
- int tm_mday; //月中的天
- int tm_mon; //一月后的月数
- int tm_year; //1900年后的年数
- int tm_wday; //星期日以后的天数
- int tm_yday; //一月一日后的天数
- int tm_isdst; //夏令时标志
- };
- #endif
函数:time_t mktime(struct tm *tmptr) 将tmptr指向的分解时间转换为日历时间
四、思路
在获得两组正确的时间后,分别求该日期所对应的日历时间,再相减,除以一天的秒数,即得到天数差值。
主要模块:
- 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 main (void)
- {
- char str[2][11];
- int second = 0;
- int day = 0;
- do
- {
- for(int i = 0;i<2;i++)
- {
- printf("Please input a date,like xxxx xx xx:(%d/2)\n",i+1);
- gets(str[i]);
- }
- }while(review((const char(*)[11])str)==false);
- second = timeparse((const char(*)[11])str);
- second = second>0?second:-second;
- day = second/24/3600;
- printf("day = %d\n",day-1);
- return 0;
- }
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.头文件的导入及宏
- #include <stdio.h>
- #include <time.h>
- #include <stdbool.h>
- #define MIN_YEAR 1900
2.日期的输入及验证
用个一do…while()结构接受日期,直到日期正确跳出循环。review函数对输入的日期进行验证,年份不得小于1900,天数得在该月所有天数内。对闰月的验证在天数验证的模块内。因为只需要看日期是否合法,所以并不用纠结日期内有几个闰月。
- int month_day[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
- char str[2][11];
- do
- {
- for(int i = 0;i<2;i++)
- {
- printf("Please input a date,like xxxx xx xx:(%d/2)\n",i+1);
- gets(str[i]);
- }
- }while(review((const char(*)[11])str)==false);
- bool review(const char str[][11])
- {
- int arr[2][3];
- int flag = 0;
- for(int i = 0;i<2;i++)
- {
- sscanf(str[i],"%d %d %d",&arr[i][0],&arr[i][1],&arr[i][2]);
- }
- for(int i = 0;i<2;i++)
- {
- if(arr[i][0]<MIN_YEAR)
- flag += error(i,0);
- if(arr[i][1]>12 || arr[i][1]<1)
- flag += error(i,1);
- if(arr[i][2]>month_day[arr[i][1]])
- {
- if((arr[i][0]%4==0 && arr[i][0]%100!=0) || arr[i][0]%400==0)
- if(arr[i][1]==2 && arr[i][2]==month_day[arr[i][1]]+1)
- continue;
- flag += error(i,2);
- }
- }
- if(flag==0)
- return true;
- else
- return false;
- }
- int error(int i,int result)
- {
- char arr[3][20] = {
- "年份错误",
- "月份错误",
- "天数错误"
- };
- printf("第%d个日期%s\n",i+1,arr[result]);
- return 1;
- }
3.日期的计算
timeparse()得到两个日期间相差的秒数,再对秒数做处理(转为天数)。
- int second = 0;
- int day = 0;
- second = timeparse((const char(*)[11])str);
- second = second>0?second:-second;
- day = second/24/3600;
- printf("day = %d\n",day-1);
toTime_t()求得一个日期的日历时间(s)。
- int timeparse(const char str[][11])
- {
- int year,month,day;
- int s[2];
- for(int i = 0;i<2;i++)
- {
- sscanf(str[i],"%d %d %d",&year,&month,&day);
- s[i] = (int)toTime_t(year,month,day);
- }
- return s[0]-s[1];
- }
- time_t toTime_t(int year,int month,int day)
- {
- struct tm ti = {0};
- ti.tm_year = year - 1900;
- ti.tm_mon = month -1;
- ti.tm_mday = day;
- return mktime(&ti);
- }
六、总结
总共100行的代码,日期检验的子函数就占了40行,还有很大的优化空间。并且受制于time_t的特性,该程序并不能计算1900年前的日期,不具有通用性。另外关于相邻日期间隔几天的不同定义,在主函数的输出里做了处理,如果认为1-1与1-3相隔两天的话,把-1去掉就行。

[C语言]日期间天数差值的计算的更多相关文章
- [Xcode 实际操作]九、实用进阶-(4)计算两个日期间的差值
目录:[Swift]Xcode实际操作 本文将演示如何计算两个日期之间的差值. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class ...
- js计算两个日期的天数差值
js计算两个日期的天数差值 通过两个日期计算这两个日期之间的天数差值 /** * 计算天数差的函数,通用 * @param sDate1 * @param sDate2 * @returns {Num ...
- C#中如何获得两个日期之间的天数差 ( c# 计算两个日期之间相差的天数 )
DateTime dtLast = new DateTime(Convert.ToInt32(LastMenses.Year), Convert.ToInt32(LastMenses.Month), ...
- javascript 计算两个日期的差值
代码 Typescript版 /** * TimeSpan just like the class TimpSpan in C# ,represent the time difference * @c ...
- Java 两个日期间的天数计算
在Java中计算两个日期间的天数,大致有2种方法:一是使用原生JDK进行计算,在JDK8中提供了更为直接和完善的方法:二是使用第三方库. 1.使用原生的JDK private static long ...
- Oracle计算两天两个日期间相差的天数
Oracle计算两天两个日期间相差的天数: select to_date('19930411','yyyymmdd')-to_date('19890507','yyyymmdd') from dual ...
- C 语言实例 - 计算两个时间段的差值
C 语言实例 - 计算两个时间段的差值 C 语言实例 C 语言实例 计算两个时间段的差值. 实例 #include <stdio.h> struct TIME { int seconds; ...
- JS循环解决任意日期间的间隔天数
用JS循环解决任意日期间的间隔天数,并求截止日期是周几 y1=1900 m1=1 d1=1 y2=2000 m2=5 d2=3 days=0 ydays=0 mdays=0 ddays=d2-d1 f ...
- Jquery计算时间戳之间的差值,可返回年,月,日,小时等
/** * 计算时间戳之间的差值 * @param startTime 开始时间戳 * @param endTime 结束时间戳 * @param type 返回指定类型差值(year, month, ...
随机推荐
- 【转发】在SQL Server中通过字段值查询存储该字段的表
-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved. -- Purpose: To search all colu ...
- Javascript设计模式理论与实战:简单工厂模式
通常我们创建对象最常规的方法就是使用new关键字调用构造函数,这会导致对象之间的依赖性.工厂模式是一种有助于消除类之间依赖性的设计模式,它使用一个方法来决定要实例化哪一个类.本文详细介绍了简单工厂模式 ...
- c# 线程的基本使用
创建线程 线程的基本操作 线程和其它常见的类一样,有着很多属性和方法,参考下表: 创建线程的方法有很多种,这里我们先从thread开始创建线程 class Program { static void ...
- 打开win8及以上操作系统的系统已安装程序目录
Windows 8 的“Metro 界面”里不能像XP和Win7那样,点击“开始”->“程序”,显示系统所有安装的程序,这个功能还是非常有用的,可以帮助我们快速查看系统已经安装的程序!我编写了这 ...
- shell、cmd、dos和脚本语言区别和联系
问题一:DOS与windows中cmd区别 在windows系统中,“开始-运行-cmd”可以打开“cmd.exe”,进行命令行操作. 操作系统可以分成核心(kernel)和Shell(外壳)两部 ...
- php—Smarty-1 (18)
smarty 一.模板原理 1. 为什么使用模板 1) 场景: ;$i<$count;$i++){ echo ‘<td>’.$row[‘proname’].’</td> ...
- python 将列表嵌套字典的unicode字符串转换为str格式的字符串的方法
今天在进行django开发的过程中遇到了一个非常棘手的问题, 因为需求原因, 需要将一份数据存为json格式到数据库中, 如下面这种格式: list_1 = [{"name":&q ...
- 为IEnumerable类型添加Add方法
IEnumerable类型原生是没有Add方法的,你可以用Contact方法去为它添加元素, 1 items = items.Concat(new[] { "foo" }); 也可 ...
- 理解 atime,ctime,mtime (上)
理解 atime,ctime,mtime (上) Unix文件系统会为每个文件存储大量时间戳.这意味着您可以使用这些时间戳来查找任意时间访问到的任何文件或目录(读取或写入),更改(文件访问权限更改)或 ...
- 挂载U盘到linux中
一. 挂载U盘到linux中,也可以是虚拟机中的linux 1. 首先插上U盘 2. fdisk -l 找到自己的U盘设备,并且记住文件系统类型,主要看空间大小来判断,比如是/dev/sdc ...