关于计算两日期之间经过多少天的超巧妙算法

首先声明:本文引自一博主原创博客

原创地址:https://blog.csdn.net/chinaeran/article/details/43601699

昨天呢,刚刚阅读了这个代码,大部分都还可以看懂,有一两个地方属实难懂,但细细思来,方知博主此代码超神奇。简直巧妙至极。

所以来细细解析一下此代码。

话不多说。我们先来看一下原文。

#include <stdio.h>
#include <stdlib.h>

int day_diff(int year_start, int month_start, int day_start
, int year_end, int month_end, int day_end)
{
int y2, m2, d2;
int y1, m1, d1;

m1 = (month_start + 9) % 12;
y1 = year_start - m1/10;
d1 = 365*y1 + y1/4 - y1/100 + y1/400 + (m1*306 + 5)/10 + (day_start - 1);

m2 = (month_end + 9) % 12;
y2 = year_end - m2/10;
d2 = 365*y2 + y2/4 - y2/100 + y2/400 + (m2*306 + 5)/10 + (day_end - 1);

return (d2 - d1);
}

int main(void)
{
printf("%d\n", day_diff(2015, 1, 1, 2015, 1, 8));
printf("%d\n", day_diff(2015, 1, 29, 2015, 2, 9));

return 0;
}

这里呢是原文代码。

可以看到非常简短,接下来,就让你真正见识到这个代码的巧妙之处。

接下来我们先来看一下楼主的解析

算法解析:

该算法总体思想是计算给定日期到 0年3月1日的天数,然后相减,获取天数的间隔。

m1 = (month_start + 9) % 12; 用于判断日期是否大于3月(2月是判断闰年的标识),还用于纪录到3月的间隔月数。

y1 = year_start - m1/10; 如果是1月和2月,则不包括当前年(因为是计算到0年3月1日的天数)。

d1 = 365*y1 + y1/4 - y1/100 + y1/400 + (m1*306 + 5)/10 + (day_start - 1);

其中 365*y1 是不算闰年多出那一天的天数,

y1/4 - y1/100 + y1/400  是加所有闰年多出的那一天,

(m2*306 + 5)/10 用于计算到当前月到3月1日间的天数,306=365-31-28(1月和2月),5是全年中不是31天月份的个数

(day_start - 1) 用于计算当前日到1日的间隔天数
————————————————

我们由简到繁,慢慢分析:

其中关于最后的  (day_start - 1)就不用多说了吧。

我们主要来讲讲没别的地方。

先来看这里:

d1 = 365*y1 + y1/4 - y1/100 + y1/400

本文思路在这在说一下:即计算每个日期距离0年三月一日的相差天数,在做差即得两日期之间天数。

好了言归正传所谓闰年四年一闰,百年不闰,四百又多一闰。

我们从0年3月一日开始算到我们输入哪一年的3月一日截止先计算整年的天数总和。

0年的二月已过。所以考虑从1年到截止年的闰年个数。

用y1/4算出可被4整除的年数,我们记为疑是闰年年数。后我们减去y1/100,去掉其中的不是闰年年数,但是由于四百年又多一闰所以我们又加上了y1/400;

这样就可以完美的算出所经过的年的总天数,关于这里的年数还涉及后面的(- m1/10)一项,这个我们后面来细细解答,这里是本文最巧妙的地方之一,,先留个悬念哈。

好了我们接着往下看。

m1 = (month_start + 9) % 12;

这个就比较巧妙了,需要与

(m1*306 + 5)/10和(- m1/10)两项结合来分析。这里就到了作者算法最为精妙的部分了,不得不说这个代码真的神奇。

OK,继续。来看(- m1/10),和m1 = (month_start + 9) % 12;的结合。

先来看,怎么样才能让余数大于10呢,1,2,这两个结果对吧。如果是m1大于10 的话呢,可知年数会减一。

简单点来说呢就是用计算年总天数的计算到当年3月一号的天数总和,

如果当年不到三月,即1,2月,我们就往前推一年,计算到上一年的3月一号的天数,

至于多出来的天数我们接着看,别急。

县来看如果是1,n那么结果就是10,

即为一月份,意思是距离上一年的3月一号过去了10个月,对吧,

即上一年的3,4,5,6,7,8,9,10,11,12

其中一共有多少天呢,其中3.5.7.8.10.11位31天每月。

即结果为30*10+6

带入 (m1*306 + 5)/10即得真的为306;是不是很神奇。

我们将这个公式一一带入算一下。

下面呢 ,我们先看m1.再看月份,再看天数。

2,,,,,余11,4,5,6,7,8,9,10,11,12,1对吧,带入刚好为337;

3,,,,,余00

4,,,,,余13带入得31

5,,,,,余二3,4带入61;

6,,,,,余三3,4,5带入92

7,,,,,余四3,4,5,6带入122

8.,,,,,余五3,4,5,6,7带入153

9,,,,,余六,3,4,5,6,7,8带入184

10,,,,,余七,3,4,5,6,7,8,9滴入214

11,,,,,余8,3,4,5,6,7,8,9,10带入245

