PHP中的日期相关函数(一)
日期相关的操作函数是我们在日常的工作开发中最常接触到的功能。当然,大部分同学可能最多用到的就是 date() 、 time() 这两个函数,我们今天先不讲这两个函数,或许后面的文章也不太会讲它们,毕竟太常用了。本身在对手册文档的学习中,就是要发掘有意思的或者没有接触过的一些功能函数,所以我们今天的学习的函数可能是大家都没怎么用过的,甚至可能很多大家都没见过的。
时区类相关函数
首先就是时区类的一个对象。它可以帮助我们获取一些当前时区相关的信息。
$timezone = new DateTimeZone('Asia/Shanghai');
var_dump($timezone);
// object(DateTimeZone)#1 (2) {
// ["timezone_type"]=>
// int(3)
// ["timezone"]=>
// string(13) "Asia/Shanghai"
// }
在实例化这个 DateTimeZone 时区类时,需要传递一个时区参数。这里我们给的就是通用的中国时区的设置,虽说我们的国际标准时区是东八区的北京时间,但在 PHP 中的时区格式中,我们的时区是以上海为命名的。
这个时区类可以直接获得当前指定时区的定位信息,比如 Asia/Shanghai 的定位信息就是直接定位到上海市的。
// 时区相关的定位信息
var_dump($timezone->getLocation());
// array(4) {
// ["country_code"]=>
// string(2) "CN"
// ["latitude"]=>
// float(31.23333)
// ["longitude"]=>
// float(121.46666)
// ["comments"]=>
// string(12) "Beijing Time"
// }
通过 getLocation() 就可以获取到时区类的定位信息,经纬度的查询结果就是上海市中心,comments 字段也明确地指出了当前时区是北京时间。
// 时区名称
var_dump($timezone->getName());
// string(13) "Asia/Shanghai"
// 相对于 GMT 的时差
var_dump($timezone->getOffset(new DateTime('now', $timezone)));
// int(28800)
// 所有时区转换信息
var_dump($timezone->getTransitions(time()));
// array(1) {
// [0]=>
// array(5) {
// ["ts"]=>
// int(1601168813)
// ["time"]=>
// string(24) "2020-09-27T01:06:53+0000"
// ["offset"]=>
// int(28800)
// ["isdst"]=>
// bool(false)
// ["abbr"]=>
// string(3) "CST"
// }
// }
getName() 方法获取的是当前时区的名称,这个就不用多说了。getOffset() 则是获取到与国际格林尼治时间(GMT)的差值,也就是与子午线的时间间隔,这里返回的是秒,转换成小时后正好就是 8 小时。getTransitions() 函数返回的是所有时区转换的时间,我测试的时间是早上,返回的 time 字段内容是格林尼治时间,offset 字段返回的也是与GMT时间的差值。GMT时间与UTC时间是一致的,我们在日常的学习和工作中如果接触到了这两个名词可以将它们看做是相同的概念。
UTC时间的标准叫法是协调世界时间,基于国际原子时间,全世界的国家的标准时间都是以它为标准进行调校的,而GMT的本意是定位为本初子午线的平太阳时,UTC也是以这条经线为基准进行时区划分的。不过,按照严格的标准来说,它们并不是完全相等的,具体的内容大家可以自行查阅,但对于我们日常开发来说,完全可以将它们视为等同的东西。
// 包含 dst (夏令时),时差和时区信息的关联数组
var_dump(DateTimeZone::listAbbreviations());
// array(144) {
// ["acdt"]=>
// array(6) {
// [0]=>
// array(3) {
// ["dst"]=>
// bool(true)
// ["offset"]=>
// int(37800)
// ["timezone_id"]=>
// string(18) "Australia/Adelaide"
// }
// [1]=>
// array(3) {
// ["dst"]=>
// bool(true)
// ["offset"]=>
// int(37800)
// ["timezone_id"]=>
// string(21) "Australia/Broken_Hill"
// }
// ……
// ……
// 包含了所有时区标示符的索引数组
var_dump(DateTimeZone::listIdentifiers());
// array(426) {
// [0]=>
// string(14) "Africa/Abidjan"
// [1]=>
// string(12) "Africa/Accra"
// [2]=>
// string(18) "Africa/Addis_Ababa"
// [3]=>
// string(14) "Africa/Algiers"
// ……
// ……
listAbbreviations() 静态方法返回的是 夏令时 相关的时差和时区信息。夏令时 和 冬令时 也是西方国家的一种生活标准,我们接触的不多,这里就不做讲解了,对于做跨境项目或者欧美外包的同学应该不会陌生。listIdentifiers() 方法返回的是包含了所有时区标示符的索引数组,这里可以看到所有的支持的时区信息。
日期间隔操作
对时日期时间的间隔操作,或许大家多少都做过一点,比如 DateTime 对象的那个 diff() 方法。
$today = new DateTime('2020-09-27');
$beforeYestoday = new DateTime("2020-09-25");
var_dump($today->diff($beforeYestoday));
// object(DateInterval)#5 (16) {
// ["y"]=>
// int(0)
// ["m"]=>
// int(0)
// ["d"]=>
// int(2)
// ["h"]=>
// int(0)
// ["i"]=>
// int(0)
// ["s"]=>
// int(0)
// ["f"]=>
// float(0)
// ["weekday"]=>
// int(0)
// ["weekday_behavior"]=>
// int(0)
// ["first_last_day_of"]=>
// int(0)
// ["invert"]=>
// int(1)
// ["days"]=>
// int(2)
// ["special_type"]=>
// int(0)
// ["special_amount"]=>
// int(0)
// ["have_weekday_relative"]=>
// int(0)
// ["have_special_relative"]=>
// int(0)
// }
从打印的结果可以看出,diff() 对象返回的是一个 DateInterval 对象。这个就是我们这节的主角了,关于它打印出来的这些属性内容就不多解释了,字段名已经非常直观了,值就是具体的差值。
$interval = new DateInterval("P2D");
var_dump($interval);
// object(DateInterval)#2 (16) {
// ["y"]=>
// int(0)
// ["m"]=>
// int(0)
// ["d"]=>
// int(2)
// ["h"]=>
// int(0)
// ["i"]=>
// int(0)
// ["s"]=>
// int(0)
// ["f"]=>
// float(0)
// ["weekday"]=>
// int(0)
// ["weekday_behavior"]=>
// int(0)
// ["first_last_day_of"]=>
// int(0)
// ["invert"]=>
// int(0)
// ["days"]=>
// bool(false)
// ["special_type"]=>
// int(0)
// ["special_amount"]=>
// int(0)
// ["have_weekday_relative"]=>
// int(0)
// ["have_special_relative"]=>
// int(0)
// }
看到没有?打印出来的内容和上面用 diff() 方法返回的对象的内容是一致的,但是它的构造函数的参数很奇怪。没错,当我们自己去实例化一个 DateInterval 对象时,需要为它定义它的间隔信息,这个间隔信息就是我们通过构造函数的参数传递进去的。P2D 的意思就是间隔 2 天,首先必须以一个 P 为开头,然后可以有 Y、M、D 这些日期内容,如果需要时间内容的话,需要一个 T 然后再跟上 H、M、S 这些内容。比如 P2Y4DT6H8M 表示的就是 2年4天6小时8分钟 的时间间隔。具体的规则大家还是去看文档中的说明:https://www.php.net/manual/zh/dateinterval.construct.php。
$interval = new DateInterval("P2Y4DT6H8M");
var_dump($interval);
// object(DateInterval)#5 (16) {
// ["y"]=>
// int(2)
// ["m"]=>
// int(0)
// ["d"]=>
// int(4)
// ["h"]=>
// int(6)
// ["i"]=>
// int(8)
// ["s"]=>
// int(0)
// ["f"]=>
// float(0)
// ["weekday"]=>
// int(0)
// ["weekday_behavior"]=>
// int(0)
// ["first_last_day_of"]=>
// int(0)
// ["invert"]=>
// int(0)
// ["days"]=>
// bool(false)
// ["special_type"]=>
// int(0)
// ["special_amount"]=>
// int(0)
// ["have_weekday_relative"]=>
// int(0)
// ["have_special_relative"]=>
// int(0)
// }
我们还可以通过字段串形式的日期数据返回间隔对象,比如:
// 从日期语句创建时间间隔
var_dump(DateInterval::createFromDateString('2 days'));
// object(DateInterval)#3 (16) {
// ["y"]=>
// int(0)
// ["m"]=>
// int(0)
// ["d"]=>
// int(2)
// ["h"]=>
// int(0)
// ["i"]=>
// int(0)
// ["s"]=>
// int(0)
// ["f"]=>
// float(0)
// ["weekday"]=>
// int(0)
// ["weekday_behavior"]=>
// int(0)
// ["first_last_day_of"]=>
// int(0)
// ["invert"]=>
// int(0)
// ["days"]=>
// bool(false)
// ["special_type"]=>
// int(0)
// ["special_amount"]=>
// int(0)
// ["have_weekday_relative"]=>
// int(0)
// ["have_special_relative"]=>
// int(0)
// }
此外,在获得对象后进行输出的时候,DateInterval 对象也为我们提供了一个 format() 方法,可以像 printf() 函数一样来格式化地输出日期信息,而且这里用的格式符还是日期的格式符。
var_dump($interval->format('%y %d %h %i'));
// string(7) "2 4 6 8"
输出的内容其实就是属性中对应的那些日期和时间差值。
时间周期相关函数
说完时间间隔了,我们再来看看时间周期。时间周期是个什么概念呢?就比如说我们要每三天间隔一次地获取日期,这时就可以用时间周期相关的类来进行处理。
$start = new DateTime('2020-09-01');
$interval = new DateInterval('P7D');
$end = new DateTime('2020-09-30');
$daterange = new DatePeriod($start, $interval ,$end);
var_dump($daterange);
// object(DatePeriod)#7 (6) {
// ["start"]=>
// object(DateTime)#8 (3) {
// ["date"]=>
// string(26) "2020-09-01 00:00:00.000000"
// ["timezone_type"]=>
// int(3)
// ["timezone"]=>
// string(13) "Asia/Shanghai"
// }
// ["current"]=>
// NULL
// ["end"]=>
// object(DateTime)#9 (3) {
// ["date"]=>
// string(26) "2020-09-30 00:00:00.000000"
// ["timezone_type"]=>
// int(3)
// ["timezone"]=>
// string(13) "Asia/Shanghai"
// }
// ["interval"]=>
// object(DateInterval)#10 (16) {
// ["y"]=>
// int(0)
// ["m"]=>
// int(0)
// ["d"]=>
// int(7)
// ["h"]=>
// int(0)
// ["i"]=>
// int(0)
// ["s"]=>
// int(0)
// ["f"]=>
// float(0)
// ["weekday"]=>
// int(0)
// ["weekday_behavior"]=>
// int(0)
// ["first_last_day_of"]=>
// int(0)
// ["invert"]=>
// int(0)
// ["days"]=>
// bool(false)
// ["special_type"]=>
// int(0)
// ["special_amount"]=>
// int(0)
// ["have_weekday_relative"]=>
// int(0)
// ["have_special_relative"]=>
// int(0)
// }
// ["recurrences"]=>
// int(1)
// ["include_start_date"]=>
// bool(true)
// }
foreach($daterange as $date){
echo $date->format("Ymd"), PHP_EOL;
}
// 20200901
// 20200908
// 20200915
// 20200922
// 20200929
首先设定了开始时间和结束时间以及一个时间间隔对象,然后用它们做为参数来生成一个 DatePeriod 时间周期对象。它是一个实现了迭代器的对象,所以我们可以直接遍历它,结果就是以 P7D ,也就是 7 天为间隔的一组日期数据。
var_dump($daterange->getDateInterval());
// object(DateInterval)#11 (16) {
// ["y"]=>
// int(0)
// ["m"]=>
// int(0)
// ["d"]=>
// int(7)
// ["h"]=>
// int(0)
// ["i"]=>
// int(0)
// ["s"]=>
// int(0)
// ["f"]=>
// float(0)
// ["weekday"]=>
// int(0)
// ["weekday_behavior"]=>
// int(0)
// ["first_last_day_of"]=>
// int(0)
// ["invert"]=>
// int(0)
// ["days"]=>
// bool(false)
// ["special_type"]=>
// int(0)
// ["special_amount"]=>
// int(0)
// ["have_weekday_relative"]=>
// int(0)
// ["have_special_relative"]=>
// int(0)
// }
var_dump($daterange->getStartDate());
// object(DateTime)#11 (3) {
// ["date"]=>
// string(26) "2020-09-01 00:00:00.000000"
// ["timezone_type"]=>
// int(3)
// ["timezone"]=>
// string(13) "Asia/Shanghai"
// }
var_dump($daterange->getEndDate());
// object(DateTime)#11 (3) {
// ["date"]=>
// string(26) "2020-09-30 00:00:00.000000"
// ["timezone_type"]=>
// int(3)
// ["timezone"]=>
// string(13) "Asia/Shanghai"
// }
它的这一堆方法其实返回的就是我们定义的那些构造参数信息。另外,它还可以指定从开始日期往后按照时间间隔返回几条信息。
$period = new DatePeriod($start, $interval, 4);
foreach($period as $date){
echo $date->format("Ymd"), PHP_EOL;
}
// 20200901
// 20200908
// 20200915
// 20200922
// 20200929
var_dump($period->getRecurrences());
// int(4)
recurrences 参数的作用就是按照指定的时间间隔返回几条信息,这里我们是返回 9月1号 之后每次间隔 7 天的 4 条信息,和上面的内容一样。这时我们修改构造函数的值为其它数量,比如修改为 2 ,那么就只会返回到 9月15号 的信息了。它不会受到结束日期的约束,可以返回从开始日期到指定数量之后的所有信息,大家可以自己尝试一下。
总结
今天学习的内容不知道大家有没有接触过,反正我是只用过 diff() 方法来处理过日期之间的差值问题,而且也并没有注意到过它返回的这个对象具体的内容。而另外两个对象则是压根没有印象,完全就是没听说过的感觉。所以说,平常多刷刷手册还是非常有帮助的,今天学习的内容又让我们知道了很多东西,而且 DatePeriod 在具体的业务实现中是肯定会有使用场景的。学习不止,后面我们要学习的内容依然精彩。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/12.PHP中的日期相关函数(一).php
参考文档:
https://www.php.net/manual/zh/book.datetime.php
关注公众号:【硬核项目经理】获取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料
知乎、公众号、抖音、头条搜索【硬核项目经理】
B站ID:482780532
PHP中的日期相关函数(一)的更多相关文章
- PHP中的日期相关函数(三)
之前我们已经介绍过了 PHP 的一些相关的日期操作对象,今天我们就来学习剩下的那些面向过程的使用方式.当然,如果是和 DateTime 类中相似的方法我们就不再进行介绍了.另外,Date() 和 ti ...
- PHP中的日期相关函数(二)
上回文章中我们介绍了三个时间日期相关的对象,不过它们的出镜频率并不是特别地高.今天学习的对象虽说可能不少人使用过,但是它的出镜频率也是非常低的.它们其实就是我们非常常用的那些面向过程的日期函数的面向对 ...
- Vim技能修炼教程(15) - 时间和日期相关函数
Vimscript武器库 前面我们走马观花地将Vimscript的大致语法过了一遍.下面我们开始深入看一下Vimscript都给我们准备了哪些武器.如果只用这些武器就够了,那么就太好了,只用Vimsc ...
- [转载]SQL语句中的日期计算
1. 本月的第一天SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0) 2. 本月的最后一天SELECT dateadd(ms,-3,DATEADD( ...
- 在Extjs中对日期的处理,以及在后端数据在SQL语句的判断处理
jsp页面可选择时间: { xtype : 'datefield', id : 'START_CREATION_DATE_', format : 'Y-m-d H:i:s', submitFormat ...
- 在MonthCalendar控件中选中日期
Calendar.MONTH Calendar now=Calendar.getInstance();System.out.print(now.get(Calendar.MONTH));得到的月份少1 ...
- Struts2中Date日期转换的问题
今天跑程序的时候莫名其妙的出现了下面的一个异常: java.lang.NoSuchMethodException:com.ca.agent.model.mybatis.ApprovalInforC ...
- C#中的日期处理函数
C#中的日期处理函数 //2013年4月24日 this.TextBox6.Text = System.DateTime.Now.ToString("D"); //2013-4-2 ...
- 谈谈javascript中的日期Date对象
一.日期对象 在javascript中并没有日期型的数据类型,但是提供了一个日期对象可以操作日期和时间. 日期对象的创建: new Date();二.将日期对象转换为字符串 将日期对象转换为字 ...
随机推荐
- windows的自动登录和隐藏用户
Launch Regedit. #r -> regedit 1. Navigate to: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\Cu ...
- Typora使用Gitee图床
前言 现在比较流行的Markdown编辑器应该是Typora,但是Typora本身不支持本地上传图片的云端存储,所以当我们写博客的时候,需要上传图片,就得自己设置图床,今天给大家推荐一款免费的图床-G ...
- mingw+gcc 10.1下载
链接: https://pan.baidu.com/s/1Qyqv1PDppRJvgph9sBmwxw 提取码: fqkp
- Go的Channel发送和接收
先来看一道面试题: 对已经关闭的 chan 进行读写,会怎么样?为什么? 在上一篇学习 Go 协程的文章中,知道 go 关键字可以用来开启一个 goroutine 进行任务处理,但多个任务之间如果需要 ...
- 题解 Walker
传送门 总觉得有个柿子可以推--然而没推出来 考试的时候有个柿子假了导致我没想用两个点可以解出一组参数的事 假掉的柿子告诉我有不少东西能消掉 然而实际上随便选两个点高斯消元解出一组参数,再代入验证看够 ...
- dubbo-admin管理控制台安装
拉项目切换分支到master git clone https://github.com/apache/dubbo-admin.git /var/tmp/dubbo-admin 打开项目修改配置 dub ...
- [转]C# 互操作性入门系列(四):在C# 中调用COM组件
传送门 C#互操作系列文章: C# 互操作性入门系列(一):C#中互操作性介绍 C# 互操作性入门系列(二):使用平台调用调用Win32 函数 C# 互操作性入门系列(三):平台调用中的数据封送处理 ...
- Linux初探之如何查看帮助文档自学命令
linux命令种类繁多,参数各异,要每个都记住除非是过目不忘的神人,否则你只能记住常用的那几个,等到 要用时还是得靠--help,man,info这些命令去读文档,可是这些文档看起来也不那么直观,所以 ...
- .net core signalR 全局异常处理
Hub的异常拦截 { } { } *:first-child { } *:last-child { } { } { } { } { } { } { } { } { } { } h6:first-chi ...
- mybatis面试题总结
1.什么是MyBatis? 答:MyBatis是一个可以自定义SQL.存储过程和高级映射的持久层框架. 2.讲下MyBatis的缓存 答:MyBatis的缓存分为一级缓存和二级缓存,一级缓存放在ses ...