日期相关的操作函数是我们在日常的工作开发中最常接触到的功能。当然,大部分同学可能最多用到的就是 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中的日期相关函数(一)的更多相关文章

  1. PHP中的日期相关函数(三)

    之前我们已经介绍过了 PHP 的一些相关的日期操作对象,今天我们就来学习剩下的那些面向过程的使用方式.当然,如果是和 DateTime 类中相似的方法我们就不再进行介绍了.另外,Date() 和 ti ...

  2. PHP中的日期相关函数(二)

    上回文章中我们介绍了三个时间日期相关的对象,不过它们的出镜频率并不是特别地高.今天学习的对象虽说可能不少人使用过,但是它的出镜频率也是非常低的.它们其实就是我们非常常用的那些面向过程的日期函数的面向对 ...

  3. Vim技能修炼教程(15) - 时间和日期相关函数

    Vimscript武器库 前面我们走马观花地将Vimscript的大致语法过了一遍.下面我们开始深入看一下Vimscript都给我们准备了哪些武器.如果只用这些武器就够了,那么就太好了,只用Vimsc ...

  4. [转载]SQL语句中的日期计算

    1. 本月的第一天SELECT  DATEADD(mm,  DATEDIFF(mm,0,getdate()),  0) 2. 本月的最后一天SELECT  dateadd(ms,-3,DATEADD( ...

  5. 在Extjs中对日期的处理,以及在后端数据在SQL语句的判断处理

    jsp页面可选择时间: { xtype : 'datefield', id : 'START_CREATION_DATE_', format : 'Y-m-d H:i:s', submitFormat ...

  6. 在MonthCalendar控件中选中日期

    Calendar.MONTH Calendar now=Calendar.getInstance();System.out.print(now.get(Calendar.MONTH));得到的月份少1 ...

  7. Struts2中Date日期转换的问题

      今天跑程序的时候莫名其妙的出现了下面的一个异常: java.lang.NoSuchMethodException:com.ca.agent.model.mybatis.ApprovalInforC ...

  8. C#中的日期处理函数

    C#中的日期处理函数 //2013年4月24日 this.TextBox6.Text = System.DateTime.Now.ToString("D"); //2013-4-2 ...

  9. 谈谈javascript中的日期Date对象

    一.日期对象  在javascript中并没有日期型的数据类型,但是提供了一个日期对象可以操作日期和时间.  日期对象的创建:  new Date();二.将日期对象转换为字符串  将日期对象转换为字 ...

随机推荐

  1. JCE加密和解密 bouncycastle

    https://blog.csdn.net/weixin_43935907/article/details/89155617 https://blog.csdn.net/qq_29583513/art ...

  2. 分享一个自己制作的XML在线编辑器

    前言 一年多没更新博客了,原因是疫情期间<骑马与砍杀2>发售,然后去写游戏MOD去了. 用C#大概写了7个月的游戏MOD,每天晚上肝到很晚,然后期间又因为介绍这个游戏MOD,学习了PR,然 ...

  3. vue路由history模式,nginx配置

    nginx配置内容 # For more information on configuration, see: # * Official English Documentation: http://n ...

  4. git 拉取代码指定分支

    问题背景: 新项目还在开发阶段,没有正式对外发布,所以开发同事合并代码到develop上(或者其他名称分支上),而不是到master分支上 通过git拉取代码的时候,默认拉取的是master分支,如下 ...

  5. 关于Java for循环的注意点

    1 import java.util.ArrayList; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 ...

  6. 刷题-力扣-518. 零钱兑换 II

    518. 零钱兑换 II 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/coin-change-2/ 著作权归领扣网络所有.商业转载 ...

  7. freeswitch新增模块

    概述 freeswitch的架构由稳定的核心模块和大量的外围插件式模块组成.核心模块保持稳定,外围模块可以动态的加载/卸载,非常灵活方便. 外围模块通过核心提供的 Public API与核心进行通信, ...

  8. Elasticsearch集群搭建教程及生产环境配置

    Elasticsearch 是一个极其强大的搜索和分析引擎,其强大的部分在于能够对其进行扩展以获得更好的性能和稳定性. 本教程将提供有关如何设置 Elasticsearch 集群的一些信息,并将添加一 ...

  9. mybaits源码分析--自定义插件(七)

    一.MyBatis插件 插件是一种常见的扩展方式,大多数开源框架也都支持用户通过添加自定义插件的方式来扩展或者改变原有的功能,MyBatis中也提供的有插件,虽然叫插件,但是实际上是通过拦截器(Int ...

  10. 字符型:char

    字符型:char 字符变量的定义和输出 字符变量用于存储一个单一字符,在C语言中用char表示,其中每个字符变量都会占用1个字节.在给字符型变量赋值时,需要用一对因为半角格式的单引号('   ')把字 ...