创意电子

标题: 学习PHP中的国际化日期格式化操纵 [打印本页]

作者: 码农老张Zy    时间: 2021-8-15 10:56
标题: 学习PHP中的国际化日期格式化操纵
对于国际化功能来说,日期相关的格式化操纵也是一块重头戏,毕竟不同的时区,不同的国家对于日期的表现方式都会有些不同。本日我们主要来学习的就是国际化地表现日期相关的信息内容。
日期格式化

起首就是最直接的格式化能力。
$fmt = new IntlDateFormatter( "en_US" ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,    'America/Los_Angeles',IntlDateFormatter::GREGORIAN  );echo "en_US 格式化结果为: ".$fmt->format(time()), PHP_EOL;// en_US 格式化结果为: Friday, November 20, 2020 at 4:45:06 PM Pacific Standard Time$fmt = new IntlDateFormatter( "de-DE" ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,     'America/Los_Angeles',IntlDateFormatter::GREGORIAN  );echo "de_DE 格式化结果为: ".$fmt->format(IntlCalendar::createInstance()), PHP_EOL;// de_DE 格式化结果为: Freitag, 20. November 2020 um 16:45:06 Nordamerikanische Westküsten-Normalzeit$fmt = new IntlDateFormatter( "zh-CN" ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,     'Asia/Shanghai',IntlDateFormatter::GREGORIAN  );echo "zh-CN 格式化结果为: ".$fmt->format(time()), PHP_EOL;// zh-CN 格式化结果为: 2020年11月21日星期六 中国标定时间 上午8:45:06IntlDateFormatter 对象就是国际化组件中对于日期格式化的操纵类。它的构造参数很多,不过其实非常简单,第一个参数是国家地区设置,第二和第三个参数分别是日期和日间的显示格式,这个我们下段代码将演示。第四个参数是时区设置,第五个参数是时间规范,这里指定的是格里高利时间。
使用 format() 方法就可以对时间戳或者日历对象举行日期时间的格式化。它只能接收这两种类型的参数并举行格式化。它会根据 IntlDateFormatter 对象所设置的各种参数举行输出,比如输出的语言是英语、德语、中文等,输出的时间是按时区(中国8点,美国下午4点)。
对于日期和时间的显示格式,我们可以使用几个 IntlDateFormatter 类的常量来表现,主要有 FULL 、 SHORT 、MEDIUM、 LONG 这些类型。
$fmt = new IntlDateFormatter( "zh-CN" ,IntlDateFormatter::SHORT, IntlDateFormatter::LONG,     'Asia/Shanghai',IntlDateFormatter::GREGORIAN  );echo "zh-CN 格式化结果为: ".$fmt->format(time()), PHP_EOL;// zh-CN 格式化结果为: 2020/11/21 GMT+8 上午8:45:06别的,构造函数的第六个参数是可以指定格式化的格式规则的。
$fmt = new IntlDateFormatter( "zh-CN" ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,     'Asia/Shanghai',IntlDateFormatter::GREGORIAN, 'yyyy/MM/dd' );echo "zh-CN 格式化结果为: ".$fmt->format(time()), PHP_EOL;// zh-CN 格式化结果为: 2020/11/21根据指定对象格式化日期

上文中的 format() 方法我们看到只能使用时间戳和日历对象类型。其实还有另一种更强大的格式化方法,它就是 formatObject() 方法。从名字可以推断出,它是根据指定的对象来格式化日期数据。
$cal = IntlCalendar::createInstance(new DateTimeZone('Asia/Shanghai'));echo IntlDateFormatter::formatObject($cal),PHP_EOL;// Nov 21, 2020, 8:45:06 AMecho IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL),PHP_EOL;// Saturday, November 21, 2020 at 8:45:06 AM China Standard Timeecho IntlDateFormatter::formatObject($cal, IntlDateFormatter::NONE, IntlDateFormatter::FULL),PHP_EOL;// 20201121 08:45 AMecho IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL, 'zh-CN'),PHP_EOL;// 2020年11月21日星期六 中国标定时间 上午8:45:06echo IntlDateFormatter::formatObject($cal, "d 'of' MMMM y", 'zh-CN'), PHP_EOL;// 21 of 十一月 2020最常用的依然是对日历对象的格式化,可以看到 formatObject() 方法的参数更多一些,它也可以直接指定日期和时间的格式形式以及相关的语言设置。别的,它还可以指定丰富的输出规则,比如我们最后一段代码输出的是当天在这个月中是第几天。在 PHP中的国际化日历类 这篇文章中,我们也使用过这个方法来举行测试,自定义的语法规则非常多,各人可以本身查阅 ICU 相关的文档。
除了对于日历类的格式化之外,formatObject() 方法还可以对 DateTime 对象举行日期格式化地输出。
$dt = new DateTime();echo IntlDateFormatter::formatObject($dt),PHP_EOL;// Nov 21, 2020, 8:45:06 AM不过必要注意的是,从官方文档的 Note 来看,formatObject() 的速度非常慢,在 PHP5 下面与 format() 方法有 10 倍左右的差距,在 PHP7 下也有 3 倍左右的差距。所以说,如果不是有特别的需求的话,只管还是不要使用 formatObject() 这个方法来格式化日期时间。
反解析日期字符串

