为什么说这个 Calendar 扩展很好玩呢?因为你基本用不到它!这个扩展是一套关于日期历法的扩展,但是对于我们来说,它没有农历的相关操作,所以对于我们中国人来说这个扩展并没有什么实际的作用。不过这并不妨碍我们去了解学习它。

日期历法类型

对于正常情况下的日期操作来说,PHP 默认使用的是 UTC 时间,也就是国际标准时间,对于我们国家来说,需要在标准 UTC 的时间上加 8 来表示北京时间东八区。当然,也可以直接修改 php.ini 或者数据库中的时区相关参数来定义好日期时区。

标准时区对应的其实就是格里高利时间历法 Gregorian 。也就是我们现在最常用的公历、阳历日期。Calendar 扩展中除了这个标准的公历历法之外,还支持 犹太历法 Jewish 、 法历 French 以及另一个非常出名的 儒略历 Julian 。我们的 Gregorian 历法就是从 Julian 历中演化而来的,它们的差距并不大,但 犹太历 和 法历 的差距就比较大了,一会在下面的代码中我们将看到各种历法之间的差别。

关于这些历法的具体内容大家可以自行查询一下相关的资料,也能够学习到一些有趣的历史知识,比如为什么废弃了 儒略历 而将公历定为了 格里历 。还有 法历 为什么只有短短的那些年,犹太历 为什么年份记得这么大了。法历 和 犹太历 月份名字的来源等,都是很有趣的故事。

Calendar 扩展安装及历法信息查看

Calendar 扩展已经集成在 PHP 安装包中了,不需要特别的单独去安装。如果你无法使用 Calendar 相关的函数,可以重新编译 PHP 并加上 --enable-calendar 参数即可。

接下来我们看下指定历法的详细信息,这里我们指定的是 犹太历 。

$info = cal_info(2);
print_r($info);
// Array
// (
// [months] => Array
// (
// [1] => Tishri
// [2] => Heshvan
// [3] => Kislev
// [4] => Tevet
// [5] => Shevat
// [6] => Adar I
// [7] => Adar II
// [8] => Nisan
// [9] => Iyyar
// [10] => Sivan
// [11] => Tammuz
// [12] => Av
// [13] => Elul
// ) // [abbrevmonths] => Array
// (
// [1] => Tishri
// [2] => Heshvan
// [3] => Kislev
// [4] => Tevet
// [5] => Shevat
// [6] => Adar I
// [7] => Adar II
// [8] => Nisan
// [9] => Iyyar
// [10] => Sivan
// [11] => Tammuz
// [12] => Av
// [13] => Elul
// ) // [maxdaysinmonth] => 30
// [calname] => Jewish
// [calsymbol] => CAL_JEWISH
// )

cal_info() 函数接收的参数是一个常量,分别是 CAL_GREGORIAN ,CAL_JULIAN ,CAL_JEWISH ,CAL_FRENCH ,它们对应的数字就是 0,1,2,3 。在这段代码中,我们返回的就是 CAL_JEWISH 的信息。可以看出,犹太历 中的月份名称与公历中的英文名称都不一样,比如这里有 尼撒月 Nisan 、提市黎月 Tishri 。具体的内容就不深究了,毕竟我们在日常生活中是完全接触不到这种历法的。

大家可以自己试试其它历法返回的信息内容,公历和儒略历是一样的,法历中的月份名字就又不一样了,而且这些名字还都很有意思。

日期历法转换

首先,要进行历法转换的话,我们要将指定的日期转换成 Julian Days 计数。这个 jd 计数可以看作是 Calendar 扩展的一个中间变量,用于各种历法之间的换算。

//  转变Unix时间戳为Julian Day计数
$today = unixtojd(mktime(0, 0, 0, 9, 23, 2020));
echo $today, PHP_EOL; // 2459116

使用 unixtojd() 函数就可以将一个 unix 时间戳转换成 jd 计数。接下来,我们看看 2020 年 9 月 23 号对应的 犹太历 是哪一天。

// 获取当前犹太历时间
print_r(cal_from_jd($today, CAL_JEWISH));
// Array
// (
// [date] => 1/5/5781
// [month] => 1
// [day] => 5
// [year] => 5781
// [dow] => 3
// [abbrevdayname] => Wed
// [dayname] => Wednesday
// [abbrevmonth] => Tishri
// [monthname] => Tishri
// )

返回的信息中已经很明确了吧,我们这一天是 犹太历 的 5781 年 1 月 5 号 星期三 。当前的月份是 Tishri 提市黎月 ,对应着公历年的第一个月,犹太历中教会年的第七个月,代表着秋天的到来。

cal_from_jd() 函数的作用就是根据 jd计数 返回指定历法的详细信息。而另外一个 cal_to_jd() 函数则是从一个支持的历法数据转换为 jd计数 。

echo cal_to_jd(CAL_JEWISH, 1, 5, 5781), PHP_EOL; // 2459116
echo cal_to_jd(CAL_GREGORIAN,9, 23, 2020), PHP_EOL; // 2459116

