日期相关的操作函数是我们在日常的工作开发中最常接触到的功能。当然,大部分同学可能最多用到的就是 date() 、 time() 这两个函数,我们今天先不讲这两个函数,或许后面的文章也不太会讲它们,毕竟太常用了。本身在对手册文档的学习中,就是要发掘有意思的或者没有接触过的一些功能函数,所以我们今天的学习的函数可能是大家都没怎么用过的,甚至可能很多大家都没见过的。

时区类相关函数

首先就是时区类的一个对象。它可以帮助我们获取一些当前时区相关的信息。

  1. $timezone = new DateTimeZone('Asia/Shanghai');
  2. var_dump($timezone);
  3. // object(DateTimeZone)#1 (2) {
  4. // ["timezone_type"]=>
  5. // int(3)
  6. // ["timezone"]=>
  7. // string(13) "Asia/Shanghai"
  8. // }

在实例化这个 DateTimeZone 时区类时,需要传递一个时区参数。这里我们给的就是通用的中国时区的设置,虽说我们的国际标准时区是东八区的北京时间,但在 PHP 中的时区格式中,我们的时区是以上海为命名的。

这个时区类可以直接获得当前指定时区的定位信息,比如 Asia/Shanghai 的定位信息就是直接定位到上海市的。

  1. // 时区相关的定位信息
  2. var_dump($timezone->getLocation());
  3. // array(4) {
  4. // ["country_code"]=>
  5. // string(2) "CN"
  6. // ["latitude"]=>
  7. // float(31.23333)
  8. // ["longitude"]=>
  9. // float(121.46666)
  10. // ["comments"]=>
  11. // string(12) "Beijing Time"
  12. // }

通过 getLocation() 就可以获取到时区类的定位信息,经纬度的查询结果就是上海市中心,comments 字段也明确地指出了当前时区是北京时间。

  1. // 时区名称
  2. var_dump($timezone->getName());
  3. // string(13) "Asia/Shanghai"
  4. // 相对于 GMT 的时差
  5. var_dump($timezone->getOffset(new DateTime('now', $timezone)));
  6. // int(28800)
  7. // 所有时区转换信息
  8. var_dump($timezone->getTransitions(time()));
  9. // array(1) {
  10. // [0]=>
  11. // array(5) {
  12. // ["ts"]=>
  13. // int(1601168813)
  14. // ["time"]=>
  15. // string(24) "2020-09-27T01:06:53+0000"
  16. // ["offset"]=>
  17. // int(28800)
  18. // ["isdst"]=>
  19. // bool(false)
  20. // ["abbr"]=>
  21. // string(3) "CST"
  22. // }
  23. // }

getName() 方法获取的是当前时区的名称,这个就不用多说了。getOffset() 则是获取到与国际格林尼治时间(GMT)的差值,也就是与子午线的时间间隔,这里返回的是秒,转换成小时后正好就是 8 小时。getTransitions() 函数返回的是所有时区转换的时间,我测试的时间是早上,返回的 time 字段内容是格林尼治时间,offset 字段返回的也是与GMT时间的差值。GMT时间与UTC时间是一致的,我们在日常的学习和工作中如果接触到了这两个名词可以将它们看做是相同的概念。

UTC时间的标准叫法是协调世界时间,基于国际原子时间,全世界的国家的标准时间都是以它为标准进行调校的,而GMT的本意是定位为本初子午线的平太阳时,UTC也是以这条经线为基准进行时区划分的。不过,按照严格的标准来说,它们并不是完全相等的,具体的内容大家可以自行查阅,但对于我们日常开发来说,完全可以将它们视为等同的东西。

  1. // 包含 dst (夏令时),时差和时区信息的关联数组
  2. var_dump(DateTimeZone::listAbbreviations());
  3. // array(144) {
  4. // ["acdt"]=>
  5. // array(6) {
  6. // [0]=>
  7. // array(3) {
  8. // ["dst"]=>
  9. // bool(true)
  10. // ["offset"]=>
  11. // int(37800)
  12. // ["timezone_id"]=>
  13. // string(18) "Australia/Adelaide"
  14. // }
  15. // [1]=>
  16. // array(3) {
  17. // ["dst"]=>
  18. // bool(true)
  19. // ["offset"]=>
  20. // int(37800)
  21. // ["timezone_id"]=>
  22. // string(21) "Australia/Broken_Hill"
  23. // }
  24. // ……
  25. // ……
  26. // 包含了所有时区标示符的索引数组
  27. var_dump(DateTimeZone::listIdentifiers());
  28. // array(426) {
  29. // [0]=>
  30. // string(14) "Africa/Abidjan"
  31. // [1]=>
  32. // string(12) "Africa/Accra"
  33. // [2]=>
  34. // string(18) "Africa/Addis_Ababa"
  35. // [3]=>
  36. // string(14) "Africa/Algiers"
  37. // ……
  38. // ……