和之前我们在 学习PHP中国际化地数字格式处置惩罚 中讲过的一样,我们可以将对象或者时间戳格式化为标准的字符串格式显示,那么能不能将这种标准的字符串格式数据再反转回来呢?
$fmt = new IntlDateFormatter( "en_US" ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,    'America/Los_Angeles',IntlDateFormatter::GREGORIAN  );$arr = $fmt->localtime($fmt->format(time()));print_r($arr);// Array// (//     [tm_sec] => 1//     [tm_min] => 59//     [tm_hour] => 16//     [tm_year] => 120//     [tm_mday] => 20//     [tm_wday] => 5//     [tm_yday] => 325//     [tm_mon] => 10//     [tm_isdst] => 0// )echo $fmt->parse("Thursday, November 19, 2020 at 5:05:41 PM Pacific Standard Time"), PHP_EOL;// 1605834341localtime() 方法就是用于解析给定的标准日期内容的,根据 IntlDateFormatter 初始化时的规则,将字符串的内容反向输出为一个数组,其中包罗了年、月、日、时、分、秒等信息。而 parse() 方法则是直接将给定的内容转换为对应的时间戳。
$fmt = new IntlDateFormatter( "zh-CN" ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,     'Asia/Shanghai',IntlDateFormatter::GREGORIAN );$arr = $fmt->localtime("2020年11月20日星期五 中国标定时间 上午8:54:08");print_r($arr);// Array// (//     [tm_sec] => 8//     [tm_min] => 54//     [tm_hour] => 8//     [tm_year] => 120//     [tm_mday] => 20//     [tm_wday] => 5//     [tm_yday] => 325//     [tm_mon] => 10//     [tm_isdst] => 0// )echo $fmt->parse("2020年11月20日星期五 中国标定时间 上午8:54:08"), PHP_EOL;// 1605833648不管是中英文都是良好支持的。
相关属性获取及设置

日历类型信息

对于日历类型来说,只有两种类型的日历,GREGORIAN 和 TRADITIONAL,分别对应的是格里高利和传统日历。在构造参数中我们可以通过第五个参数指定,也可以在对象使用的过程中使用 setCalendar() 方法来设置。getCalendar() 方法用于获取当前设置的日期类型信息。
$fmt = new IntlDateFormatter( "en_US" ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,     'America/Los_Angeles',IntlDateFormatter::GREGORIAN );echo $fmt->getCalendar(), PHP_EOL; // 1$fmt->setCalendar(IntlDateFormatter::TRADITIONAL);echo $fmt->getCalendar(), PHP_EOL; // 0日期和时间类型

// 日期类型获取及设置$fmt = new IntlDateFormatter( "en_US" ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,     'America/Los_Angeles',IntlDateFormatter::GREGORIAN );echo $fmt->getDateType(), PHP_EOL; // 0$fmt = new IntlDateFormatter( "en_US" ,IntlDateFormatter::SHORT, IntlDateFormatter::FULL,     'America/Los_Angeles',IntlDateFormatter::GREGORIAN );echo $fmt->getDateType(), PHP_EOL; // 3// 时间类型获取及设置echo $fmt->getTimeType(), PHP_EOL; // 0$fmt = new IntlDateFormatter( "en_US" ,IntlDateFormatter::SHORT, IntlDateFormatter::MEDIUM,     'America/Los_Angeles',IntlDateFormatter::GREGORIAN );echo $fmt->getTimeType(), PHP_EOL; // 2对于日期和时间类型来说,我们只能通过构造函数的参数举行指定,获取到的也是对应常量的值。
地区语言信息

echo $fmt->getLocale(), PHP_EOL; // enecho $fmt->getLocale(Locale::VALID_LOCALE), PHP_EOL; // en_US这个就不多做解释了,之前的文章中都有,似乎国际化相关组件的类中都会包罗这两个方法。
格式规则获取及设置