可以看到上面 犹太历 返回的 jd计数 和我们公历返回的 jd计数 是一致的。

当然,我们也可以将 jd计数 的日期转换成 unix 时间。

echo date("Y-m-d", jdtounix($today)), PHP_EOL;
// 2020-09-23

除了 cal_from_jd() 和 cal_to_jd() 之外,Calendar 扩展还为我们提供了一些快捷的函数进行日期的转换,只不过它们是直接返回的字符串类型的日期信息,不是像 cal_from_jd() 函数一样返回日期的详细信息。

// 转变一个Gregorian历法日期到Julian Day计数
$jd = GregorianToJD(9, 23, 2020); // 转变一个Julian Day计数为Gregorian历法日期
echo jdtogregorian($jd), PHP_EOL; // 9/23/2020
// 转变一个Julian Day计数为Julian历法日期
echo jdtojulian($jd), PHP_EOL; // 9/10/2020
// 转变一个Julian Day计数为犹太历法日期
echo jdtojewish($jd), PHP_EOL; // 1/5/5781
// 转变一个Julian Day计数为unix时间戳
echo jdtounix($jd), PHP_EOL; // 1600819200 $jd = GregorianToJD(9, 23, 1799);
// 转变一个Julian Day计数为French历法日期
echo jdtofrench($jd), PHP_EOL; // 1/1/8

GregorianToJD() 方法就是快捷地转换一个公历日期为 jd计数 。而 jdtoxxxxx 为些函数就是快速地返回 jd计数 对应的日期历法的字符串信息。

大家可以注意下,法历 日期只能是公历 1792年9月22日到1806年9月22日 这段日期以内的日期,也就是 法兰西第一共和国 成立后推出的 法历 ,并在 1806年 结束使用,因为 1804年 拿破仑 成立了 法兰西第一帝国 。帝国废止了 法历(共和历)并全面推行 公历 。

某个月份的天数

上面的历史知识学习的怎么样?接下来还是回归到 Calendar 扩展中的学习中来。

$num = cal_days_in_month(CAL_GREGORIAN, 2, 2020);
echo $num, PHP_EOL; // 29

cal_days_in_month() 函数是返回指定历法月份的天数,比如我们看看 2020 年的 2月 是不是 闰月 就可以用这个函数来实现。

复活节彩蛋

复活节是西方非常重要的一个节日,所以在 Calendar 扩展中就有函数可以直接获得指定年份的复活节日期。关于复活节的计算方式其实还是比较复杂的,手工推算是比较麻烦的,而程序计算就非常方便了。

// 指定年份的复活节时间戳
echo date("M-d-Y", easter_date(2019)), PHP_EOL; // Apr-21-2019
echo date("M-d-Y", easter_date(2020)), PHP_EOL; // Apr-12-2020
echo date("M-d-Y", easter_date(2021)), PHP_EOL; // Apr-04-2021 // 3月21日到复活节之间的天数
echo easter_days(2019), PHP_EOL; // 31
echo easter_days(2020), PHP_EOL; // 22
echo easter_days(2021), PHP_EOL; // 14

easter_date() 函数就是返回指定年份的复活节日期。而 easter_days() 函数则是返回从当年公历的 3月21日 到复活节之间的天数。

复活节是每年春分月圆后的第一个星期日,而春分一般是在3月21日,这就简化为只要计算满月的日期和紧挨的星期日的日期就可以得到每年复活节的具体日期了。这种函数在西方世界的软件开发中会非常常用,其实就像我们需要获取每年春节的具体公历日期一样。

总结

是不是很有意思的一套扩展函数。不过对于我们主要面向国内开发的开发者来说用处确实不大,但笔者在学习这个扩展的时候另外收获了不少历史方面的知识,也算是开了眼界,也不失为一大收获,大家也自己试着玩玩并且查查相关的历史知识吧,说不定你的收获会更多!

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/10.PHP中非常好玩的Calendar扩展学习.php

参考文档:

https://www.php.net/manual/zh/book.calendar.php

===============

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

