PHP强化之05 - 时间 Date/Time(新)

2022-01-16  本文已影响0人  四月不见

----- 最近更新时间【2022-01-16】-----

PHP强化系列--目录

一、简介

日期和时间信息在 PHP 内部是以 64 位数字存储的, 它可以覆盖当前时间前后 2920 亿年的时间,这个范围之广,足以满足现有应用的实际需求。

注意: 需要注意的是, 这些函数都是依赖服务器的区域设置的。 所以在使用它们的时候,要考虑夏令时 (例如:使用 $date = strtotime('+7 days', $date) 而不是 $date += 7*24*60*60) 和闰年的情况。

夏令时:
一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。全世界有近110个国家每年要实行夏令时。
中国:
从1986年到1991年的六个年度,每年从四月中旬第一个星期日的凌晨2时整(北京时间),将时钟拨快一小时,即将表针由2时拨至3时,夏令时开始;到九月中旬第一个星期日的凌晨2时整(北京夏令时),再将时钟拨回一小时,即将表针由2时拨至1时,夏令时结束。1992年起,夏令时暂停实行。
闰年:
闰年是历法中的名词,分为普通闰年和世纪闰年。(平年有365天)
闰年是为了弥补因人为历法规定造成的年度天数与地球实际公转周期的时间差而设立的,共有366天(1月~12月分别为31天、29天、31天、30天、31天、30天、31天、31天、30天、31天、30天、31天)。
普通闰年:公历年份是4的倍数,且不是100的倍数的,为闰年(如2004年、2020年等就是闰年)。
世纪闰年:公历年份是整百数的,必须是400的倍数才是闰年(如1900年不是闰年,2000年是闰年)。

二、时区设置

PHP 的时区设置可在配置文件 php.ini 或 httpd.conf 中修改,或者者使用相关的函数,如 date_default_timezone_set()ini_set()

1、查看配置文件目录

1)在 linux 中

[nosee@instance-4 ~]$ sudo find / -name httpd.conf
[nosee@instance-4 ~]$ sudo find / -name php.ini
/etc/php/7.3/apache2/php.ini  (apache模式,Apache 默认配置文件)
/etc/php/7.3/fpm/php.ini      (fpm模式,Nginx 默认配置文件)
/etc/php/7.3/cli/php.ini      (命令行模式下的配置文件)

2)在 window 中,php.ini就位于php的安装目录。
3)使用 phpinfo()函数查找配置文件目录。
4)还可以用函数 php_ini_scanned_files()查看php的额外配置文件。

2、设置时区

如果时区没有被设置,那么默认时区为:UTC 。
中国与 UTC 的时差为 +8,即 UTC 的时间加上8小时就等于中国时区了。

1)修改 php.ini 文件

date.timezone = Asia/Shanghai

2)使用 date_default_timezone_set 函数

date_default_timezone_set('America/Los_Angeles');

可以使用函数 date_default_timezone_get()查看你当前服务器的默认时区。

3)使用 ini_set 函数

ini_set('date.timezone','Asia/Shanghai'); 

3、查看时区设置

php 中可以使用函数 date_default_timezone_get() 查看默认时区设置。

php > echo date_default_timezone_get() ;
UTC

4、UTC 与 GMT

协调世界时(UTC,Universal Time Coordinated) ,又称世界统一时间、世界标准时间、国际协调时间。由于英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称 UTC。

协调世界时 与 格林尼治标准时(GMT, Greenwich MeanTime)一样,都与英国伦敦的本地时相同。为了方便,在不需要精确到秒的情况下,通常将GMT 和UTC 视作等同。但UTC 更加科学更加精确。

区别:
UTC是我们现在用得时间标准,GMT是老的时间计量标准。
UTC是根据原子钟来计算时间(最精确原子钟问世:50亿年误差一秒),而GMT是根据地球的自转和公转来计算时间,也就是太阳每天经过英国伦敦郊区的皇家格林威治天文台的时间就是中午12点。

UTC不与任何地区位置相关,也不代表此刻某地的时间,所以在说明某地时间时要加上时区。也就是说GMT并不等于UTC,而是等于UTC+0,只是格林尼治刚好在0时区上。

注意:在PHP中不支持如CST、PST 这类时区表示法,如表示中国时区应该使用 Asia/Shanghai 而不是 CST。

可在这个链接查看 PHP 支持的所有时区列表:https://www.php.net/manual/zh/timezones.php

三、2038年问题