listAbbreviations() 静态方法返回的是 夏令时 相关的时差和时区信息。夏令时 和 冬令时 也是西方国家的一种生活标准,我们接触的不多,这里就不做讲解了,对于做跨境项目或者欧美外包的同学应该不会陌生。listIdentifiers() 方法返回的是包含了所有时区标示符的索引数组,这里可以看到所有的支持的时区信息。

日期间隔操作

对时日期时间的间隔操作,或许大家多少都做过一点,比如 DateTime 对象的那个 diff() 方法。

  1. $today = new DateTime('2020-09-27');
  2. $beforeYestoday = new DateTime("2020-09-25");
  3. var_dump($today->diff($beforeYestoday));
  4. // object(DateInterval)#5 (16) {
  5. // ["y"]=>
  6. // int(0)
  7. // ["m"]=>
  8. // int(0)
  9. // ["d"]=>
  10. // int(2)
  11. // ["h"]=>
  12. // int(0)
  13. // ["i"]=>
  14. // int(0)
  15. // ["s"]=>
  16. // int(0)
  17. // ["f"]=>
  18. // float(0)
  19. // ["weekday"]=>
  20. // int(0)
  21. // ["weekday_behavior"]=>
  22. // int(0)
  23. // ["first_last_day_of"]=>
  24. // int(0)
  25. // ["invert"]=>
  26. // int(1)
  27. // ["days"]=>
  28. // int(2)
  29. // ["special_type"]=>
  30. // int(0)
  31. // ["special_amount"]=>
  32. // int(0)
  33. // ["have_weekday_relative"]=>
  34. // int(0)
  35. // ["have_special_relative"]=>
  36. // int(0)
  37. // }

从打印的结果可以看出,diff() 对象返回的是一个 DateInterval 对象。这个就是我们这节的主角了,关于它打印出来的这些属性内容就不多解释了,字段名已经非常直观了,值就是具体的差值。

  1. $interval = new DateInterval("P2D");
  2. var_dump($interval);
  3. // object(DateInterval)#2 (16) {
  4. // ["y"]=>
  5. // int(0)
  6. // ["m"]=>
  7. // int(0)
  8. // ["d"]=>
  9. // int(2)
  10. // ["h"]=>
  11. // int(0)
  12. // ["i"]=>
  13. // int(0)
  14. // ["s"]=>
  15. // int(0)
  16. // ["f"]=>
  17. // float(0)
  18. // ["weekday"]=>
  19. // int(0)
  20. // ["weekday_behavior"]=>
  21. // int(0)
  22. // ["first_last_day_of"]=>
  23. // int(0)
  24. // ["invert"]=>
  25. // int(0)
  26. // ["days"]=>
  27. // bool(false)
  28. // ["special_type"]=>
  29. // int(0)
  30. // ["special_amount"]=>
  31. // int(0)
  32. // ["have_weekday_relative"]=>
  33. // int(0)
  34. // ["have_special_relative"]=>
  35. // int(0)
  36. // }

看到没有?打印出来的内容和上面用 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

  1. $interval = new DateInterval("P2Y4DT6H8M");
  2. var_dump($interval);
  3. // object(DateInterval)#5 (16) {
  4. // ["y"]=>
  5. // int(2)
  6. // ["m"]=>
  7. // int(0)
  8. // ["d"]=>
  9. // int(4)
  10. // ["h"]=>
  11. // int(6)
  12. // ["i"]=>
  13. // int(8)
  14. // ["s"]=>
  15. // int(0)
  16. // ["f"]=>
  17. // float(0)
  18. // ["weekday"]=>
  19. // int(0)
  20. // ["weekday_behavior"]=>
  21. // int(0)
  22. // ["first_last_day_of"]=>
  23. // int(0)
  24. // ["invert"]=>
  25. // int(0)
  26. // ["days"]=>
  27. // bool(false)
  28. // ["special_type"]=>
  29. // int(0)
  30. // ["special_amount"]=>
  31. // int(0)
  32. // ["have_weekday_relative"]=>
  33. // int(0)
  34. // ["have_special_relative"]=>
  35. // int(0)
  36. // }

