在 PHP 的国际化组件中,还有一个我们并不是很常用的跟日期相关的操作类,它就是日历操作类。说是日历,其实大部分还是对日期时间的操作,一般也是主要用于日期的格式化和比较之类的。但是通常我们直接使用 date 相关的函数或者 DateTime 相关的类操作日期相关的功能,反而比这套日历的功能更方便灵活。当然,本着学习的目的,我们还是来简单地了解一下。

格式化时间

首先还是从格式化时间说起。

$cal = IntlCalendar::createInstance(IntlTimeZone::getGMT());var_dump(get_class($cal), IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL));// string(21) "IntlGregorianCalendar"// string(66) "2020年11月18日星期三 格林尼治标准时间 上午12:58:14"$cal1 = IntlCalendar::fromDateTime('2013-02-28 00:01:02 Europe/Berlin');var_dump(get_class($cal1), IntlDateFormatter::formatObject($cal1, 'yyyy MMMM d HH:mm:ss VVVV', 'de_DE'));// string(21) "IntlGregorianCalendar"// string(41) "2013 Februar 28 00:01:02 Deutschland Zeit"

IntlCalendar 类的 createInstance() 方法会返回一个 IntlCalendar 对象,它的参数是可选的,不过必须是 TimeZone 类型的参数。fromDateTime() 方法同样也是生成一个 IntlCalendar 对象,不过它可以设置一个 DateTime 对象或者日期类型的字符串为参数。

可以看到,我们返回的对象使用 get_class() 方法后看到实际返回的是一个 IntlGregorianCalendar 格林格里日历对象。这时,就可以使用 IntlDateFormatter 类的 formatObject() 方法来格式化输出内容,它是可以指定地区的,不同的地区设置就会显示不同的格式化语言结果。

返回时间戳

echo IntlCalendar::getNow(), PHP_EOL; // 1605661094417

不多做解释了,不过这个静态方法返的是带毫秒数的时间戳。

时区相关设置

只要是国际化相关的功能,都多少和时区 TimeZone 有关,日历类也不例外。

ini_set('intl.default_locale', 'de_DE');ini_set('date.timezone', 'Europe/Berlin');$cal = IntlCalendar::createInstance();print_r($cal->getTimeZone());// IntlTimeZone Object// (// [valid] => 1// [id] => Europe/Berlin// [rawOffset] => 3600000// [currentOffset] => 3600000// )echo $cal->getLocale(Locale::ACTUAL_LOCALE), PHP_EOL; // deecho $cal->getLocale(Locale::VALID_LOCALE), PHP_EOL; // de_DE

使用 getTimeZone() 就可以获得当前的时区信息,getLocale() 和之前我们文章中其它相关功能类的 getLocale() 方法没有什么区别,大家可以看下之前讲过的内容。当然,这个 TimeZone 属性除了通过 ini_set() 之外,也是可以直接通过对象的 setTimeZone() 方法进行修改的。

ini_set('intl.default_locale', 'zh_CN');ini_set('date.timezone', 'Asia/Shanghai');$cal = IntlCalendar::createInstance();print_r($cal->getTimeZone());// IntlTimeZone Object// (// [valid] => 1// [id] => Asia/Shanghai// [rawOffset] => 28800000// [currentOffset] => 28800000// )$cal->setTimeZone('UTC');print_r($cal->getTimeZone());// IntlTimeZone Object// (// [valid] => 1// [id] => UTC// [rawOffset] => 0// [currentOffset] => 0// )echo $cal->getLocale(Locale::ACTUAL_LOCALE), PHP_EOL; // zhecho $cal->getLocale(Locale::VALID_LOCALE), PHP_EOL; // zh_Hans_CN

日历相关操作

时间字段最大、最小值相关信息

这是什么意思呢?先看下代码。