2038年1月19日凌晨3:14:07(UTC)是自1970年1月1日0点后的2147483647秒。2147483647有什么特殊?它恰好是(2的31次方-1),如果使用32位表示一个有符号整数,这将是可表示的最大整数(第32位用来表示正负号)。

php > echo pow(2, 31)-1;
2147483647

有效的时间戳典型范围是格林威治时间 1901 年 12 月 13 日 20:45:54 到 2038 年 1 月 19 日 03:14:07。(此范围符合 32 位有符号整数的最小值和最大值)。不过在 PHP 5.1 之前此范围在某些系统(如 Windows)中限制为从 1970 年 1 月 1 日到 2038 年 1 月 19 日。

64位系统则不会有以上问题,它可以覆盖当前时间前后 2920 亿年的时间,足以够我们使用。

php > var_dump(date('Y-m-d H:i:s', 9223372036854775807));
string(27) "292277026596-12-04 15:30:07"
php > var_dump(date('Y-m-d H:i:s', 9223372036854775808));
PHP Warning:  date() expects parameter 2 to be int, float given in php shell code on line 1
bool(false)

注:9223372036854775807 为 2的63次方再减1 的值。

四、常用方法

1、日期格式化(时间戳转化成日期字符串):date、gmdate、strftime

PHP 有许多函数可以使用 format 参数,即一些特殊的格式字串,如 date 函数。
格式字串可以识别以下 format 参数的字符串(格式字串中不能被识别的字符将原样显示)。

format字符 说明 返回值例子
--- ---
d 月份中的第几天,有前导零的 2 位数字 0131
D 星期中的第几天,文本表示,3 个字母 MonSun
j 月份中的第几天,没有前导零 131
l(小写"L") 星期几,完整的文本格式 SundaySaturday
N ISO-8601 格式数字表示的星期中的第几天 1(表示星期一)到 7(表示星期天)
S(大写S) 每月天数后面的英文后缀,2 个字符 st,nd,rd或者th。可以和j一起用
w(小写W) 星期中的第几天,数字表示 0(表示星期天)到 6(表示星期六)
z(小写Z) 年份中的第几天。(未满一天不算?) 0365
星期 --- ---
W(大写W) ISO-8601 格式年份中的第几周,每周从星期一开始 例如:42(当年的第 42 周)
--- ---
F 月份,完整的文本格式,例如 January 或者 March JanuaryDecember
m 数字表示的月份,有前导零 0112
M 三个字母缩写表示的月份 JanDec
n 数字表示的月份,没有前导零 112
t 指定的月份有几天 2831
--- ---
L 是否为闰年 如果是闰年为 1,否则为 0
o(小写o) ISO-8601 格式年份数字。这和 Y 的值相同,只除了如果
ISO 的星期数(W)属于前一年或下一年,则用那一年。
Examples: 1999 or 2003
Y 4 位数字完整表示的年份 例如:19992003
y 2 位数字表示的年份 例如:9903
时间 --- ---
a 小写的上午和下午值 ampm
A 大写的上午和下午值 AMPM
B Swatch因特网时间 000999
g 小时,12 小时格式,没有前导零 112
G 小时,24 小时格式,没有前导零 023
h 小时,12 小时格式,有前导零 0112
H 小时,24 小时格式,有前导零 0023
i 有前导零的分钟数 0059>
s(小写s) 秒数,有前导零 0059>
u(小写U) 微秒。需要注意的是date()函数总是返回 000000 因为它只
接受 integer 参数, 而 DateTime::format()才支持微秒。
示例: 654321
时区 --- ---
e 时区标识 例如:UTCGMTAtlantic/Azores
I((大写i)) 是否为夏令时 如果是夏令时为 1,否则为 0
O(大写O) 与格林威治时间相差的小时和分钟数(没有冒号分隔) 例如:+0200
P(大写P) 与格林威治时间相差的小时和分钟数(有冒号分隔) 例如:+02:00
p(小写P) The same as P, but returns Z instead of +00:00 (PHP8.0新加) 例如:+02:00
T 本机所在的时区(缩写),未知则为GMT的偏移量
(【译者注】在 Windows 下为完整文本格式,例如"Eastern
Standard Time",中文版会显示"中国标准时间")。
例如:EST,MDT,CST,+05
Z(大写Z) 时差偏移量的秒数。UTC 西边的时区偏移量总是负的,
UTC 东边的时区偏移量总是正的。
-4320043200 (43200秒为12小时)
完整的
日期/时间
--- ---
c(小写C) ISO 8601 格式的日期(PHP 5 新加) 例如:2004-02-12T15:19:21+00:00
r RFC 822 格式的日期 例如:Thu, 21 Dec 2000 16:01:07 +0200
U(大写U) 从 Unix 纪元(1970-1-1 00:00:00 GMT)开始至今的秒数 time()的值

注:1秒(s)=1000毫秒(ms), 1秒(s)=1000000 微秒(μs)

1)date - 格式化一个本地时间/日期