我们可以在构造函数的第六个参数中指定格式化的规则,同时也可以对对象进举措态的设置。
echo $fmt->getPattern(), PHP_EOL; // M/d/yy, h:mm:ss a$fmt->setPattern('yyyyMMdd hh:mm:ss z');echo $fmt->getPattern(), PHP_EOL; // yyyyMMdd hh:mm:ss zecho $fmt->format(time()), PHP_EOL; // 20201120 04:59:01 PST使用 setPattern() 设置格式规则之后,再次举行 formar() 就是以新的格式规则举行格式化了。
时区设置

起首我们来看一个 getTimezoneId() 方法。它是直接获取时区内容的,也就是一个字符串。
echo $fmt->getTimezoneId(), PHP_EOL; // America/Los_Angeles// $fmt->setTimeZoneId('CN'); // PHP7 已删除// echo $fmt->getTimezoneId(), PHP_EOL;不过在 PHP7 中已经删除了 setTimezoneId() 方法,如今保举是使用 setTimezone() 方法来设置时区信息,我们马上来看看。
var_dump($fmt->getTimezone());// object(IntlTimeZone)#4 (4) {//     ["valid"]=>//     bool(true)//     ["id"]=>//     string(19) "America/Los_Angeles"//     ["rawOffset"]=>//     int(-28800000)//     ["currentOffset"]=>//     int(-28800000)//   }$fmt->setTimeZone('Asia/Shanghai');var_dump($fmt->getTimezone());// object(IntlTimeZone)#4 (4) {//     ["valid"]=>//     bool(true)//     ["id"]=>//     string(13) "Asia/Shanghai"//     ["rawOffset"]=>//     int(28800000)//     ["currentOffset"]=>//     int(28800000)//   }$fmt->setTimeZone('GMT+00:30');var_dump($fmt->getTimezone());// object(IntlTimeZone)#4 (4) {//     ["valid"]=>//     bool(true)//     ["id"]=>//     string(9) "GMT+00:30"//     ["rawOffset"]=>//     int(1800000)//     ["currentOffset"]=>//     int(1800000)//   }与 getTimezoneId() 方法不同的是,getTimezone() 方法返回的是一个 IntlTimeZone 对象,关于这个对象的内容官方文档不全,很多方法参数都没有写,我也不好猜测,所以不会写这个对象的文章,各人可以本身查阅相关的资料。不过对于简单的设置时区来说,setTimezone() 方法可以直接使用字符串做为参数。比如我们在上面的代码分别将美国洛杉矶的时区修改为中国上海以及GMT+00:30这两种时区。对应地,如果我们再 format() 输出时间的话,就是以当前时区的标定时间为准举行输出了。
获取日历对象

本身在格式化数据的时候,我们就与日历对象打了很多交道,当然通过 IntlDateFormatter 对象我们也是可以得到日历信息的。
$cal = $fmt->getCalendarObject();var_dump(    $cal->getType(),    $cal->getTimeZone(),    $cal->getLocale(Locale::VALID_LOCALE));// string(9) "gregorian"// object(IntlTimeZone)#3 (4) {//   ["valid"]=>//   bool(true)//   ["id"]=>//   string(9) "GMT+00:30"//   ["rawOffset"]=>//   int(1800000)//   ["currentOffset"]=>//   int(1800000)// }// string(5) "en_US"宽容能力

最后我们再看一下宽容能力,其实也就是一种严格模式的操纵。比如我们如果定义一个错误的时间,IntlDateFormatter 中的操纵并不会报错,因为它默认是宽容处置惩罚的。
$fmt->setPattern('dd/mm/yyyy');var_dump($fmt->isLenient()); // bool(true)echo $fmt->parse('35/13/1955'), PHP_EOL;// -470449020很显着,这个日期是一个错误的日期。通过 isLenient() 方法我们可以获取当前是否是宽容处置惩罚的状态。我们如今将宽容处置惩罚的能力取消掉,再看看会是什么结果。
$fmt->setLenient(FALSE);echo $fmt->parse('35/13/1955'), PHP_EOL;// echo $fmt->getErrorCode(), PHP_EOL; // 9echo $fmt->getErrorMessage(), PHP_EOL; // Date parsing failed: U_PARSE_ERRORparse() 方法没有任何输出了。同时通过 getErrorCode() 和 getErrorMessage() 也看到了错误信息。这就是 IntlDateFormatter 对象中宽容处置惩罚的主要能力。
总结

本日学习的内容比较多和零散,不过主要都是 IntlDateFormatter 这个对象的内容。数字和日期格式是国际化相关功能中最主要的功能,也可以或许随时应用到我们的一样平常业务开发中,各人可以多多地学习了解相关的知识。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202011/source/8.学习PHP中的国际化日期格式化操纵.php
参考文档:
https://www.php.net/manual/zh/class.intldateformatter.php




欢迎光临 创意电子 (https://www.wxcydz.cc/) Powered by Discuz! X3.4