$cal = IntlCalendar::fromDateTime('2020-02-15');var_dump($cal->getActualMaximum(IntlCalendar::FIELD_DAY_OF_MONTH)); //29var_dump($cal->getMaximum(IntlCalendar::FIELD_DAY_OF_MONTH)); //31var_dump($cal->getActualMinimum(IntlCalendar::FIELD_DAY_OF_MONTH)); //1var_dump($cal->getMinimum(IntlCalendar::FIELD_DAY_OF_MONTH)); //1var_dump($cal->getLeastMaximum(IntlCalendar::FIELD_DAY_OF_MONTH));// 28 $cal->add(IntlCalendar::FIELD_EXTENDED_YEAR, -1);var_dump($cal->getActualMaximum(IntlCalendar::FIELD_DAY_OF_MONTH)); //28var_dump($cal->getMaximum(IntlCalendar::FIELD_DAY_OF_MONTH)); //31var_dump($cal->getActualMinimum(IntlCalendar::FIELD_DAY_OF_MONTH)); //1var_dump($cal->getMinimum(IntlCalendar::FIELD_DAY_OF_MONTH)); //1var_dump($cal->getLeastMaximum(IntlCalendar::FIELD_DAY_OF_MONTH));// 28

楼上这一堆是什么鬼?其实这几个方法就是返回的指定参数字段内容的最大、最小值,比如我们查看的是 FIELD_DAY_OF_MONTH ,也就是月份有多少天。getActualMaximum() 返回的是实际值,比如 2020 年的 2 月份是有 29 天的 。getMaximum() 返回的是正常月份的最大值,都是 31 。getActualMinimum() 、getMinimum() 返回的是实际最小值和正常最小值,这个对于月份来说都是 1 ,每个月都肯定会有第 1 天。getLeastMaximum() 方法是获取字段的最小局部最大值,怎么理解呢?2月份最小天数是28天,它的局部最大值也就是28天,其它月份则分 30 和 31 天。

一周的起始日期

这个功能主要是可以设置一周的起始日期是周几。比如对于欧美的国际标准时间来说,周一并不是一周的开始,周日才是这一周的第一天。大家从各种日历应用中就能发现这个问题。

$cal = IntlCalendar::createInstance();$cal->set(2020, 5, 30);var_dump($cal->getFirstDayOfWeek()); // 1echo IntlDateFormatter::formatObject($cal, <<<EOD'local day of week: 'cc'
week of month : 'W'
week of year : 'wwEOD), PHP_EOL;// local day of week: 3// week of month : 5// week of year : 27

在当前的时区中,我们 getFirstDayOfWeek() 返回的结果是 1 ,手机靓号买号也就是周一为一周的起点,周几是从 0 开始计算的。set() 方法可以设置具体的日期,需要注意月份也是从 0 开始的。我们再使用 IntlDateFormatter::formatObject() 输出当前日期在周几、在月中的第几周以及当前周是今年的第几周。在这里我们设置的是 2020年的 6 月 30 号,‘cc’ 表示的当前日期在周中是周四,是一周中的第四天(不是指定的6月30号,是我们运行代码时的时间,方便我们修改后查看),当前周是在当前月是第五周,当前周在整年里的是第 27 周。如果我们改变这个每周开始的时间呢?

$cal->setFirstDayOfWeek(3);var_dump($cal->getFirstDayOfWeek()); // int(5)echo IntlDateFormatter::formatObject($cal, <<<EOD'local day of week: 'cc'
week of month : 'W'
week of year : 'wwEOD), PHP_EOL;// local day of week: 1// week of month : 6// week of year : 27

嗯,‘cc’ 变为 1 了,当前成为了周一。现在是在当前月份的第 6 周了,因为我们现在一周的开始是从周四开始算的啦。

日历比较

日历对象比较

$cal1 = IntlCalendar::createInstance();$cal2 = IntlCalendar::createInstance();var_dump($cal1->equals($cal2)); // bool(true)$cal2->setTime($cal1->getTime() + 1);var_dump($cal1->equals($cal2)); // bool(false)

这个比较简单,日历对象内部的属性不同,当然 equals() 方法返回的结果就是 false 了。

日历对象差值

除了比较日历对象外,还可以获取两个日历时间之前的差值信息。

$cal1 = IntlCalendar::fromDateTime('2019-1-29 09:00:11');$cal2 = IntlCalendar::fromDateTime('2020-03-01 09:19:29');$time = $cal2->getTime();echo "之前的时间: ", IntlDateFormatter::formatObject($cal1), "\n";// 之前的时间: 2019年1月29日 上午9:00:11printf(
"两个时间的差别: %d year(s), %d month(s), "
. "%d day(s), %d hour(s) and %d minute(s)\n",
$cal1->fieldDifference($time, IntlCalendar::FIELD_YEAR),
$cal1->fieldDifference($time, IntlCalendar::FIELD_MONTH),
$cal1->fieldDifference($time, IntlCalendar::FIELD_DAY_OF_MONTH),
$cal1->fieldDifference($time, IntlCalendar::FIELD_HOUR_OF_DAY),
$cal1->fieldDifference($time, IntlCalendar::FIELD_MINUTE));// 两个时间的差别: 1 year(s), 1 month(s), 1 day(s), 0 hour(s) and 19 minute(s)echo "之后的时间: ", IntlDateFormatter::formatObject($cal1), "\n";// 之后的时间: 2020年3月1日 上午9:19:11