12,,,,,余9,,3,4,5,6,7,8,9,10,11带入275

OK,是不是发现都对,是不是很神奇。

我也这样觉得,我来为大家分析其玄妙之处

先来分析月份问题。

随余数的增加月份为3  4  5  6  7  8  9  10  11  12  1

先来看为31天的月份有,3  5  7  8  9 10   12   1

看一下其中大部分30,31天的月份间隔,对吧,

简单看一下即可看出由于306后面的6的原因及后面5的作用下

我们把它稍微化简一下化为(m1*300+5+m1*6)/10

m1*300的我们直接滤掉

(5+6*m1)/10;

可以看到

1得1

2得1

3得2

最容易的得知的就是每加二回多一天即上面的初步规律30,31间隔出现

其中有两个特例,7到8,12到2

包含7,和7,8月份的余数分别为5,6

可以得出符合,

再看1到12你会发现一样符合,

到底为什么呢

看6

多出来的6是最最中心的地方

月份每加一,在其原来的31,30紧挨着变化的情况下会多出来一个1

而当月份为5,10时,会凑乘5,而后再过一个月,按30,31来看为 偶数,是30天,不过由于6多出来的五和多一月多出来的6结合,又会造就一个31天,而且和前一个31天还是挨着的

所以,7月到8月的特例就包含了。

再看12月到1月的情况12月时余数为10,一月为11.

是不是又凑成一个5,后面一加有多出来一天。

OK,本次解析到此结束,

慢慢领悟此代码的玄妙之处吧

再见。嘿嘿

再次声明

代码不是我的

转载自https://blog.csdn.net/chinaeran/article/details/43601699

原文地址:https://www.cnblogs.com/cndccm/p/11974754.html

时间: 2024-10-29 07:06:13

关于计算两日期之间经过多少天的超巧妙算法的相关文章

MySql计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数

MySql计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数 计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数,这里主要分享的是通过MySql内置的函数 TimeStampDiff() 实现. 函数 TimeStampDiff() 是MySQL本身提供的可以计算两个时间间隔的函数,语法为: TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) 返回日期或日期时间表达式datetime_expr1 和datetime_expr2the 之

java计算两日期间隔小时或分钟

public static void main(String[] args) {        try {            long min = dateDiff("2014-05-27 13:30:00","2014-05-27 13:00:00","yyyy-MM-dd HH:mm:ss");            System.out.println("---------相隔分钟数: "+min);        

JS实现——计算两日期之差

在网上找了个js实现的,根据相差天数计算日期和根据两个日期计算相差多少天的示例和代码: 根据相差天数计算日期: 距离: 年 月 日 (缺省为今天) 相差: 天 (输入负数则往前计算) 日期是:   根据日期计算相差天数: 开始日期: 年 月 日 结束日期: 年 月 日 相差天数:   实现代码如下: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content=&qu

计算两个集合的差集——第六期 Power8 算法挑战赛

第六期Power8大赛 1.1 比赛题目 题目: 计算两个集合的差集: 详细说明: 分别有集合A和B两个大数集合,求解集合A与B的差集(A中有,但B中无的元素),并将结果保存在集合C中,要求集合C中的元素升序. 输入为两个文件,分别为A.txt,B.txt,一行一个值,并且是无序的.结果输出到C.txt,即输入文件的差集,一行一个值,并且要求结果升序排列. 考量点: (1) 大数集合求差集: (2) 大数据集合排序: 题目实例: 例如,若集合A={5,20,10,15,25,30},集合B={1

求两日期之间的相隔天数(year,month,day)

主要思路理解部分看ppt #include<cstdio> int isRunNian(int year); int DiJiTian(int year,int month,int day); void swap(int *a,int *b); int main() { int year1,month1,day1; int year2,month2,day2; int sum=0; scanf("%d%d%d",&year1,&month1,&day

Python2 获取两日期之间的每一天

import datetime def getEveryDay(begin_date,end_date): date_list = [] begin_date = datetime.datetime.strptime(begin_date, "%Y-%m-%d") end_date = datetime.datetime.strptime(end_date,"%Y-%m-%d") while begin_date <= end_date: date_str =

计算两天之间的天数差

var today = new Date(); var time = '2016-10-05'; time = new Date(time); var g = getDays(today,time); console.log(g); function getDays(date1, date2) { var getd = (date1.getTime() - date2.getTime()) / (3600 * 24 * 1000); getd = parseInt(getd); return g

计算 两日期 间隔天数 zzuli1878

#include<iostream>#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<ctype.h>#include<algorithm>using namespace std;#define N 1010000#define INF 0x3f3f3f3f int yearday[N]; int IsLeap(int

两个日期之间相差的天数

输入两个字符串格式的日期,计算两日期之间,相差的天数 限制条件:输入的日期字符串,格式必须为 yyyy-MM-dd 方法一: 1 /** 2 *两个日期(字符串 格式:yyyy-MM-dd)的间隔天数 3 * 4 * @param smdate 较小的时间 5 * @param bdate 较大的时间 6 * @return 相差天数 7 */ 8 public static int daysBetween(String smdate,String bdate) throws ParseExce