乐趣区

关于php:学习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:06

IntlDateFormatter 对象就是国际化组件中对于日期格式化的操作类。它的结构参数很多,不过其实非常简单,第一个参数是国家区域设置,第二和第三个参数别离是日期和日间的显示格局,这个咱们下段代码将演示。第四个参数是时区设置,第五个参数是工夫标准,这里指定的是格里高利工夫。

应用 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 AM
echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL),PHP_EOL;
// Saturday, November 21, 2020 at 8:45:06 AM China Standard Time
echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::NONE, IntlDateFormatter::FULL),PHP_EOL;
// 20201121 08:45 AM
echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL, 'zh-CN'),PHP_EOL;
// 2020 年 11 月 21 日星期六 中国规范工夫 上午 8:45:06
echo 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;
// 1605834341

localtime() 办法就是用于解析给定的规范日期内容的,依据 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; // en
echo $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 z
echo $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; // 9
echo $fmt->getErrorMessage(), PHP_EOL; // Date parsing failed: U_PARSE_ERROR

parse() 办法没有任何输入了。同时通过 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

===========

各自媒体平台均可搜寻【硬核项目经理】

退出移动版