语法:date(string $format, ?int $timestamp = null): string
返回将整数 timestamp 按照给定的格式字串而产生的字符串。如果 timestamp 未指定或是 null,则使用默认值time()

例:

php > ini_set('date.timezone','Asia/Shanghai');
php > var_dump(date('Y-m-d H:i:s'));
string(19) "2022-01-16 12:05:04"
php > var_dump(date('Y-m-d H:i:sP'));
string(25) "2022-01-16 12:05:05+08:00"
php > var_dump(date('T Y-m-d H:i:sP'));
string(29) "CST 2022-01-16 12:11:42+08:00"
php > var_dump(date('e Y-m-d H:i:s'));
string(33) "Asia/Shanghai 2022-01-16 12:31:06"

例:查看微秒(需要使用 DateTime 类 或者 使用函数:date_createdate_format

php > var_dump(date('Y-m-d H:i:s u'));
string(26) "2022-01-16 12:37:44 000000"   / / 这里返回 000000 是因为 date 函数不支持毫秒运算
// 方法一:过程化风格
php > $date = date_create();
php > echo date_format($date,'Y-m-d H:i:s u');
2022-01-16 12:45:31 327165
// 方法二:面向对象风格
php > $date1 = new DateTime();
php > echo $date1->format('Y-m-d H:i:s u');
2022-01-16 12:51:41 030498

2)gmdate - 格式化一个 GMT/UTC 日期/时间

语法:gmdate(string $format, ?int $timestamp = null): string
该函数功能和 date函数一样,除了返回的时间是格林威治标准时(GMT)。

例:前面我已经将时区设置为ini_set('date.timezone','Asia/Shanghai');

php > var_dump(date('T Y-m-d H:i:s'));
string(23) "CST 2022-01-16 13:33:13"
php > var_dump(gmdate('T Y-m-d H:i:s'));
string(23) "GMT 2022-01-16 05:33:15"

3)strftime - 根据区域设置格式化本地时间/日期

string strftime ( string $format [, int $timestamp = time() ] )

返回用给定的格式字串对给出的 timestamp 进行格式输出后的字符串。如果没有给出时间戳则用当前的本地时间。

注:从 PHP 8.1.0 开始,该函数已被弃用,所以也不建议使用了。

2、获取日期详情(数组):getdate、localtime

1)getdate - 取得日期/时间信息
语法:getdate(?int $timestamp = null): array
返回一个根据 timestamp 得出的包含有日期信息的关联数组 array。如果没有给出时间戳则认为是当前本地时间。

例:

php > print_r(getdate());
Array
(
    [seconds] => 58
    [minutes] => 33
    [hours] => 20
    [mday] => 16
    [wday] => 0
    [mon] => 1
    [year] => 2022
    [yday] => 15
    [weekday] => Sunday
    [month] => January
    [0] => 1642336438
)

返回的关联数组中的键名单元:

键名 说明 返回值例子
"seconds" 秒的数字表示 059
"minutes" 分钟的数字表示 059
"hours" 小时的数字表示 023
"mday" 月份中第几天的数字表示 131
"wday" 星期中第几天的数字表示 0 (周日) 到 6 (周六)
"mon" 月份的数字表示 112
"year" 4 位数字表示的完整年份 比如: 19992003
"yday" 一年中第几天的数字表示 0365
"weekday" 星期几的完整文本表示 SundaySaturday
"month" 月份的完整文本表示,比如 January 或 March JanuaryDecember
0 自从 Unix 纪元开始至今的秒数,和 time()的返回值以及用于 date()的值类似。 系统相关,典型值为从 -21474836482147483647

2)localtime - 取得本地时间,返回一个关联数组
语法:localtime(?int $timestamp = null, bool $associative = false): array

例:个人感觉没有getdate函数好用。

php > print_r(localtime());
Array
(
    [0] => 39
    [1] => 40
    [2] => 20
    [3] => 16
    [4] => 0
    [5] => 122
    [6] => 0
    [7] => 15
    [8] => 0
)
php > print_r(localtime(time(),1));
Array
(
    [tm_sec] => 40
    [tm_min] => 40
    [tm_hour] => 20
    [tm_mday] => 16
    [tm_mon] => 0
    [tm_year] => 122
    [tm_wday] => 0
    [tm_yday] => 15
    [tm_isdst] => 0
)