可以看到使用 fieldDifference() 方法就可以获得日历对象和比较日期之间相关的信息。需要注意的是,使用 fieldDifference() 之后,原来的日历对象全变成新的日期信息。

其它信息

查看区域设置关键字值集

print_r(iterator_to_array(IntlCalendar::getKeywordValuesForLocale('calendar', 'zh_CN', true)));// Array// (// [0] => gregorian// [1] => chinese// )print_r(iterator_to_array(IntlCalendar::getKeywordValuesForLocale('calendar', 'zh_CN', false)));// Array// (// [0] => gregorian// [1] => chinese// [2] => japanese// [3] => buddhist// [4] => roc// [5] => persian// [6] => islamic-civil// [7] => islamic// [8] => hebrew// [9] => indian// [10] => coptic// [11] => ethiopic// [12] => ethiopic-amete-alem// [13] => iso8601// [14] => dangi// [15] => islamic-umalqura// [16] => islamic-tbla// [17] => islamic-rgsa// )

getKeywordValuesForLocale() 方法的第一个参数只能固定写 calendar ,后面是填写相关的区域,返回的内容就是当前语言环境下所支持的相关字值信息。

区域语言类型

$cal = IntlCalendar::createInstance(NULL, '@calendar=ethiopic-amete-alem');var_dump($cal->getType());// string(19) "ethiopic-amete-alem"$cal = new IntlGregorianCalendar();var_dump($cal->getType());// string(9) "gregorian"

很明显,getType() 方法返回的就是指定语言区域信息的类型。

滚动日历

var_dump(IntlDateFormatter::formatObject($cal)); // string(31) "2020年11月18日 上午9:14:59"$cal->roll(IntlCalendar::FIELD_DAY_OF_MONTH, true);var_dump(IntlDateFormatter::formatObject($cal)); // string(31) "2020年11月19日 上午9:14:59"

使用 roll() 方法可以滚动或者说是卷动日历,在这里我们将日历滚动一天,也就是加了一天的时间。

转换为 DateTime 对象

var_dump($cal->toDateTime());// object(DateTime)#4 (3) {// ["date"]=>// string(26) "2020-11-19 09:14:59.000000"// ["timezone_type"]=>// int(3)// ["timezone"]=>// string(13) "Asia/Shanghai"// }

使用 toDateTime() 方法就可以将当前的 IntlCalendar 对象转换成 DateTime 对象。

当前系统中支持的所有区域信息

print_r(IntlCalendar::getAvailableLocales());// Array// (// [0] => af// [1] => af_NA// [2] => af_ZA// [3] => agq// [4] => agq_CM// [5] => ak// [6] => ak_GH// [7] => am// [8] => am_ET// [9] => ar// ……// ……

getAvailableLocales() 返回的是当前系统中所有支持可用的 Locale 信息。

更多相关文章

  1. 浅谈IOS屏幕刷新ADisplayLink
  2. 【前端】如何阻止ios微信下双击屏幕向上滑的问题
  3. 如何查看HTTP接口的响应时间
  4. PHP获取两个时间之间的所有日期
  5. 【前端 · 面试 】HTTP 总结(八)—— HTTP 强缓存
  6. 我们常说的算法时间复杂度和空间复杂度到底是什么?
  7. ThinkPHP 时间戳,写错了,好尴尬
  8. promise间隔时间添加dom
  9. 时间序列建模三部曲

随机推荐

  1. 【android初级】之android布局属性详解
  2. Android Layout属性详解
  3. 布局技巧和列表控件
  4. Android ScrollView滚动条
  5. android sdk的快速安装法
  6. Android基本控件TextView
  7. Android应用程序的debug属性
  8. GridView相关
  9. Android Activity 的四种启动模式 lunchM
  10. android 布局学习