linux程序mktime无权限,linux中mktime算法解析

Linux源码中的mktime算法解析

我们知道,从CMOS中读出来的系统时间并不是time_t类型,而是类似于struct tm那样,年月日时分秒是分开存储的。

那么,要把它转化为系统便于处理的time_t类型,就需要算法进行转换。

我们都知道我们的公历还是比较复杂的,有大月小月,有闰年非闰年,处理起来会很麻烦。

但是Linux的源代码仅仅用了短短的几行就完成了这个复杂的转换(Gauss算法),实在令人惊奇。话不多说,先看源代码:

include/linux/time.h

None.gifstaticinlineunsignedlongmktime(unsignedintyear,unsignedintmon,

None.gifunsignedintday,unsignedinthour,

None.gifunsignedintmin,unsignedintsec)

ExpandedBlockStart.gif{

ExpandedSubBlockStart.gifif(0>=(int) (mon-=2)){/* 1..12 -> 11,12,1..10 */ExpandedSubBlockStart.gif         mon+=12;/* Puts Feb last since it has leap day */6a9c071a08f1dae2d3e1c512000eef41.png         year-=1;

ExpandedSubBlockEnd.gif    }6a9c071a08f1dae2d3e1c512000eef41.png

6a9c071a08f1dae2d3e1c512000eef41.pngreturn(((

6a9c071a08f1dae2d3e1c512000eef41.png             (unsignedlong) (year/4-year/100+year/400+367*mon/12+day)+6a9c071a08f1dae2d3e1c512000eef41.png             year*365-719499ExpandedSubBlockStart.gif          )*24+hour/* now have hours */ExpandedSubBlockStart.gif       )*60+min/* now have minutes */ExpandedSubBlockStart.gif    )*60+sec;/* finally seconds */ExpandedBlockEnd.gif}

看上去令人眼花缭乱,毫无头绪。下面就让我们对该算法作具体的分析。

先不看前面的,直接看return那句,该式整体上具有这样的结构:

T = ((X * 24 + hour) * 60 + min) * 60 + sec

这说明该算法是先算出从1970年1月1日开始的天数X,再进而求出具体的时间值T的。

因此我们重点看如何求天数X。也就是X = year/4 - year/100 + year/400 + 367*mon/12 + day + year*365 - 719499这一部分。

首先可以将上式拆成:

/*    润年判断方法:

*    判断一:能被4整除,不能被100整除,是润年

*    判断二:不满足判断一时,如果能被400整除,是润年

*/

Y = year / 4 - year / 100 + year / 400

Z = 367 * mon / 12

W = year * 365 + day

X = Y + Z + W - 719499

Y很简单,它计算了从公元元年到所求年份为止所有的闰年数。从W式看出,该算法先假设所有年都是正常年(365天),再加上闰年额外的天数(式Y)。

到现在为止都算简单,关键是Z式和X式中的那个常数719499是怎么回事,似乎莫名其妙。还有就是它们和return语句前面的那个if判断有什么关系呢?

首先要澄清一点,常数719499并不是像很多人说的那样,是0001年1月1日到1970年1月1日所经历的天数。

不信你可以随手写个脚本,将得到正确的数字:719162天。

显然719162和719499是有关系的。我们把注意力放在那个if语句上:

None.gifmon-=2;

ExpandedBlockStart.gifif(mon<=0){

6a9c071a08f1dae2d3e1c512000eef41.png    mon+=12;

6a9c071a08f1dae2d3e1c512000eef41.png    year--;

ExpandedBlockEnd.gif}

很明显,它是想把1月和2月当作上一年年底的最后两个月,让3月作为一年的第一个月。这样一来,我们可以尽量少的被闰年所影响。

按照这个假设,让我们先不管Z式是怎么来的,看看0001年1月1日时,Y + Z + W等于什么:

mon = 1月变成上一年(公元前0001年)的11月;

year减一后变成了0,因此Y = 0;