我们还可以通过字段串形式的日期数据返回间隔对象,比如:

  1. // 从日期语句创建时间间隔
  2. var_dump(DateInterval::createFromDateString('2 days'));
  3. // object(DateInterval)#3 (16) {
  4. // ["y"]=>
  5. // int(0)
  6. // ["m"]=>
  7. // int(0)
  8. // ["d"]=>
  9. // int(2)
  10. // ["h"]=>
  11. // int(0)
  12. // ["i"]=>
  13. // int(0)
  14. // ["s"]=>
  15. // int(0)
  16. // ["f"]=>
  17. // float(0)
  18. // ["weekday"]=>
  19. // int(0)
  20. // ["weekday_behavior"]=>
  21. // int(0)
  22. // ["first_last_day_of"]=>
  23. // int(0)
  24. // ["invert"]=>
  25. // int(0)
  26. // ["days"]=>
  27. // bool(false)
  28. // ["special_type"]=>
  29. // int(0)
  30. // ["special_amount"]=>
  31. // int(0)
  32. // ["have_weekday_relative"]=>
  33. // int(0)
  34. // ["have_special_relative"]=>
  35. // int(0)
  36. // }

此外,在获得对象后进行输出的时候,DateInterval 对象也为我们提供了一个 format() 方法,可以像 printf() 函数一样来格式化地输出日期信息,而且这里用的格式符还是日期的格式符。

  1. var_dump($interval->format('%y %d %h %i'));
  2. // string(7) "2 4 6 8"

输出的内容其实就是属性中对应的那些日期和时间差值。

时间周期相关函数

说完时间间隔了,我们再来看看时间周期。时间周期是个什么概念呢?就比如说我们要每三天间隔一次地获取日期,这时就可以用时间周期相关的类来进行处理。

  1. $start = new DateTime('2020-09-01');
  2. $interval = new DateInterval('P7D');
  3. $end = new DateTime('2020-09-30');
  4. $daterange = new DatePeriod($start, $interval ,$end);
  5. var_dump($daterange);
  6. // object(DatePeriod)#7 (6) {
  7. // ["start"]=>
  8. // object(DateTime)#8 (3) {
  9. // ["date"]=>
  10. // string(26) "2020-09-01 00:00:00.000000"
  11. // ["timezone_type"]=>
  12. // int(3)
  13. // ["timezone"]=>
  14. // string(13) "Asia/Shanghai"
  15. // }
  16. // ["current"]=>
  17. // NULL
  18. // ["end"]=>
  19. // object(DateTime)#9 (3) {
  20. // ["date"]=>
  21. // string(26) "2020-09-30 00:00:00.000000"
  22. // ["timezone_type"]=>
  23. // int(3)
  24. // ["timezone"]=>
  25. // string(13) "Asia/Shanghai"
  26. // }
  27. // ["interval"]=>
  28. // object(DateInterval)#10 (16) {
  29. // ["y"]=>
  30. // int(0)
  31. // ["m"]=>
  32. // int(0)
  33. // ["d"]=>
  34. // int(7)
  35. // ["h"]=>
  36. // int(0)
  37. // ["i"]=>
  38. // int(0)
  39. // ["s"]=>
  40. // int(0)
  41. // ["f"]=>
  42. // float(0)
  43. // ["weekday"]=>
  44. // int(0)
  45. // ["weekday_behavior"]=>
  46. // int(0)
  47. // ["first_last_day_of"]=>
  48. // int(0)
  49. // ["invert"]=>
  50. // int(0)
  51. // ["days"]=>
  52. // bool(false)
  53. // ["special_type"]=>
  54. // int(0)
  55. // ["special_amount"]=>
  56. // int(0)
  57. // ["have_weekday_relative"]=>
  58. // int(0)
  59. // ["have_special_relative"]=>
  60. // int(0)
  61. // }
  62. // ["recurrences"]=>
  63. // int(1)
  64. // ["include_start_date"]=>
  65. // bool(true)
  66. // }
  67. foreach($daterange as $date){
  68. echo $date->format("Ymd"), PHP_EOL;
  69. }
  70. // 20200901
  71. // 20200908
  72. // 20200915
  73. // 20200922
  74. // 20200929