3、取得一个日期的时间戳:time、microtime、strtotime、mktime

1)time - 返回当前的 Unix 时间戳
语法:time() : int

返回自从 Unix 纪元(January 1 1970 00:00:00 GMT) 到当前时间的秒数。 该函数是php时间函数中使用频率最高的一个函数。

2)microtime - 返回当前 Unix 时间戳和微秒数
语法:microtime(bool $as_float = false): string|float

例:

php > var_dump(microtime(1),time());
float(1642337661.363878)
int(1642337661)
php > var_dump(microtime(),time());
string(21) "0.53894800 1642337662"
int(1642337662)

相关函数:

3)strtotime - 将任何字符串的日期时间描述解析为 Unix 时间戳
语法:strtotime(string $datetime, ?int $baseTimestamp = null): int|false

本函数预期接受一个包含美国英语日期格式的字符串并尝试将其解析为 Unix 时间戳。
更多支持的日期格式字符串请查看:
https://www.php.net/manual/en/datetime.formats.php

例:

//今天此刻的时间是"0 days",等价于date("Y-m-d H:i:s")
php > echo date("Y-m-d H:i:s", strtotime("0 days")) ;
2022-01-16 21:19:15

//昨天此刻的时间是"-1 days",明天则是 "1 days",前天则是"-2 days";
date("Y-m-d H:i:s", strtotime("-1 days")) 
php > echo date("Y-m-d H:i:s", strtotime("1 days"));
2022-01-17 21:21:34

//获取指定日期$date所在月的第一天
php > $date = '2022-01-16';
php > echo date("Y-m-01", strtotime($date));
2022-01-01
php > echo date("Y-m-01", strtotime('0 day'));
2022-01-01

//获取指定日期$date所在月的最后一天
php > $date = '2022-01-16';
php > $firstday = date("Y-m-01", strtotime($date));
php > echo date("Y-m-d", strtotime("$firstday +1 month -1 day"));
2022-01-31

例:

//获得指定日期$day所在星期的第一天和最后一天
$lastday = date('Y-m-d', strtotime("$day Sunday"));
$firstday = date('Y-m-d', strtotime("$lastday -6 days"));

4)mktime - 取得一个日期的 Unix 时间戳

语法:

mktime(
  int $hour,
  int $minute = date("i"), 
  int $second = date("s"), 
  int $month = date("n"), 
  int $day = date("j"), 
  int $year = date("Y"),
) : int|false

注:PHP 8.0 开始 $hour 不再是可选参数.。

根据给出的参数返回 Unix 时间戳。时间戳是一个长整数,包含了从 Unix 纪元 (January 1 1970 00:00:00 GMT) 到给定时间的秒数。

参数可以从右向左省略,任何省略的参数会被设置成本地日期和时间的当前值。

mktime()在做日期计算和验证方面很有用,它会自动计算超出范围的输入的正确值。

例1:下面例子中每一行都会输出相同的结果"Jan-01-1998"

echo date("M-d-Y", mktime(0, 0, 0, 12, 32, 1997));
echo date("M-d-Y", mktime(0, 0, 0, 13, 1, 1997));
echo date("M-d-Y", mktime(0, 0, 0, 1, 1, 1998));
echo date("M-d-Y", mktime(0, 0, 0, 1, 1, 98));

例2:计算下个月的最后一天

任何给定月份的最后一天都可以被表示为下个月的第 "0" 天,而不是 -1 天。下面两个例子都是输出 "02-29"。

php > $lastday = mktime(0, 0, 0, 3, 0, 2000);
php > echo date("m-d", $lastday);
02-29
php > $lastday = mktime(0, 0, 0, 4, -31, 2000);
php > echo date('m-d',$lastday);
02-29

4、日期判断:checkdate

1)checkdate - 验证一个公历日期的正确性
语法:checkdate( int $month, int $day, int $year) : bool

例:

php > var_dump(checkdate(12, 31, 2000));
bool(true)
php > var_dump(checkdate(2, 29, 2001));
bool(false)

五、经典案例

1、求两个日期的差数,例如2007-2-5 ~ 2007-3-6 的日期差数

(strtotime($day2) - strtotime($day1)) / (3600*24);

六、参考:

官方文档:

相关书籍:

上一篇下一篇

猜你喜欢

热点阅读