PHP中非常好玩的Calendar扩展学习的更多相关文章

  1. PHP中一个好玩的性别判断扩展

    今天我们来学习的一个扩展同时它也是非常小众的一个扩展,其实说白了,或许是根本没什么人用过得扩展.当然,我们也只是出于学习的目的来看看这个扩展到底是什么东西,有什么好玩的地方. 扩展说明 Gender ...

  2. PHP中的MySQLi扩展学习(三)mysqli的基本操作

    我们继续 MySQLi 扩展的学习,上篇文章中提到过,MySQLi 的扩展相对于 PDO 来说功能更加的丰富,所以我们依然还会在学习过程中穿插各种 MySQLi 中好玩的方法函数.不过,今天的主角是 ...

  3. PHP中操作任意精度大小的GMP扩展学习

    对于各类开发语言来说,整数都有一个最大的位数,如果超过位数就无法显示或者操作了.其实,这也是一种精度越界之后产生的精度丢失问题.在我们的 PHP 代码中,最大的整数非常大,我们可以通过 PHP_INT ...

  4. 学习PHP中的高精度计时器HRTime扩展

    不知道大家还记得在学校的时候体育测试时老师带的秒表吗?当枪声想起时,我们开始跑步,这时秒表启动,当我们跑过终点后,老师会按下按扭记录我们的成绩,这就是一个典型的定时器的应用.今天我们要学习的内容其实就 ...

  5. PHP中的MySQLi扩展学习(六)MySQLI_result对象操作

    在之前的文章中,我们就已经接触过 MYSQLI_result 相关的内容.它的作用其实就是一个查询的结果集.不过在 PDO 中,一般直接通过 query() 或者 PDOStatement 对象进行查 ...

  6. PHP中的MySQLi扩展学习(五)MySQLI_STMT对象操作

    就像 PDO 中的 PDO_Statment 对象一样,MySQLI_STMT 对象也是一个预处理语句所形成的对象,专门用来操作 MySQLi 所生成的预处理语句的.其实操作方式之类也都比较相似,不外 ...

  7. PHP中的MySQLi扩展学习(四)mysqli的事务与预处理语句

    对于 MySQLi 来说,事务和预处理语句当然是它之所以能够淘汰 MySQL(原始) 扩展的资本.我们之前也已经学习过了 PDO 中关于事务和预处理语句相关的内容.所以在这里,我们就不再多讲理论方面的 ...

  8. PHP中的MySQLi扩展学习(二)mysqli类的一些少见的属性方法

    虽说是少见的一些属性方法,但是可能还是有不少同学在日常的开发中使用过,这里只是学习了可能相对来说我们用得比较少的一些 mysqli 的属性或方法.就当是扩展一下自己的知识体系. 切换用户 首先就是切换 ...

  9. PHP中的MySQLi扩展学习(一)MySQLi介绍

    关于 PDO 的学习我们告一段落,从这篇文章开始,我们继续学习另外一个 MySQL 扩展,也就是除了 PDO 之外的最核心的 MySQLi 扩展.可以说它的祖先,也就是 MySQL(原始) 扩展是我们 ...

随机推荐

  1. 【笔记】numpy.array基础(2)

    numpy数组的基本操作 以几个数组为例 使用ndim可以显示出是几维数组 使用shape可以查看元素维度数 使用size可以查看元素个数 对一维数组进行数据访问 对多维数组进行数据访问 切片访问,使 ...

  2. 012 PCIe总线的基础知识

    一.PCIe总线的基础知识 与PCI总线不同,PCIe总线使用端到端的连接方式,在一条PCIe链路的两端只能各连接一个设备,这两个设备互为是数据发送端和数据接收端.PCIe总线除了总线链路外,还具有多 ...

  3. 题解 CF613E Puzzle Lover

    解题思路 其实仔细观察我们可以发现路径一定是一个类似于下图的一个左括号之后中间随便反复曲折,然后右边在来一个右括号. 然后对于两个括号形状的东西其实是可以利用 Hash 来判等特殊处理的. 对于中间的 ...

  4. one_gadget的一些姿势

    概要 one_gadget是libc中存在的一些执行execve("/bin/sh", NULL, NULL)的片段,当可以泄露libc地址,并且可以知道libc版本的时候,可以使 ...

  5. elasticsearch可视化工具-dejavu

    https://github.com/appbaseio/dejavu docker run -p 1358:1358 -d appbaseio/dejavu http.port: 9200 http ...

  6. 【springboot】知识点总结

    [springboot 基础编] 01.SpringBoot>01 - 第一个应用–HelloWorld 02.SpringBoot>02 - 整合 MyBatis 03.SpringBo ...

  7. WPF---数据绑定之ItemsControl(三)

    一.Combox绑定 场景:定义多个Person,Person有Name和Age属性,将多个Person与Combox进行绑定,Combox中只显示Name信息,点击任意一个item,在左侧显示该条目 ...

  8. C#设计模式---模板方法模式(Template Method Pattern)

    一.目的 模板方法模式把不变行为搬到超类中,从而去除了子类中的重复代码. 二.定义 模板方法模式:在一个抽象类中定义一个操作的算法骨架,将算法骨架中某些特定的操作延迟到子类中实现. 模板方法使得子类在 ...

  9. linux下C编程初篇

    对于程序设计员来说,makefile是我们绕不过去的一个坎.可能对于习惯Visual C++的用户来说,是否会编写makefile无所谓.毕竟工具本身已经帮我们做好了全部的编译流程.但是在Linux上 ...

  10. 高性能利器:CDN我建议你好好学一下!

    硬核干货分享,欢迎关注[Java补习课]成长的路上,我们一起前行 ! <高可用系列文章> 已收录在专栏,欢迎关注! CDN 概述 CDN 全称 Content Delivery Netwo ...