首先设定了开始时间和结束时间以及一个时间间隔对象,然后用它们做为参数来生成一个 DatePeriod 时间周期对象。它是一个实现了迭代器的对象,所以我们可以直接遍历它,结果就是以 P7D ,也就是 7 天为间隔的一组日期数据。

  1. var_dump($daterange->getDateInterval());
  2. // object(DateInterval)#11 (16) {
  3. // ["y"]=>
  4. // int(0)
  5. // ["m"]=>
  6. // int(0)
  7. // ["d"]=>
  8. // int(7)
  9. // ["h"]=>
  10. // int(0)
  11. // ["i"]=>
  12. // int(0)
  13. // ["s"]=>
  14. // int(0)
  15. // ["f"]=>
  16. // float(0)
  17. // ["weekday"]=>
  18. // int(0)
  19. // ["weekday_behavior"]=>
  20. // int(0)
  21. // ["first_last_day_of"]=>
  22. // int(0)
  23. // ["invert"]=>
  24. // int(0)
  25. // ["days"]=>
  26. // bool(false)
  27. // ["special_type"]=>
  28. // int(0)
  29. // ["special_amount"]=>
  30. // int(0)
  31. // ["have_weekday_relative"]=>
  32. // int(0)
  33. // ["have_special_relative"]=>
  34. // int(0)
  35. // }
  36. var_dump($daterange->getStartDate());
  37. // object(DateTime)#11 (3) {
  38. // ["date"]=>
  39. // string(26) "2020-09-01 00:00:00.000000"
  40. // ["timezone_type"]=>
  41. // int(3)
  42. // ["timezone"]=>
  43. // string(13) "Asia/Shanghai"
  44. // }
  45. var_dump($daterange->getEndDate());
  46. // object(DateTime)#11 (3) {
  47. // ["date"]=>
  48. // string(26) "2020-09-30 00:00:00.000000"
  49. // ["timezone_type"]=>
  50. // int(3)
  51. // ["timezone"]=>
  52. // string(13) "Asia/Shanghai"
  53. // }

它的这一堆方法其实返回的就是我们定义的那些构造参数信息。另外,它还可以指定从开始日期往后按照时间间隔返回几条信息。

  1. $period = new DatePeriod($start, $interval, 4);
  2. foreach($period as $date){
  3. echo $date->format("Ymd"), PHP_EOL;
  4. }
  5. // 20200901
  6. // 20200908
  7. // 20200915
  8. // 20200922
  9. // 20200929
  10. var_dump($period->getRecurrences());
  11. // 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. sqli-labs lesson 32-37

    宽字节注入: 原理:mysql在使用GBK编码的时候,会认为两个字符为一个汉字,例如%aa%5c就是一个汉字(前一个ascii码大于128才能到汉字的范围).我们在过滤 ' 的时候(也就是从防御的角度 ...

  2. Linux 多进程编程实例(一)

    文章目录 目标: main.c process1.c process2.c 目标: 一个进程,创建两个子进程,利用exec函数族使两个子进程执行不同的程序.子进程1执行ls -l命令后正常返回,子进程 ...

  3. uniapp 实现信息推送(App)

    废话不多说直接上代码 以下代码需写在onlaunch生命周期内 onlaunch(){// onlaunch应用级生命周期 :当uni-app 初始化完成时触发(全局只触发一次) //#ifdef A ...

  4. SQL 练习14

    查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩 SELECT Student.SId,Student.Sname,t.不及格课程数,t.平均成绩 from Student, (SELECT ...

  5. idea的properties文件乱码问题解决

    设置编码格式: File============>Settings,打开设置后,设置成下面的即可解决:

  6. windows10磁盘分区后,如何恢复分区,回到未分区之前

    windows10磁盘分区后,恢复到分区以前的状态 1.我的电脑右键======>管理 2.找到磁盘管理 3.因为我的H盘原来是和F盘是同一个分区,只是拆分出来了,所有,找到H盘(确保数据都做过 ...

  7. html,javascript,正则表达式

    正则表达式是对字符串操作的逻辑公式,用事先定好的一些特定字符组成一个"规则字符串",在用"规则字符串"对字符串进行过滤. ECMAScript 通过RegExp ...

  8. npm常用命令及其node相关工具汇总

    它是一个事件驱动异步I/O单进程的服务端JS环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好. 浏览器是JS的前端运行环境. Node.js是JS的后端运行环 ...

  9. 【java虚拟机】分代垃圾回收策略的基础概念

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/6602166.html 一.为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一 ...

  10. linux(4)----------ssh config详解

    1.概述 ~~  config为了方便我们批量管理多个ssh ~~  config存放在~/.ssh/config                 .XX代表隐藏目录 ~~  config配置语法 2 ...