Z = 367 * 11 / 12 = 336;

W = 1 + 0 * 365 = 1;

Y + Z + W = 337。

337这个数正好等于719499 - 719162!换句话说,它是对上述假设所做的补正!于是这些式子就变成了:

Y = year / 4 - year / 100 + year / 400

Z = 367 * mon / 12

V = Z - 337

W = year * 365 + day

X = Y + W + V - 719162

再来看式Z,这个式子表面看不出任何名堂,367这个数字显然很是奇怪。那让我们穷举一下mon,看看这个式子算出的都是些什么值吧:

mon         Z

1           30

2           61

3           91

4           122

5           152

6           183

7           214

8           244

9           275

10          305

11          336

12          367

似乎看出了什么?再让我们把相邻的两个mon的Z做一下减法看看:

mon         dZ

1           30

2           31

3           30

4           31

5           30

6           31

7           31

8           30

9           31

10          30

11          31

12          31

闻出点味道了吧,很象大小月的规则。让我们回想起那个if语句作了什么,它把1月2月变成了11月和12月,3月变成了1月!还原一下看看:

mon     org-mon         dZ

1       3               30

2       4               31

3       5               30

4       6               31

5       7               30

6       8               31

7       9               31

8       10              30

9       11              31

10      12              30

11      1               31

12      2               31

怎么本来应该是大月的3月成了30天?

那好我们想想这个原理,假设今天是1月1日,那你能说你今年已经过了31天了么?显然不是,1月还没过,我们不能把它算进去。

这里同然,我们从4月看起,如果今天是愚人节,那么距离3月1日我们经过了31天。

就像前面说的,我们假设一年是从3月开始,到次年的2月结束。按照这个规则,整个式子里有问题的只有3月,理论上这里应该是0!

但是这没关系,我们把它减去就行了,于是变成:

Z = 367 * mon / 12 - 30

V = Z - 307

回头看看W式,year * 365,但是按照上面的理论,没过完的这一年不应该加进去,所以这里把它减去,再和V式合并:

V = Z + 58

W = (year - 1) * 365 + day

我们记得这个算法的一年是从3月开始的,因此少算了公元元年的1月和2月的天数:31 + 28 = 59天:(公元元年是正常年)

V = Z + 59 - 1

那么最后的这个减1是什么?还是上面那个原理,今天还没过,就不应该把它算进去!

综上,整个算法就明朗了,主要难于理解的是那个3月开始的假设以及367 * mon / 12会产生类似大小月的序列。

最后把这些式子整理并罗列一下,做为本文的结束:

None.gifY = (year - 1) * 365 + year / 4 - year / 100 + year / 400None.gifM = 367 * mon / 12 - 30 + 59None.gifD = day - 1None.gifX = Y + M + D - 719162None.gifT = ((X * 24 + hour) * 60 + min) * 60 + sec

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/442890.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.写一个方法 void printScore(int score),输出相应的等级。score代表分数,等级格式如下:

package Day04;/*** 二、* 1.写一个方法 void printScore(int score)&#xff0c;输出相应的等级。score代表分数,等级格式如下&#xff1a;* 不及格0<s<59, 及格 60<s<79&#xff0c;良好 80<s<89&#xff0c;优秀 90<s<100* 2.在main方法中实现进行测…

linux服务器怎么防,Linux服务器防攻击的各种方案

Linux服务器防袭击的各类计划信任入席站长都对服务器袭击很敏感&#xff0c;谁都经验过&#xff0c;这里就给大伙分享一下Linux服务器防袭击的各类计划。1、使用防火墙1、Linux自带防火墙Centos6下commandservice iptables stop //关闭防火墙chkconfig iptables off //永远关闭…

* 四、要求写一个方法:method。该方法要求传入一个数字n(n要小于10), * 该方法能够计算得到所有各位上的数字不超过n且每一位的数字都不重复的三位数的个数。

package Day04;/*** 四、要求写一个方法&#xff1a;method。该方法要求传入一个数字n&#xff08;n要小于10&#xff09;&#xff0c;* 该方法能够计算得到所有各位上的数字不超过n且每一位的数字都不重复的三位数的个数。* 并且在测试该方法。*/ public class Day04_Demo04 {…

linux 无线网卡连接网络连接不上去,【已解决】Ubuntu 10.04 无线网卡 无法连接

----------------------------------搬家声明------------------------------------------------------------------------搬家声明--------------------------------------【已解决】Ubuntu 10.04 无线网卡 无法连接【问题】新装的Ubuntu 10.04&#xff0c;其他一切正常&#…

Linux 软件包管理器的目的是什么,Linux软件包的管理--RPM包管理器

在Linux中如何安装、升级、卸载软件&#xff0c;是我们日常运维中重要的组成部分。接下来一CentOS6系统为例&#xff0c;讲解如何使用 RPM 包管理器&#xff0c;yum包管理器以及源码的方式来管理我们的软件包。一、相关的背景知识许多程序的源程序&#xff0c;例如使用C语言编写…

获取数组中元素值为偶数的累加和与元素值为奇数的累加和,并计算他们之间的差值

/*** 1.获取数组中元素值为偶数的累加和与元素值为奇数的累加和&#xff0c;并计算他们之间的差值* 1.定义int getNum(int[] arr)静态方法&#xff0c;该方法要求完成* 1.1 获取指定数组arr中元素值为偶数的累加和* 1.2 获取指定数组arr中元素值为奇数的累加和* 1.3 返回偶数累…

嵌入式linux mongodb,小白在Ubuntu安装mongoDB与mongo-c-driver

目的&#xff1a;本人从事嵌入式软件&#xff0c;项目中需要使用MongoDB&#xff0c;最终需要熟悉c-driver的API&#xff0c;小白在搭建环境有些浪费时间&#xff0c;故写这文章让与我同样状态的开发人员学习学习。在Ubuntu上的安装mongodb方法一&#xff1a;sudo apt-get ins…

获取键盘录入的5个int数,并存放到int数组arr中,输入前提示输入的是第几个值 * * 2.2 传递数组arr调用getNum(int[] arr)方法,获取返回值,并打印输出

package Day05;import java.util.Scanner;/*** 2.定义main方法&#xff1a;* * 2.1 获取键盘录入的5个int数&#xff0c;并存放到int数组arr中&#xff0c;输入前提示输入的是第几个值* * 2.2 传递数组arr调用getNum(int[] arr)方法&#xff0c;获取返回值&#xff0c;并打印…

u盘装linux7.2,u盘安装centos 7.2

在Mac环境下&#xff0c;将Linux的ISO镜像生成一个Linux的安装盘&#xff0c;和Linux下差不多&#xff0c;只是Mac下有一些自己的工具。步骤如下&#xff1a;1、在终端下&#xff0c;将ISO镜像转换为DMG格式&#xff1a;$ hdiutil convert -format UDRW -o ~/linux.dmg /tmp/li…

计算分数数组中去掉最低分的平均分,并打印

package Day05;/*** 2.定义一个分数数组&#xff1a;double[] arr {88.5,96,97,74,88.2,58.5,77.9,90,99};* 计算分数数组中去掉最低分的平均分&#xff0c;并打印*/ public class Day05_Demo02_02 {public static void main(String[] args) {double[] arr {88.5, 96, 97, 74…

linux 串口 lsr 0xc9,串口发送0x0D后,从串口接收到数据被转换成了0x0A

如题&#xff0c;在追踪串口中断接收字符接口UART_getc() 到底层&#xff0c;其调用的是 typedef int32_t (*UART_ReadPollingFxn) (UART_Handle handle, void *buffer, size_t size);函数指针&#xff0c;但是该原型我并没有检索到&#xff0c;这个函数的具体实现&a…

1. 定义方法,求出指定元素在数组中出现的次数.

package Day05;import java.util.ArrayList;/*** 3、* c* 1. 定义方法&#xff0c;求出指定元素在数组中出现的次数.* 2. 定义方法&#xff0c;统计数组中出现次数为1的元素一共有多少个。(推荐-遍历数组&#xff0c;然后调用第一个方法&#xff0c;求出数组中每个元素在数组中…

linux网络编程之广播详细代码及文档说明 -,Linux网络编程之广播

1.概念前面介绍的TCP,UDP都是单播方式&#xff0c;即一对一.而广播是一台主机向局域网内的所有主机发送数据。这时&#xff0c;同一网段的所有主机都能接收到数据。发送广播包的步骤大致如下:(1)确定一个发送广播的接口&#xff0c;如eth0(2)确定广播的地址&#xff0c;通过ioc…

求出该数组中特定元素的和,特定元素是指个位和十位不包含7的偶数。

package Day05;/*** 4.* 分析以下需求&#xff0c;并用代码实现&#xff1a;* (1).定义一个int类型的一维数组&#xff0c;内容为{171,72,19,16,118,51,210,7,18}* (2).求出该数组中特定元素的和&#xff0c;特定元素是指个位和十位不包含7的偶数。*/ public class Day05_Demo0…

linux实现自动互信,Linux 使用shell脚本实现自动SSH互信功能

说假设有一个1000台节点的Hadoop集群&#xff0c;要配置节点之间的SSH免密码登录&#xff0c;该如何用shell脚本实现&#xff1f;#!/bin/expect#循环1000台机器的IP地址&#xff0c;生成密钥文件authorized_keysfor ip in {cat ip.list}dossh user$ip ssh-keygen -t rsa &…

在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。 * (静态初始化一个数组,在数组中随意写入6个分数) 选手的最后得分为: * 去掉一个最高分和一个最低分后 的4个评委平均值。

package Day05;/*** 5、* 需求&#xff1a;在编程竞赛中&#xff0c;有6个评委为参赛的选手打分&#xff0c;分数为0-100的整数分。* &#xff08;静态初始化一个数组&#xff0c;在数组中随意写入6个分数&#xff09; 选手的最后得分为&#xff1a;* 去掉一个最高分和一个最低…

linux系统基础与应用,Linux操作系统:基础、原理与应用

《Linux操作系统&#xff1a;基础、原理与应用》第1部分基础篇第1章操作系统概述/31.1认识操作系统31.1.1操作系统的概念31.1.2操作系统的功能41.2操作系统的发展与现状51.2.1操作系统的发展51.2.2操作系统的分类与现状71.3Linux操作系统概述101.3.1Linux的发展背景与历史101.3…

兔子算法题

package Day05;/*** 6、* 兔子过三个月会成老兔子&#xff0c;第四个月开始老兔子每月都会生一个小兔子* 需求&#xff1a;有一对兔子&#xff0c;从出生起后第3个月起每个月都生一对兔子&#xff0c;* 小兔子长到第三个月后每个月又生一对兔子&#xff0c;* 假如兔子都不死&am…

linux 挂载san存储,新手看招:Linux操作系统下挂载SAN资源

在存储设备上配置好SAN资源后&#xff0c;操作Linux主机服务器1.安装iSCSI驱动程序&#xff1b;2.Linux主机安装iSCSI Initiator&#xff1b;3.配置iSCSI Inititor&#xff0c;主要是IP地址和InitiatorName&#xff0c;这一步得重启进程&#xff1b;#vi /etc/iscsi.confDiscove…

要求将数组中的0项去掉,将不为0的值存入一个新的数组,

package Day05;/*** 7、* 现在有如下一个数组&#xff1a;* int oldArr[]{1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5};* 要求将以上数组中的0项去掉&#xff0c;将不为0的值存入一个新的数组&#xff0c;*/ public class Day07_Demo07 {public static void main(String[] args) {int ol…