fightbulc/moment

在 PHP 中解析、验证、操作和显示日期,支持国际化。受 moment.js 启发。


README

过去1.5年来,我成为了一个爸爸,这在合并PR或推动此包的进一步发展上表现得非常明显。时间在这里是最大的约束。我很乐意将项目转交给有更多时间和推动项目前进的动力的人。只需给我发个消息。干杯!

                                      _           _
 _ __ ___   ___  _ __ ___   ___ _ __ | |_   _ __ | |__  _ __
| '_ ` _ \ / _ \| '_ ` _ \ / _ \ '_ \| __| | '_ \| '_ \| '_ \
| | | | | | (_) | | | | | |  __/ | | | |_ _| |_) | | | | |_) |
|_| |_| |_|\___/|_| |_| |_|\___|_| |_|\__(_) .__/|_| |_| .__/
                                           |_|         |_|

Integrate

Latest Stable Version Total Downloads Monthly Downloads

变更日志

简介

什么是 moment.php?

用于解析、操作和格式化日期的国际化日期库。

有依赖项吗?

PHP 5.3 或更高版本,因为 moment.php 基于 PHP 的 DateTime 类

安装

通过 composer 简单安装。还不知道 composer 是什么?请在这里了解信息

composer require fightbulc/moment

快速示例

获取一个 moment

$m = new \Moment\Moment(); // default is "now" UTC
echo $m->format(); // e.g. 2012-10-03T10:00:00+0000

$m = new \Moment\Moment('now', 'Europe/Berlin');
echo $m->format(); // e.g. 2012-10-03T12:00:00+0200

$m = new \Moment\Moment('2017-06-06T10:00:00', 'Europe/Berlin');
echo $m->format(); // e.g. 2012-10-03T12:00:00+0200

$m = new \Moment\Moment(1499366585);
echo $m->format(); // e.g. 2017-07-06T18:43:05+0000

接受的日期格式

Moment 可以解析以下日期格式作为输入

const ATOM = 'Y-m-d\TH:i:sP'; // 2005-08-15T15:52:01+00:00
const COOKIE = 'l, d-M-y H:i:s T'; // Monday, 15-Aug-2005 15:52:01 UTC
const ISO8601 = 'Y-m-d\TH:i:sO'; // 2005-08-15T15:52:01+0000
const RFC822 = 'D, d M y H:i:s O'; // Mon, 15 Aug 05 15:52:01 +0000
const RFC850 = 'l, d-M-y H:i:s T'; // Monday, 15-Aug-05 15:52:01 UTC
const RFC1036 = 'D, d M y H:i:s O'; // Mon, 15 Aug 05 15:52:01 +0000
const RFC1123 = 'D, d M Y H:i:s O'; // Mon, 15 Aug 2005 15:52:01 +0000
const RFC2822 = 'D, d M Y H:i:s O'; // Mon, 15 Aug 2005 15:52:01 +0000
const RSS = 'D, d M Y H:i:s O'; // Mon, 15 Aug 2005 15:52:01 +0000
const W3C = 'Y-m-d\TH:i:sP'; // 2005-08-15T15:52:01+00:00

// Moment also tries to parse dates without timezone or without seconds

const NO_TZ_MYSQL = 'Y-m-d H:i:s'; // 2005-08-15 15:52:01
const NO_TZ_NO_SECS = 'Y-m-d H:i'; // 2005-08-15 15:52
const NO_TIME = 'Y-m-d'; // 2005-08-15

// time fractions ".000" will be automatically removed
$timeWithFraction = '2016-05-04T10:00:00.000';

切换区域设置

查看 Locales 文件夹以查看所有支持的语言。默认区域设置为 en_GB

$m = new \Moment\Moment();
echo $m->format('[Weekday:] l'); // e.g. Weekday: Wednesday

// set german locale
\Moment\Moment::setLocale('de_DE');

$m = new \Moment\Moment();
echo $m->format('[Wochentag:] l'); // e.g. Wochentag: Mittwoch

目前支持的语言

ar_TN 阿拉伯(突尼斯) ca_ES 加泰罗尼亚语 cs_CZ 捷克语 da_DK 丹麦语 de_DE 德语(德国) en_CA 英语(加拿大) en_GB 英语(英国) en_US 英语(美国) eo_EO 世界语 es_ES 西班牙语(欧洲) fa_IR 波斯语 fi_FI 芬兰语 fr_CA 法语(加拿大) fr_FR 法语(欧洲) hu_HU 匈牙利语 id_ID 印度尼西亚语 it_IT 意大利语 ja_JP 日语 kz_KZ 哈萨克语 lv_LV 拉脱维亚语(拉脱维亚语) nl_NL 荷兰语 oc_LNC 普罗旺斯语 pl_PL 波兰语 pt_BR 葡萄牙语(巴西) pt_PT 葡萄牙语(葡萄牙) ru_RU 俄语(基本版本) sv_SE 瑞典语 th_TH 泰语 tr_TR 土耳其语 uk_UA 乌克兰语 vi_VN 越南语 zh_CN 中文 zh_TW 繁体中文

切换时区

$m = new \Moment\Moment('2012-04-25T03:00:00', 'CET');
echo $m->setTimezone('UTC')->format(); // 2012-04-25T01:00:00+0000

更改默认时区

\Moment\Moment::setDefaultTimezone('CET');

$m = new \Moment\Moment('2016-09-13T14:32:06');
echo $m->format(); // 2016-09-13T14:32:06+0100

自定义格式

I. 仅 PHP(标准)

$m = new \Moment\Moment('2012-04-25T03:00:00', 'CET');
echo $m->format('l, dS F Y / H:i (e)'); // Wednesday, 25th April 2012 / 03:00 (Europe/Berlin)

格式基于 PHP 的 Date 函数DateTime 类

II. 非PHP格式

您现在可以通过传递实现 FormatsInterface 的类来注入不同的格式处理。您可以在测试文件夹中找到一个示例,该示例实现了来自 moment.js 的所有格式。感谢 Ashish 付出时间来匹配 moment.js 格式与 PHP 格式。查看 测试脚本 以查看示例。

每个人都可以以相同的方式编写格式类。它既简单又可扩展。

// get  desired formats class
// create a moment
$m = new \Moment\Moment('2012-04-25T03:00:00', 'CET');

// format with moment.js definitions
echo $m->format('LLLL', new \Moment\CustomFormats\MomentJs()); // Wednesday, April 25th 2012 3:00 AM

自定义格式 也可以作为每个 Locale 的部分。如果您的区域设置还没有,请继续添加。查看 法语区域设置 的示例。

IV. 易于文本转义

只需将所有文本包裹在 [] 中,所有字符都将自动为您转义。

$m = new \Moment\Moment('2012-04-25T03:00:00', 'CET');
echo $m->format('[We are in the month of:] F'); // We are in the month of: April

IV. 固定序数表示

PHP 的内部序数计算似乎有缺陷。我添加了一个快速修复来处理这个问题。

以下示例打印给定日期的年度周数。它应该打印 22nd

// internal function
date('WS', mktime(12, 22, 0, 5, 27, 2014)); // 22th

// moment.php
$m = new \Moment\Moment('2014-05-27T12:22:00', 'CET');
$m->format('WS'); // 22nd

创建自定义时刻并对其进行操作

I. 过去/未来时刻

$m = new \Moment\Moment('2012-05-15T12:30:00', 'CET');
echo $m->addHours(2)->format(); // 2012-05-15T14:30:00+0200

$m = new \Moment\Moment('2012-05-15T12:30:00', 'CET');
echo $m->subtractDays(7)->subtractMinutes(15)->format(); // 2012-05-08T12:15:00+0200

$m = new \Moment\Moment('@1401443979', 'CET'); // unix time
echo $m->subtractDays(7)->subtractMinutes(15)->format(); // 2014-05-23T09:44:39+0000

II. 复制一个给定的时刻

有时,您可能需要使用一个给定的时刻进行操作,而不会更改原始时刻。为此,请使用 cloning()

$m = new \Moment\Moment('2012-05-15T12:30:00', 'CET');
$c = $m->cloning()->addDays(1);

echo $m->getDay(); // 15
echo $c->getDay(); // 16

或者,您可以在原始时刻上启用不可变模式。

$m = new \Moment\Moment('2012-05-15T12:30:00', 'CET', true);
$c = $m->addDays(1);

echo $m->getDay(); // 15
echo $c->getDay(); // 16

// You can also change the immutable mode after creation:
$m->setImmutableMode(false)->subtractDays(1);

echo $m->getDay(); // 14

不可变模式会在应用修改之前隐式调用 cloning(),使所有修改方法生效。

III. 操作日期/时间的函数

IV. 设置器/获取器

日期差异

$m = new \Moment\Moment('2013-02-01T07:00:00');
$momentFromVo = $m->fromNow();

// or from a specific moment
$m = new \Moment\Moment('2013-02-01T07:00:00');
$momentFromVo = $m->from('2011-09-25T10:00:00');

// result comes as a value object class
echo $momentFromVo->getDirection()  // "future"
echo $momentFromVo->getSeconds()    // -42411600
echo $momentFromVo->getMinutes()    // -706860
echo $momentFromVo->getHours()      // -11781
echo $momentFromVo->getDays()       // -490.88
echo $momentFromVo->getWeeks()      // -70.13
echo $momentFromVo->getMonths()     // -17.53
echo $momentFromVo->getYears()      // -1.42
echo $momentFromVo->getRelative()   // in a year

获取日期周期(周、月、季度)

有时,获取给定日期的周期边界是有帮助的。例如,如果今天是星期三,我需要从今天的周开始和结束的日期。允许的周期是 weekmonthquarter

$m = new \Moment\Moment('2013-10-23T10:00:00');
$momentPeriodVo = $m->getPeriod('week');

// results comes as well as a value object class
echo $momentPeriodVo
    ->getStartDate()
    ->format('Y-m-d'); // 2013-10-21

echo $momentPeriodVo
    ->getEndDate()
    ->format('Y-m-d'); // 2013-10-27

echo $momentPeriodVo
    ->getRefDate()
    ->format('Y-m-d'); // 2013-10-23

echo $momentPeriodVo->getInterval(); // 43 = week of year

对于月度和季度周期,操作方式相同。

$momentPeriodVo = $m->getPeriod('month');
$momentPeriodVo = $m->getPeriod('quarter');

日历时间

日历时间显示相对于 now 的时间,但与 Moment::fromNow() 略有不同。Moment::calendar() 将根据日期与今天的接近程度以不同的字符串格式化日期。

(new \Moment\Moment('2014-03-30T16:58:00', 'CET'))->subtractDays(6)->calendar(); // last week
(new \Moment\Moment('2014-03-30T16:58:00', 'CET'))->subtractDays(1)->calendar(); // yesterday
(new \Moment\Moment('2014-03-30T16:58:00', 'CET'))->calendar(); // today
(new \Moment\Moment('2014-03-30T16:58:00', 'CET'))->addDays(1)->calendar(); // tomorrow
(new \Moment\Moment('2014-03-30T16:58:00', 'CET'))->addDays(3)->calendar(); // next week
(new \Moment\Moment('2014-03-30T16:58:00', 'CET'))->addDays(10)->calendar(); // everything else

注意:使用 $moment->calendar(false) 可省略时间 at 00:00

startOf / endOf

与 moment.js 中的操作相同:通过设置原始时刻为单位时间的开始/结束来修改原始时刻。

$m = new \Moment\Moment('20140515T10:15:23', 'CET');

$m->startOf('year');    // set to January 1st, 00:00 this year
$m->startOf('quarter'); // set to the beginning of the current quarter, 1st day of months, 00:00
$m->startOf('month');   // set to the first of this month, 00:00
$m->startOf('week');    // set to the first day of this week, 00:00
$m->startOf('day');     // set to 00:00 today
$m->startOf('hour');    // set to now, but with 0 mins, 0 secs
$m->startOf('minute');  // set to now, but with 0 seconds

$m->endOf('year');    // set to December 31st, 23:59 this year
$m->endOf('quarter'); // set to the end of the current quarter, last day of month, 23:59
$m->endOf('month');   // set to the last of this month, 23:59
$m->endOf('week');    // set to the last day of this week, 23:59
$m->endOf('day');     // set to 23:59 today
$m->endOf('hour');    // set to now, but with 59 mins, 59 secs
$m->endOf('minute');  // set to now, but with 59 seconds

注意:由于我们不处理毫秒,因此忽略了 second 的周期。

获取未来几周给定星期的日期

对于我的一个客户,我需要通过选定的星期来获取时刻。 任务如下: 给我下三周内 星期二星期四 的日期。因此,我添加了一个小处理程序,它正好完成这项任务。结果,您将收到一个包含 Moment 对象 的数组。

// 1 - 7 = Mon - Sun
$weekdayNumbers = [
    2, // tuesday
    4, // thursday
];

$m = new \Moment\Moment();
$dates = $m->getMomentsByWeekdays($weekdayNumbers, 3);

// $dates = [Moment, Moment, Moment ...]

现在,您可以遍历结果,将其格式化到下拉字段中或用于您需要的任何用途。

路线图

  • 尝试将有用的方法从 moment.js 转移过来
  • 添加单元测试

变更日志

未发布

  • 添加
    • 支持 PHP 8.2 #218
    • 支持 PHP 8.3 #227

1.33.0

  • 修复
    • 法语区域
    • 加拿大测试
  • 添加
    • 世界语区域
    • 哈萨克区域

1.32.1

  • 修复
    • DateTime::createFromFormat 签名匹配

1.32.0

  • 添加
    • 波斯语区域

1.31.0

  • 添加
    • 通过 GH 动作工作流程进行代码检查
    • 英语/法语的双语加拿大区域

1.30.1

  • 修复
    • 合并几个 PR(谢谢!)

1.30.0

  • 添加
    • 完成区域设置
  • 修复
    • 瑞典区域

1.29.0

  • 更新意大利区域
  • 添加
    • 为 en_US 添加自定义格式
    • 加载类似区域的标志

1.28.3

  • 修复类型提示问题

1.28.2

  • 修复
    • 缺少相对时间格式
    • 允许 9 位数 Unix 时间戳

1.28.1

  • 修复 RFC2822 为有效格式

1.28.0

  • 修复相对时间
  • 添加挪威区域

1.27.0

1.26.10

  • 修复
    • 奥克西塔尼亚区域

1.26.9

1.26.8

  • 添加
    • 葡萄牙语(pt_PT)

1.26.7

  • 修复
    • 匈牙利区域星期顺序

1.26.6

  • 添加
    • 允许使用不带前缀 @ 的 Unix 时间戳初始化 Moment

1.26.5

  • 修复
    • 修复自定义格式中 'LLL' 的格式

1.26.4

  • 修复
    • 删除 php5.4+ 专用语法

1.26.3

  • 修复
    • 丹麦日和月名称正确的大小写
    • 法语区域
    • PHPDocs
  • 添加
    • 在解析日期时为 NO_TZ_MYSQLNO_TZ_NO_SECSNO_TIME 提供常量

1.26.2

  • 添加
    • 荷兰自定义格式

1.26.1

  • 修复
    • 俄语区域

1.26.0

  • 添加
    • 土耳其区域
  • 修复
    • 朗格多克区域

1.25.1

  • 修复
    • PHP7.1 setTime 需要 $microseconds

1.25

  • 添加
    • 乌克兰区域

1.24

  • 添加
    • 匈牙利区域

1.23.1

  • 修复
    • 朗格多克区域

1.23.0

  • 添加
    • 越南区域
    • 朗格多克区域

1.22.0

  • 添加
    • 更改默认时区
  • 修复
    • FormatsInterface 文档

1.21.0

  • 添加
    • 阿拉伯区域
    • 在区域级别自定义格式

1.20.9

  • 修复
    • 俄语区域
  • 添加
    • 俄语区域测试

1.20.8

  • 修复
    • 波兰区域
    • 秒的计算

1.20.7

  • 修复
    • 俄语:更多相对时间修复

1.20.6

  • 修复
    • 俄语区域相对时间:处理天

1.20.5

  • 修复
    • 缺少不可变处理

1.20.4

  • 修复
    • 改进波兰区域(添加了 Nominativ)

1.20.3

  • 修复
    • 中文区域

1.20.2

  • 添加接受格式到 README

1.20.1

  • 修复
    • 泰语地区

1.20.0

  • 添加
    • 加泰罗尼亚语地区
  • 修复
    • 波兰语地区测试

1.19.0

  • 添加
    • 俄语区域
  • 修复
    • 波兰语地区测试

1.18.0

  • 添加
    • 不可变模式
  • 修复
    • 波兰区域

1.17.0

  • 添加
    • 波兰区域

1.16.0

  • 添加
    • 印度尼西亚语地区

1.15.0

  • 添加
    • 日语地区

1.14.1

  • 修复
    • 荷兰语地区中存在错误

1.14.0

  • 添加
    • 荷兰语地区

1.13.0

  • 添加
    • 瑞典区域

1.12.0

  • 添加
    • 丹麦语地区

1.11.4

  • 修复
    • 为罗马尼亚语地区固定开始/结束星期

1.11.3

  • 修复
    • 为意大利语地区添加分隔符字符

1.11.1

  • 修复
    • 为周、月、季度传递新实例的startOf/endOf

1.11.0

  • 添加
    • 地区:捷克语

1.10.4

  • 添加
    • calendar地区接收以下参数作为\Closure:function(Moment $m) {}
    • relativeTime地区接收以下参数作为\Closure:function($count, $direction, Moment $m) {}

1.10.3

  • 添加
    • 固定传递闭包到地区(calendar,relativeTime)
    • 设置正确的德语地区信息

1.10.2

  • 添加
    • 固定泰语地区字符串

1.10.1

  • 添加
    • 地区:繁体中文

1.10.0

  • 添加
    • 地区:中文
    • 序数格式化器现在接收token,例如dS中的token是d

1.9.1

  • 固定:11-13之间的数字的英语序数问题

1.9.0

  • 添加:意大利语地区

1.8.1

  • 固定:英语序数问题

1.8.0

  • 添加:葡萄牙语地区

1.7.2

  • 修复
    • 地区显示错误月份名称(#34)
    • 更改了地区文件中星期的顺序

1.7.1

  • 添加
    • getWeekdayNameLong()
    • getWeekdayNameShort()
    • getMonthNameLong()
    • getMonthNameShort()

1.7.0

  • 添加
    • 地区:泰国

1.6.0

  • 添加
    • 地区
    • MomentFromVo
      • getMonths()
      • getYears()
      • getRelative()
  • 修复
    • MomentFromVo
      • getSeconds()现在也显示方向

1.5.3

  • 修复
    • 只有对于Unixtime日期才会发生的时区问题
  • 其他
    • MomentFromVo
      • 方向现在返回:“未来”(-)/“过去”(+)
      • 现在将时间值类型转换为浮点数

1.5.2

  • 修复
    • 构造Moment时无法识别的时区

1.5.1

  • 添加
    • getMomentsByWeekdays()
    • getWeekday()
    • getWeekOfYear()
  • 其他
    • 转义文本

1.5.0

  • 添加

    • startOf和endOf如moment.js中实现
    • 获取给定日期的季度周期
    • setDay()
    • getDay()
    • setMonth()
    • getMonth()
    • setYear()
    • getYear()
    • getQuarter()
    • setSecond()
    • getSecond()
    • setMinute()
    • getMinute()
    • setHour()
    • getHour()
    • 添加了cloning()
      • 基于给定实例创建一个新的可变moment
    • 添加了到MomentPeriodVogetInterval(),以指示给定周期的时间间隔
      • week = 年份中的周
      • month = 年份中的月
      • quarter = 年份中的季度
    • 添加了静态类MomentHelper
      • 获取给定年份中给定季度的周期
    • 固定PHP内部序数计算(与moment.js格式化结合使用)
      • 例如,WS表示年份的第21周现在显示为正确的21th等。
    • 您现在可以通过将文本包裹在[]中来转义文本
      • 例如,[Hello World]将被自动转换为\H\e\l\l\o \W\o\r\l\d
  • 已删除

    • add()
    • subtract()

1.4.0

1.3.0

  • 修复

    • 与PHP 5.3不兼容
  • 添加

    • 异常抛出为MomentException
    • 实例化时的日期验证
      • 测试格式为YYYY-mm-ddYYYY-mm-ddTHH:ii:ss的日期
      • 在无效日期上抛出MomentException
    • addSeconds()
    • addMinutes()
    • addHours()
    • addDays()
    • addWeeks()
    • addMonths()
    • addYears()
    • subtractSeconds()
    • subtractMinutes()
    • subtractHours()
    • subtractDays()
    • subtractWeeks()
    • subtractMonths()
    • subtractYears()
  • 已弃用

    • add()
    • subtract()

贡献

本项目的维护者建议遵循贡献指南

许可证

Moment.php可以在MIT许可证的条款下自由分发。

版权(c)2017 Tino Ehrich

本许可证在此免费授予任何获得本软件及其相关文档文件(以下简称“软件”)副本的个人,在不受限制的情况下处理软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本的权利,并允许将软件提供给他人进行此类操作,但须遵守以下条件

上述版权声明和本许可证声明应包含在软件的所有副本或实质性部分中。

软件按“原样”提供,不提供任何形式的质量保证,无论是明示的、默示的还是其他形式的保证,包括但不限于适销性、适用于特定用途和不侵权的保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任承担责任,无论基于合同、侵权或其他原因,是否与软件或软件的使用或其他操作有关。