init
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phive xmlns="https://phar.io/phive">
|
||||
<phar name="phpstan" version="2.1.17" installed="2.1.17" location="./tools/phpstan" copy="false"/>
|
||||
</phive>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
# Basic docker based environment
|
||||
# Necessary to trick dokku into building the documentation
|
||||
# using dockerfile instead of herokuish
|
||||
FROM php:8.1
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
VOLUME ["/code"]
|
||||
|
||||
CMD [ '/bin/bash' ]
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Copyright (C) Brian Nesbitt
|
||||
Copyright (C) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# CakePHP Chronos
|
||||
|
||||

|
||||
[](https://packagist.org/packages/cakephp/chronos)
|
||||
[](https://packagist.org/packages/cakephp/chronos/stats)
|
||||
[](https://coveralls.io/r/cakephp/chronos?branch=master)
|
||||
[](LICENSE)
|
||||
|
||||
Chronos focuses on providing immutable date/datetime objects.
|
||||
Immutable objects help ensure that datetime objects aren't accidentally
|
||||
modified, keeping data more predictable.
|
||||
|
||||
# Installation
|
||||
|
||||
Installing with composer:
|
||||
|
||||
```
|
||||
$ composer require cakephp/chronos
|
||||
```
|
||||
|
||||
For details on the (minimum/maximum) PHP version see [version map](https://github.com/cakephp/chronos/wiki#version-map).
|
||||
|
||||
# Usage
|
||||
|
||||
```php
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
|
||||
printf("Now: %s", Chronos::now());
|
||||
```
|
||||
|
||||
# Differences with nesbot/carbon
|
||||
|
||||
Chronos was originally compatible with Carbon but has diverged and no longer
|
||||
extends the PHP DateTime and DateTimeImmutable classes.
|
||||
|
||||
# Immutable Object Changes
|
||||
|
||||
Immutable objects have a number of advantages:
|
||||
|
||||
1. Using immutable objects is always free of side-effects.
|
||||
2. Dates and times don't accidentally change underneath other parts of your code.
|
||||
|
||||
With those benefits in mind, there are a few things you need to keep in mind
|
||||
when modifying immutable objects:
|
||||
|
||||
```php
|
||||
// This will lose modifications
|
||||
$date = new Chronos('2015-10-21 16:29:00');
|
||||
$date->modify('+2 hours');
|
||||
|
||||
// This will keep modifications
|
||||
$date = new Chronos('2015-10-21 16:29:00');
|
||||
$date = $date->modify('+2 hours');
|
||||
```
|
||||
|
||||
# Calendar Dates
|
||||
|
||||
PHP only offers datetime objects as part of the native extensions. Chronos adds
|
||||
a number of conveniences to the traditional DateTime object and introduces
|
||||
a `ChronosDate` object. `ChronosDate` instances their time frozen to `00:00:00` and the timezone
|
||||
set to the server default timezone. This makes them ideal when working with
|
||||
calendar dates as the time components will always match.
|
||||
|
||||
```php
|
||||
use Cake\Chronos\ChronosDate;
|
||||
|
||||
$today = new ChronosDate();
|
||||
echo $today;
|
||||
// Outputs '2015-10-21'
|
||||
|
||||
echo $today->modify('+3 hours');
|
||||
// Outputs '2015-10-21'
|
||||
```
|
||||
|
||||
Like instances of `Chronos`, `ChronosDate` objects are also *immutable*.
|
||||
|
||||
# Documentation
|
||||
|
||||
A more descriptive documentation can be found at [book.cakephp.org/chronos/3/en/](https://book.cakephp.org/chronos/3/en/).
|
||||
|
||||
# API Documentation
|
||||
|
||||
API documentation can be found on [api.cakephp.org/chronos](https://api.cakephp.org/chronos).
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "cakephp/chronos",
|
||||
"description": "A simple API extension for DateTime.",
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"date",
|
||||
"time",
|
||||
"DateTime"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Brian Nesbitt",
|
||||
"email": "brian@nesbot.com",
|
||||
"homepage": "http://nesbot.com"
|
||||
},
|
||||
{
|
||||
"name": "The CakePHP Team",
|
||||
"homepage": "https://cakephp.org"
|
||||
}
|
||||
],
|
||||
"homepage": "https://cakephp.org",
|
||||
"support": {
|
||||
"issues": "https://github.com/cakephp/chronos/issues",
|
||||
"source": "https://github.com/cakephp/chronos"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"psr/clock": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"cakephp/cakephp-codesniffer": "^5.0",
|
||||
"phpunit/phpunit": "^10.5.58 || ^11.1.3"
|
||||
},
|
||||
"provide": {
|
||||
"psr/clock-implementation": "1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Cake\\Chronos\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Cake\\Chronos\\Test\\": "tests/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"check": [
|
||||
"@test",
|
||||
"@cs-check",
|
||||
"@stan"
|
||||
],
|
||||
"cs-check": "phpcs --colors --parallel=16 -p",
|
||||
"cs-fix": "phpcbf --colors --parallel=16 -p",
|
||||
"phpstan": "tools/phpstan analyse",
|
||||
"stan": "@phpstan",
|
||||
"stan-baseline": "tools/phpstan --generate-baseline",
|
||||
"stan-setup": "phive install",
|
||||
"test": "phpunit"
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Generate the HTML output.
|
||||
FROM ghcr.io/cakephp/docs-builder as builder
|
||||
|
||||
RUN pip install git+https://github.com/sphinx-contrib/video.git@master
|
||||
|
||||
COPY docs /data/docs
|
||||
ENV LANGS="en fr ja pt"
|
||||
|
||||
# build docs with sphinx
|
||||
RUN cd /data/docs-builder && \
|
||||
make website LANGS="$LANGS" SOURCE=/data/docs DEST=/data/website
|
||||
|
||||
# Build a small nginx container with just the static site in it.
|
||||
FROM ghcr.io/cakephp/docs-builder:runtime as runtime
|
||||
|
||||
ENV LANGS="en fr ja pt"
|
||||
ENV SEARCH_SOURCE="/usr/share/nginx/html"
|
||||
ENV SEARCH_URL_PREFIX="/chronos/3"
|
||||
|
||||
COPY --from=builder /data/docs /data/docs
|
||||
COPY --from=builder /data/website /data/website
|
||||
COPY --from=builder /data/docs-builder/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Move docs into place.
|
||||
RUN cp -R /data/website/html/* /usr/share/nginx/html \
|
||||
&& rm -rf /data/website
|
||||
@@ -0,0 +1,50 @@
|
||||
# Global configuration information used across all the
|
||||
# translations of documentation.
|
||||
#
|
||||
# Import the base theme configuration
|
||||
from cakephpsphinx.config.all import *
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '3.x'
|
||||
|
||||
# The search index version.
|
||||
search_version = 'chronos-3'
|
||||
|
||||
# The marketing display name for the book.
|
||||
version_name = ''
|
||||
|
||||
# Project name shown in the black header bar
|
||||
project = 'Chronos'
|
||||
|
||||
# Other versions that display in the version picker menu.
|
||||
version_list = [
|
||||
{'name': '1.x', 'number': '/chronos/1', 'title': '1.x'},
|
||||
{'name': '2.x', 'number': '/chronos/2', 'title': '2.x'},
|
||||
{'name': '3.x', 'number': '/chronos/3', 'title': '3.x', 'current': True},
|
||||
]
|
||||
|
||||
# Languages available.
|
||||
languages = ['en', 'fr', 'ja', 'pt']
|
||||
|
||||
# The GitHub branch name for this version of the docs
|
||||
# for edit links to point at.
|
||||
branch = '3.x'
|
||||
|
||||
# Current version being built
|
||||
version = '3.x'
|
||||
|
||||
# Language in use for this directory.
|
||||
language = 'en'
|
||||
|
||||
show_root_link = True
|
||||
|
||||
repository = 'cakephp/chronos'
|
||||
|
||||
source_path = 'docs/'
|
||||
|
||||
hide_page_contents = ('search', '404', 'contents')
|
||||
@@ -0,0 +1,21 @@
|
||||
3.x Migration Guide
|
||||
###################
|
||||
|
||||
Chronos 3.x contains breaking changes that could impact your application. This
|
||||
guide provides an overview of the breaking changes made in 3.x
|
||||
|
||||
Minimum of PHP 8.1
|
||||
==================
|
||||
|
||||
Chronos 3.x requires at least PHP 8.1. This allows chronos to provide more
|
||||
comprehensive typehinting and better performance by leveraging features found in
|
||||
newer PHP versions.
|
||||
|
||||
MutableDateTime and MutableDate removed
|
||||
=======================================
|
||||
|
||||
The ``MutableDateTime`` and ``MutableDate`` classes have been removed. Long term
|
||||
PHP will be deprecating and removing mutable datetime classes in favour of
|
||||
immutable ones. Chronos has long favoured immutable objects and removing the
|
||||
mutable variants helps simplify the internals of Chronos and encourages safer
|
||||
development practices.
|
||||
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
# Append the top level directory of the docs, so we can import from the config dir.
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# Pull in all the configuration options defined in the global config file..
|
||||
from config.all import *
|
||||
|
||||
language = 'en'
|
||||
@@ -0,0 +1,7 @@
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: CakePHP Chronos
|
||||
|
||||
/index
|
||||
|
||||
API <https://api.cakephp.org/chronos>
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
Chronos
|
||||
#######
|
||||
|
||||
Chronos provides a zero-dependency ``DateTimeImmutable`` extension, Date-only and Time-only classes:
|
||||
|
||||
* ``Cake\Chronos\Chronos`` extends ``DateTimeImmutable`` and provides many helpers.
|
||||
* ``Cake\Chronos\ChronosDate`` represents calendar dates unaffected by time or time zones.
|
||||
* ``Cake\Chronos\ChronosTime`` represents clock times independent of date or time zones.
|
||||
* Only safe, immutable objects.
|
||||
* A pluggable translation system. Only English translations are included in the
|
||||
library. However, ``cakephp/i18n`` can be used for full language support.
|
||||
|
||||
The ``Chronos`` class extends ``DateTimeImmutable`` and implements ``DateTimeInterface``
|
||||
which allows users to use type declarations that support either.
|
||||
|
||||
``ChronosDate`` and ``ChronosTime`` do not extend ``DateTimeImmutable`` and do not
|
||||
share an interface. However, they can be converted to a ``DateTimeImmutable`` instance
|
||||
using ``toDateTimeImmutable()``.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
To install Chronos, you should use ``composer``. From your
|
||||
application's ROOT directory (where composer.json file is located) run the
|
||||
following::
|
||||
|
||||
php composer.phar require "cakephp/chronos:^3.0"
|
||||
|
||||
Creating Instances
|
||||
------------------
|
||||
|
||||
There are many ways to get an instance of Chronos or Date. There are a number of
|
||||
factory methods that work with different argument sets::
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
|
||||
$now = Chronos::now();
|
||||
$today = Chronos::today();
|
||||
$yesterday = Chronos::yesterday();
|
||||
$tomorrow = Chronos::tomorrow();
|
||||
|
||||
// Parse relative expressions
|
||||
$date = Chronos::parse('+2 days, +3 hours');
|
||||
|
||||
// Date and time integer values.
|
||||
$date = Chronos::create(2015, 12, 25, 4, 32, 58);
|
||||
|
||||
// Date or time integer values.
|
||||
$date = Chronos::createFromDate(2015, 12, 25);
|
||||
$date = Chronos::createFromTime(11, 45, 10);
|
||||
|
||||
// Parse formatted values.
|
||||
$date = Chronos::createFromFormat('m/d/Y', '06/15/2015');
|
||||
|
||||
Working with Immutable Objects
|
||||
------------------------------
|
||||
|
||||
Chronos provides only *immutable* objects.
|
||||
|
||||
If you've used PHP ``DateTimeImmutable`` and ``DateTime`` classes, then you understand
|
||||
the difference between *mutable* and *immutable* objects.
|
||||
|
||||
Immutable objects create copies of an object each time a change is made. Because modifier methods
|
||||
around datetimes are not always easy to identify, data can be modified accidentally
|
||||
or without the developer knowing. Immutable objects prevent accidental changes
|
||||
to data, and make code free of order-based dependency issues. Immutability does
|
||||
mean that you will need to remember to replace variables when using modifiers::
|
||||
|
||||
// This code doesn't work with immutable objects
|
||||
$chronos->addDay(1);
|
||||
doSomething($chronos);
|
||||
return $chronos;
|
||||
|
||||
// This works like you'd expect
|
||||
$chronos = $chronos->addDay(1);
|
||||
$chronos = doSomething($chronos);
|
||||
return $chronos;
|
||||
|
||||
By capturing the return value of each modification your code will work as
|
||||
expected.
|
||||
|
||||
Date Objects
|
||||
------------
|
||||
|
||||
PHP provides only date-time classes that combines both dates and time parts.
|
||||
Representing calendar dates can be a bit awkward with ``DateTimeImmutable`` as it includes
|
||||
time and timezones, which aren't part of a 'date'. Chronos provides
|
||||
``ChronosDate`` that allows you to represent dates. The time these objects
|
||||
these objects is always fixed to ``00:00:00`` and not affeced by the server time zone
|
||||
or modify helpers::
|
||||
|
||||
use Cake\Chronos\ChronosDate;
|
||||
|
||||
$today = ChronosDate::today();
|
||||
|
||||
// Changes to the time/timezone are ignored.
|
||||
$today->modify('+1 hours');
|
||||
|
||||
// Outputs '2015-12-20'
|
||||
echo $today;
|
||||
|
||||
Although ``ChronosDate`` uses a fixed time zone internally, you can specify which
|
||||
time zone to use for current time such as ``now()`` or ``today()``::
|
||||
|
||||
use Cake\Chronos\ChronosDate:
|
||||
|
||||
// Takes the current date from Asia/Tokyo time zone
|
||||
$today = ChronosDate::today('Asia/Tokyo');
|
||||
|
||||
Modifier Methods
|
||||
----------------
|
||||
|
||||
Chronos objects provide modifier methods that let you modify the value in
|
||||
a granular way::
|
||||
|
||||
// Set components of the datetime value.
|
||||
$halloween = Chronos::create()
|
||||
->year(2015)
|
||||
->month(10)
|
||||
->day(31)
|
||||
->hour(20)
|
||||
->minute(30);
|
||||
|
||||
You can also modify parts of the datetime relatively::
|
||||
|
||||
$future = Chronos::create()
|
||||
->addYears(1)
|
||||
->subMonths(2)
|
||||
->addDays(15)
|
||||
->addHours(20)
|
||||
->subMinutes(2);
|
||||
|
||||
It is also possible to make big jumps to defined points in time::
|
||||
|
||||
$time = Chronos::create();
|
||||
$time->startOfDay();
|
||||
$time->endOfDay();
|
||||
$time->startOfMonth();
|
||||
$time->endOfMonth();
|
||||
$time->startOfYear();
|
||||
$time->endOfYear();
|
||||
$time->startOfWeek();
|
||||
$time->endOfWeek();
|
||||
|
||||
Or jump to specific days of the week::
|
||||
|
||||
$time->next(Chronos::TUESDAY);
|
||||
$time->previous(Chronos::MONDAY);
|
||||
|
||||
When modifying dates/times across :abbr:`DST (Daylight Savings Time)` transitions
|
||||
your operations may gain/lose an additional hours resulting in hour values that
|
||||
don't add up. You can avoid these issues by first changing your timezone to
|
||||
``UTC``, modifying the time::
|
||||
|
||||
// Additional hour gained.
|
||||
$time = new Chronos('2014-03-30 00:00:00', 'Europe/London');
|
||||
debug($time->modify('+24 hours')); // 2014-03-31 01:00:00
|
||||
|
||||
// First switch to UTC, and modify
|
||||
$time = $time->setTimezone('UTC')
|
||||
->modify('+24 hours');
|
||||
|
||||
Once you are done modifying the time you can add the original timezone to get
|
||||
the localized time.
|
||||
|
||||
Comparison Methods
|
||||
------------------
|
||||
|
||||
Once you have 2 instances of Chronos date/time objects you can compare them in
|
||||
a variety of ways::
|
||||
|
||||
// Full suite of comparators exist
|
||||
// equals, notEquals, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals
|
||||
$first->equals($second);
|
||||
$first->greaterThanOrEquals($second);
|
||||
|
||||
// See if the current object is between two others.
|
||||
$now->between($start, $end);
|
||||
|
||||
// Find which argument is closest or farthest.
|
||||
$now->closest($june, $november);
|
||||
$now->farthest($june, $november);
|
||||
|
||||
You can also inquire about where a given value falls on the calendar::
|
||||
|
||||
$now->isToday();
|
||||
$now->isYesterday();
|
||||
$now->isFuture();
|
||||
$now->isPast();
|
||||
|
||||
// Check the day of the week
|
||||
$now->isWeekend();
|
||||
|
||||
// All other weekday methods exist too.
|
||||
$now->isMonday();
|
||||
|
||||
You can also find out if a value was within a relative time period::
|
||||
|
||||
$time->wasWithinLast('3 days');
|
||||
$time->isWithinNext('3 hours');
|
||||
|
||||
Generating Differences
|
||||
----------------------
|
||||
|
||||
In addition to comparing datetimes, calculating differences or deltas between
|
||||
two values is a common task::
|
||||
|
||||
// Get a DateInterval representing the difference
|
||||
$first->diff($second);
|
||||
|
||||
// Get difference as a count of specific units.
|
||||
$first->diffInHours($second);
|
||||
$first->diffInDays($second);
|
||||
$first->diffInWeeks($second);
|
||||
$first->diffInYears($second);
|
||||
|
||||
You can generate human readable differences suitable for use in a feed or
|
||||
timeline::
|
||||
|
||||
// Difference from now.
|
||||
echo $date->diffForHumans();
|
||||
|
||||
// Difference from another point in time.
|
||||
echo $date->diffForHumans($other); // 1 hour ago;
|
||||
|
||||
Formatting Strings
|
||||
------------------
|
||||
|
||||
Chronos provides a number of methods for displaying our outputting datetime
|
||||
objects::
|
||||
|
||||
// Uses the format controlled by setToStringFormat()
|
||||
echo $date;
|
||||
|
||||
// Different standard formats
|
||||
echo $time->toAtomString(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toCookieString(); // Thursday, 25-Dec-1975 14:15:16 EST
|
||||
echo $time->toIso8601String(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toRfc822String(); // Thu, 25 Dec 75 14:15:16 -0500
|
||||
echo $time->toRfc850String(); // Thursday, 25-Dec-75 14:15:16 EST
|
||||
echo $time->toRfc1036String(); // Thu, 25 Dec 75 14:15:16 -0500
|
||||
echo $time->toRfc1123String(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toRfc2822String(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toRfc3339String(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toRssString(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toW3cString(); // 1975-12-25T14:15:16-05:00
|
||||
|
||||
// Get the quarter/week
|
||||
echo $time->toQuarter(); // 4
|
||||
echo $time->toWeek(); // 52
|
||||
|
||||
// Generic formatting
|
||||
echo $time->toTimeString(); // 14:15:16
|
||||
echo $time->toDateString(); // 1975-12-25
|
||||
echo $time->toDateTimeString(); // 1975-12-25 14:15:16
|
||||
echo $time->toFormattedDateString(); // Dec 25, 1975
|
||||
echo $time->toDayDateTimeString(); // Thu, Dec 25, 1975 2:15 PM
|
||||
|
||||
Extracting Date Components
|
||||
--------------------------
|
||||
|
||||
Getting parts of a date object can be done by directly accessing properties::
|
||||
|
||||
$time = new Chronos('2015-12-31 23:59:58.123');
|
||||
$time->year; // 2015
|
||||
$time->month; // 12
|
||||
$time->day; // 31
|
||||
$time->hour // 23
|
||||
$time->minute // 59
|
||||
$time->second // 58
|
||||
$time->micro // 123
|
||||
|
||||
Other properties that can be accessed are:
|
||||
|
||||
- timezone
|
||||
- timezoneName
|
||||
- dayOfWeek
|
||||
- dayOfMonth
|
||||
- dayOfYear
|
||||
- daysInMonth
|
||||
- timestamp
|
||||
- quarter
|
||||
- half
|
||||
|
||||
Testing Aids
|
||||
------------
|
||||
|
||||
When writing unit tests, it is helpful to fixate the current time. Chronos lets
|
||||
you fix the current time for each class. As part of your test suite's bootstrap
|
||||
process you can include the following::
|
||||
|
||||
Chronos::setTestNow(Chronos::now());
|
||||
ChronosDate::setTestNow(ChronosDate::parse(Chronos::now()));
|
||||
|
||||
This will fix the current time of all objects to be the point at which the test
|
||||
suite started.
|
||||
|
||||
For example, if you fixate the ``Chronos`` to some moment in the past, any new
|
||||
instance of ``Chronos`` created with ``now`` or a relative time string, will be
|
||||
returned relative to the fixated time::
|
||||
|
||||
Chronos::setTestNow(new Chronos('1975-12-25 00:00:00'));
|
||||
|
||||
$time = new Chronos(); // 1975-12-25 00:00:00
|
||||
$time = new Chronos('1 hour ago'); // 1975-12-24 23:00:00
|
||||
|
||||
To reset the fixation, simply call ``setTestNow()`` again with no parameter or
|
||||
with ``null`` as a parameter.
|
||||
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
# Append the top level directory of the docs, so we can import from the config dir.
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# Pull in all the configuration options defined in the global config file..
|
||||
from config.all import *
|
||||
|
||||
language = 'fr'
|
||||
@@ -0,0 +1,7 @@
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: CakePHP Chronos
|
||||
|
||||
/index
|
||||
|
||||
API <https://api.cakephp.org/chronos>
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
Chronos
|
||||
#######
|
||||
|
||||
Chronos fournit une collection d'extensions sans aucune dépendance pour l'objet
|
||||
``DateTime``. En plus de méthodes pratiques, Chronos fournit:
|
||||
|
||||
* Des objets ``Date`` pour représenter les dates du calendrier.
|
||||
* Des objets immutables pour les dates et les datetimes.
|
||||
* Un système de traduction intégrable. Seules les traductions anglaises sont
|
||||
incluses dans la librairie. Cependant, ``cakephp/i18n`` peut être utilisé
|
||||
pour un support complet d'autres langues.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Pour installer Chronos, vous devez utiliser ``composer``. À partir du répertoire
|
||||
ROOT de votre application (celui où se trouve le fichier composer.json),
|
||||
exécutez ce qui suit::
|
||||
|
||||
php composer.phar require "cakephp/chronos:^2.0"
|
||||
|
||||
Vue d'Ensemble
|
||||
--------------
|
||||
|
||||
Chronos fournit un certain nombre d'extensions pour les objets DateTime fournis
|
||||
par PHP. Chronos fournit 5 classes qui gèrent les variantes mutables et
|
||||
immutables de date/time et les extensions de ``DateInterval``.
|
||||
|
||||
* ``Cake\Chronos\Chronos`` est un objet de *date et heure* immutable.
|
||||
* ``Cake\Chronos\ChronosDate`` est un objet de *date* immutable.
|
||||
* ``Cake\Chronos\MutableDateTime`` est un objet de *date et heure* mutable.
|
||||
* ``Cake\Chronos\MutableDate`` est un objet de *date* mutable.
|
||||
* ``Cake\Chronos\ChronosInterval`` est une extension pour l'objet
|
||||
``DateInterval``.
|
||||
|
||||
Créer des Instances
|
||||
-------------------
|
||||
|
||||
Il y a plusieurs façons d'obtenir une instance de Chronos ou de Date. Il y a
|
||||
un certain nombre de méthodes factory qui fonctionnent avec différents ensembles
|
||||
d'arguments::
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
|
||||
$now = Chronos::now();
|
||||
$today = Chronos::today();
|
||||
$yesterday = Chronos::yesterday();
|
||||
$tomorrow = Chronos::tomorrow();
|
||||
|
||||
// Parse les expressions relatives
|
||||
$date = Chronos::parse('+2 days, +3 hours');
|
||||
|
||||
// Des entiers indiquant la date et l'heure.
|
||||
$date = Chronos::create(2015, 12, 25, 4, 32, 58);
|
||||
|
||||
// Des entiers indiquant la date ou l'heure.
|
||||
$date = Chronos::createFromDate(2015, 12, 25);
|
||||
$date = Chronos::createFromTime(11, 45, 10);
|
||||
|
||||
// Parse les valeurs formatées.
|
||||
$date = Chronos::createFromFormat('m/d/Y', '06/15/2015');
|
||||
|
||||
Travailler avec les Objets Immutables
|
||||
-------------------------------------
|
||||
|
||||
Si vous avez utilisé les objets ``DateTime`` de PHP, vous êtes à l'aise avec
|
||||
les objets *mutable*. Chronos offre des objets mutables, mais elle fournit
|
||||
également des objets *immutables*. Les objets Immutables créent des copies des
|
||||
objets à chaque fois qu'un objet est modifié. Puisque les méthodes de
|
||||
modification autour des datetimes ne sont pas toujours transparentes, les
|
||||
données peuvent être modifiées accidentellement ou sans que le développeur ne
|
||||
le sache. Les objets immutables évitent les changements accidentels des
|
||||
données et permettent de s'affranchir de tout problème lié à l'ordre d'appel
|
||||
des fonctions ou des dépendances. L'immutabilité signifie que vous devez vous
|
||||
souvenir de remplacer les variables quand vous utilisez les modificateurs::
|
||||
|
||||
// Ce code ne fonctionne pas avec les objets immutables
|
||||
$time->addDay(1);
|
||||
doSomething($time);
|
||||
return $time;
|
||||
|
||||
// Ceci fonctionne comme vous le souhaitez
|
||||
$time = $time->addDay(1);
|
||||
$time = doSomething($time);
|
||||
return $time;
|
||||
|
||||
En capturant la valeur de retour pour chaque modification, votre code
|
||||
fonctionnera comme souhaité. Si vous avez déjà créé un objet immutable, et que
|
||||
vous souhaitez un objet mutable, vous pouvez utiliser ``toMutable()``::
|
||||
|
||||
$inplace = $time->toMutable();
|
||||
|
||||
Objets Date
|
||||
-----------
|
||||
|
||||
PHP fournit seulement un unique objet DateTime. Représenter les dates de
|
||||
calendrier peut être un peu gênant avec cette classe puisqu'elle inclut les
|
||||
timezones, et les composants de time qui n'appartiennent pas vraiment
|
||||
au concept d'un 'jour'. Chronos fournit un objet ``Date`` qui vous permet
|
||||
de représenter les dates. Les time et timezone pour ces objets sont toujours
|
||||
fixés à ``00:00:00 UTC`` et toutes les méthodes de formatage/différence
|
||||
fonctionnent au niveau du jour::
|
||||
|
||||
use Cake\Chronos\ChronosDate;
|
||||
|
||||
$today = ChronosDate::today();
|
||||
|
||||
// Les changements selon le time/timezone sont ignorés.
|
||||
$today->modify('+1 hours');
|
||||
|
||||
// Affiche '2015-12-20'
|
||||
echo $today;
|
||||
|
||||
Bien que ``Date`` utilise en interne un fuseau horaire fixe, vous pouvez
|
||||
spécifier le fuseau à utiliser pour l'heure courante telle que ``now()`` ou
|
||||
``today()``::
|
||||
|
||||
use Cake\Chronos\ChronosDate:
|
||||
|
||||
// Prend l'heure courante pour le fuseau horaire de Tokyo
|
||||
$today = ChronosDate::today('Asia/Tokyo');
|
||||
|
||||
|
||||
Méthodes de Modification
|
||||
------------------------
|
||||
|
||||
Les objets Chronos fournissent des méthodes de modification qui vous laissent
|
||||
modifier la valeur d'une façon assez précise::
|
||||
|
||||
// Définit les composants de la valeur du datetime.
|
||||
$halloween = Chronos::create()
|
||||
->year(2015)
|
||||
->month(10)
|
||||
->day(31)
|
||||
->hour(20)
|
||||
->minute(30);
|
||||
|
||||
Vous pouvez aussi modifier les parties de la date de façon relative::
|
||||
|
||||
$future = Chronos::create()
|
||||
->addYear(1)
|
||||
->subMonth(2)
|
||||
->addDays(15)
|
||||
->addHours(20)
|
||||
->subMinutes(2);
|
||||
|
||||
Il est également possible de faire des sauts vers des points définis dans le
|
||||
temps::
|
||||
|
||||
$time = Chronos::create();
|
||||
$time->startOfDay();
|
||||
$time->endOfDay();
|
||||
$time->startOfMonth();
|
||||
$time->endOfMonth();
|
||||
$time->startOfYear();
|
||||
$time->endOfYear();
|
||||
$time->startOfWeek();
|
||||
$time->endOfWeek();
|
||||
|
||||
Ou de sauter à un jour spécifique de la semaine::
|
||||
|
||||
$time->next(Chronos::TUESDAY);
|
||||
$time->previous(Chronos::MONDAY);
|
||||
|
||||
Quand vous modifiez des dates/heures au-delà d'un passage à l'heure d'été ou à
|
||||
l'heure d'hiver, vous opérations peuvent gagner/perdre une heure de plus, de
|
||||
sorte que les heures seront incorrectes. Vous pouvez éviter ce problème en
|
||||
définissant d'abord le timezone à ``UTC``, ce qui change l'heure::
|
||||
|
||||
// Une heure de plus de gagnée.
|
||||
$time = new Chronos('2014-03-30 00:00:00', 'Europe/London');
|
||||
debug($time->modify('+24 hours')); // 2014-03-31 01:00:00
|
||||
|
||||
// Passez d'abord à UTC, et modifiez ensuite
|
||||
$time = $time->setTimezone('UTC')
|
||||
->modify('+24 hours');
|
||||
|
||||
Une fois que vous avez modifié l'heure, vous pouvez repasser au timezone
|
||||
d'origine pour obtenir l'heure locale.
|
||||
|
||||
Méthodes de Comparaison
|
||||
-----------------------
|
||||
|
||||
Une fois que vous avez 2 instances d'objets date/time de Chronos, vous pouvez
|
||||
les comparer de plusieurs façons::
|
||||
|
||||
// Il existe une suite complète de comparateurs
|
||||
// equals, notEquals, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals
|
||||
$first->equals($second);
|
||||
$first->greaterThanOrEquals($second);
|
||||
|
||||
// Regarder si l'objet courant est entre deux autres.
|
||||
$now->between($start, $end);
|
||||
|
||||
// Trouver l'argument le plus proche ou le plus éloigné.
|
||||
$now->closest($june, $november);
|
||||
$now->farthest($june, $november);
|
||||
|
||||
Vous pouvez aussi vous renseigner sur le moment où une valeur donnée tombe dans
|
||||
le calendrier::
|
||||
|
||||
$now->isToday();
|
||||
$now->isYesterday();
|
||||
$now->isFuture();
|
||||
$now->isPast();
|
||||
|
||||
// Vérifie le jour de la semaine
|
||||
$now->isWeekend();
|
||||
|
||||
// Toutes les autres méthodes des jours de la semaine existent aussi.
|
||||
$now->isMonday();
|
||||
|
||||
Vous pouvez aussi trouver si une valeur était dans une période de temps relative::
|
||||
|
||||
$time->wasWithinLast('3 days');
|
||||
$time->isWithinNext('3 hours');
|
||||
|
||||
Générer des Différences
|
||||
-----------------------
|
||||
|
||||
En plus de comparer les datetimes, calculer les différences ou les deltas entre
|
||||
des valeurs est une tâche courante::
|
||||
|
||||
// Récupère un DateInterval représentant la différence
|
||||
$first->diff($second);
|
||||
|
||||
// Récupère la différence en tant que nombre d'unités spécifiques.
|
||||
$first->diffInHours($second);
|
||||
$first->diffInDays($second);
|
||||
$first->diffInWeeks($second);
|
||||
$first->diffInYears($second);
|
||||
|
||||
Vous pouvez générer des différences lisibles qui peuvent vous servir pour
|
||||
l'utilisation d'un feed ou d'une timeline::
|
||||
|
||||
// Différence à partir de maintenant.
|
||||
echo $date->diffForHumans();
|
||||
|
||||
// Différence à partir d'un autre point du temps.
|
||||
echo $date->diffForHumans($other); // 1 hour ago;
|
||||
|
||||
Formater les Chaînes
|
||||
--------------------
|
||||
|
||||
Chronos fournit un certain nombre de méthodes pour afficher nos sorties d'objets
|
||||
datetime::
|
||||
|
||||
// Utilise le format contrôlé par setToStringFormat()
|
||||
echo $date;
|
||||
|
||||
// Différents formats standards
|
||||
echo $time->toAtomString(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toCookieString(); // Thursday, 25-Dec-1975 14:15:16 EST
|
||||
echo $time->toIso8601String(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toRfc822String(); // Thu, 25 Dec 75 14:15:16 -0500
|
||||
echo $time->toRfc850String(); // Thursday, 25-Dec-75 14:15:16 EST
|
||||
echo $time->toRfc1036String(); // Thu, 25 Dec 75 14:15:16 -0500
|
||||
echo $time->toRfc1123String(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toRfc2822String(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toRfc3339String(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toRssString(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toW3cString(); // 1975-12-25T14:15:16-05:00
|
||||
|
||||
// Récupère le trimestre
|
||||
echo $time->toQuarter(); // 4;
|
||||
// Récupère la semaine
|
||||
echo $time->toWeek(); // 52;
|
||||
|
||||
// Formatage générique
|
||||
echo $time->toTimeString(); // 14:15:16
|
||||
echo $time->toDateString(); // 1975-12-25
|
||||
echo $time->toDateTimeString(); // 1975-12-25 14:15:16
|
||||
echo $time->toFormattedDateString(); // Dec 25, 1975
|
||||
echo $time->toDayDateTimeString(); // Thu, Dec 25, 1975 2:15 PM
|
||||
|
||||
Extraire des Fragments de Date
|
||||
------------------------------
|
||||
|
||||
Il est possible de récupérer des parties d'un objet date en accédant directement
|
||||
à ses propriétés::
|
||||
|
||||
$time = new Chronos('2015-12-31 23:59:58.123');
|
||||
$time->year; // 2015
|
||||
$time->month; // 12
|
||||
$time->day; // 31
|
||||
$time->hour // 23
|
||||
$time->minute // 59
|
||||
$time->second // 58
|
||||
$time->micro // 123
|
||||
|
||||
Les autres propriétés accessibles sont:
|
||||
|
||||
- timezone
|
||||
- timezoneName
|
||||
- dayOfWeek
|
||||
- dayOfMonth
|
||||
- dayOfYear
|
||||
- daysInMonth
|
||||
- timestamp
|
||||
- quarter
|
||||
- half
|
||||
|
||||
Aides aux Tests
|
||||
---------------
|
||||
|
||||
Quand vous écrivez des tests unitaires, il peut être utile de fixer le *time*
|
||||
courant. Chronos vous permet de fixer le time courant pour chaque classe.
|
||||
Pour l'intégrer dans votre processus de démarrage (bootstrap) de suite de tests,
|
||||
vous pouvez inclure ce qui suit::
|
||||
|
||||
Chronos::setTestNow(Chronos::now());
|
||||
MutableDateTime::setTestNow(MutableDateTime::now());
|
||||
ChronosDate::setTestNow(ChronosDate::parse(Chronos::now()));
|
||||
MutableDate::setTestNow(MutableDate::now());
|
||||
|
||||
Ceci va fixer le time courant de tous les objets selon le moment où la suite de
|
||||
tests a démarré.
|
||||
|
||||
Par exemple, si vous fixez le ``Chronos`` à un moment du passé, chaque nouvelle
|
||||
instance de ``Chronos`` créée avec ``now`` ou une chaine de temps relative, sera
|
||||
retournée relativement à la date fixée::
|
||||
|
||||
Chronos::setTestNow(new Chronos('1975-12-25 00:00:00'));
|
||||
|
||||
$time = new Chronos(); // 1975-12-25 00:00:00
|
||||
$time = new Chronos('1 hour ago'); // 1975-12-24 23:00:00
|
||||
|
||||
Pour réinitialiser la "fixation" du temps, appelez simplement ``setTestNow()``
|
||||
sans paramètre ou avec ``null`` comme paramètre.
|
||||
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
# Append the top level directory of the docs, so we can import from the config dir.
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# Pull in all the configuration options defined in the global config file..
|
||||
from config.all import *
|
||||
|
||||
language = 'ja'
|
||||
@@ -0,0 +1,7 @@
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: CakePHP Chronos
|
||||
|
||||
/index
|
||||
|
||||
API <https://api.cakephp.org/chronos>
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
Chronos
|
||||
#######
|
||||
|
||||
Chronos (クロノス) は、 ``DateTime`` オブジェクトへの拡張の依存関係の無いコレクションを提供します。
|
||||
便利なメソッドに加えて、Chronos は以下を提供します。
|
||||
|
||||
* カレンダー日付のための ``Date`` オブジェクト
|
||||
* イミュータブルな日付と日時オブジェクト
|
||||
* プラグインのような翻訳システム。ライブラリーは英語のみの翻訳を含んでいます。
|
||||
しかし、全ての言語サポートのために、 ``cakephp/i18n`` を使うことができます。
|
||||
|
||||
インストール
|
||||
------------
|
||||
|
||||
Chronos をインストールするためには、 ``composer`` を利用することができます。
|
||||
アプリケーションの ROOT ディレクトリー(composer.json ファイルのある場所)
|
||||
で以下のように実行します。 ::
|
||||
|
||||
php composer.phar require cakephp/chronos "@stable"
|
||||
|
||||
概要
|
||||
----
|
||||
|
||||
Chronos は PHP が提供する DateTime オブジェクトのいくつかの拡張を提供します。
|
||||
Chronos は ``DateInterval`` の拡張機能および、ミュータブル(変更可能)と
|
||||
イミュータブル(変更不可)な 日付/時刻 の派生系をカバーする5つのクラスを提供します。
|
||||
|
||||
* ``Cake\Chronos\Chronos`` はイミュータブルな *日付と時刻* オブジェクト。
|
||||
* ``Cake\Chronos\ChronosDate`` はイミュータブルな *日付* オブジェクト。
|
||||
* ``Cake\Chronos\MutableDateTime`` はミュータブルな *日付と時刻* オブジェクト。
|
||||
* ``Cake\Chronos\MutableDate`` はミュータブルな *日付* オブジェクト。
|
||||
* ``Cake\Chronos\ChronosInterval`` は ``DateInterval`` の拡張機能。
|
||||
|
||||
インスタンスの作成
|
||||
------------------
|
||||
|
||||
Chronos または Date のインスタンスを取得するためには、多くの方法があります。
|
||||
異なる引数セットで動作する多くのファクトリーメソッドがあります。 ::
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
|
||||
$now = Chronos::now();
|
||||
$today = Chronos::today();
|
||||
$yesterday = Chronos::yesterday();
|
||||
$tomorrow = Chronos::tomorrow();
|
||||
|
||||
// 相対式のパース
|
||||
$date = Chronos::parse('+2 days, +3 hours');
|
||||
|
||||
// 日付と時間の整数値
|
||||
$date = Chronos::create(2015, 12, 25, 4, 32, 58);
|
||||
|
||||
// 日付または時間の整数値
|
||||
$date = Chronos::createFromDate(2015, 12, 25);
|
||||
$date = Chronos::createFromTime(11, 45, 10);
|
||||
|
||||
// 整形した値にパース
|
||||
$date = Chronos::createFromFormat('m/d/Y', '06/15/2015');
|
||||
|
||||
イミュータブルオブジェクトの動作
|
||||
--------------------------------
|
||||
|
||||
もしあなたが、PHP の ``DateTime`` オブジェクトを使用したことがあるなら、
|
||||
*ミュータブル* オブジェクトは簡単に使用できます。
|
||||
Chronos はミュータブルオブジェクトを提供しますが、これは *イミュータブル* オブジェクトにもなります。
|
||||
イミュータブルオブジェクトはオブジェクトが変更されるたびにオブジェクトのコピーを作ります。
|
||||
なぜなら、日時周りの変更メソッドは必ずしも透明でないため、データが誤って、
|
||||
または開発者が知らない内に変更してしまうからです。
|
||||
イミュータブルオブジェクトはデータが誤って変更されることを防止し、
|
||||
順序ベースの依存関係の問題の無いコードを作ります。
|
||||
不変性は、変更時に忘れずに変数を置き換える必要があることを意味しています。 ::
|
||||
|
||||
// このコードはイミュータブルオブジェクトでは動作しません
|
||||
$time->addDay(1);
|
||||
doSomething($time);
|
||||
return $time
|
||||
|
||||
// このコードは期待通りに動作します
|
||||
$time = $time->addDay(1);
|
||||
$time = doSomething($time);
|
||||
return $time
|
||||
|
||||
各修正の戻り値をキャプチャーすることによって、コードは期待通りに動作します。
|
||||
イミュータブルオブジェクトを持っていて、ミュータブルオブジェクトを作りたい場合、
|
||||
``toMutable()`` が使用できます。 ::
|
||||
|
||||
$inplace = $time->toMutable();
|
||||
|
||||
日付オブジェクト
|
||||
------------------
|
||||
|
||||
PHP は単純な DateTime オブジェクトだけを提供します。このクラスのカレンダー日付の表現で、
|
||||
タイムゾーンおよび、本当に「日」の概念に属していないタイムコンポーネントを含むと、
|
||||
少し厄介な可能性があります。
|
||||
Chronos は日時表現のための ``Date`` オブジェクトを提供します。
|
||||
これらのオブジェクトの時間とタイムゾーンは常に ``00:00:00 UTC`` に固定されており、
|
||||
全ての書式/差分のメソッドは一日単位で動作します。 ::
|
||||
|
||||
use Cake\Chronos\ChronosDate;
|
||||
|
||||
$today = ChronosDate::today();
|
||||
|
||||
// 時間/タイムゾーンの変更は無視されます
|
||||
$today->modify('+1 hours');
|
||||
|
||||
// 出力 '2015-12-20'
|
||||
echo $today;
|
||||
|
||||
変更メソッド
|
||||
------------
|
||||
|
||||
Chronos オブジェクトは細やかに値を変更できるメソッドを提供します。 ::
|
||||
|
||||
// 日時の値のコンポーネントを設定
|
||||
$halloween = Chronos::create()
|
||||
->year(2015)
|
||||
->month(10)
|
||||
->day(31)
|
||||
->hour(20)
|
||||
->minute(30);
|
||||
|
||||
また、日時の部分を相対的に変更することもできます。 ::
|
||||
|
||||
$future = Chronos::create()
|
||||
->addYear(1)
|
||||
->subMonth(2)
|
||||
->addDays(15)
|
||||
->addHours(20)
|
||||
->subMinutes(2);
|
||||
|
||||
また、ある時間の中で、定義された時点に飛ぶことも可能です。 ::
|
||||
|
||||
$time = Chronos::create();
|
||||
$time->startOfDay();
|
||||
$time->endOfDay();
|
||||
$time->startOfMonth();
|
||||
$time->endOfMonth();
|
||||
$time->startOfYear();
|
||||
$time->endOfYear();
|
||||
$time->startOfWeek();
|
||||
$time->endOfWeek();
|
||||
|
||||
また、1週間中の特定の日にも飛べます。 ::
|
||||
|
||||
$time->next(Chronos::TUESDAY);
|
||||
$time->previous(Chronos::MONDAY);
|
||||
|
||||
:abbr:`DST (夏時間)` の遷移の前後で日付/時間を変更すると、
|
||||
あなたの操作で時間が増減するかもしれませんが、その結果、意図しない時間の値になります。
|
||||
これらの問題を回避するには、最初にタイムゾーンを ``UTC`` に変更し、時間を変更します。 ::
|
||||
|
||||
// 余分な時間が追加されました
|
||||
$time = new Chronos('2014-03-30 00:00:00', 'Europe/London');
|
||||
debug($time->modify('+24 hours')); // 2014-03-31 01:00:00
|
||||
|
||||
// 最初に UTC に切り替え、そして更新
|
||||
$time = $time->setTimezone('UTC')
|
||||
->modify('+24 hours');
|
||||
|
||||
時間を変更すると、元のタイムゾーンを追加してローカライズされた時間を取得することができます。
|
||||
|
||||
比較メソッド
|
||||
------------
|
||||
|
||||
Chronos の日付/時間オブジェクトの2つのインスタンスを様々な方法で比較することができます。 ::
|
||||
|
||||
// 比較のフルセットが存在します
|
||||
// equals, notEquals, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals
|
||||
$first->equals($second);
|
||||
$first->greaterThanOrEquals($second);
|
||||
|
||||
// カレントオブジェクトが2つのオブジェクトの間にあるかどうかを確認します。
|
||||
$now->between($start, $end);
|
||||
|
||||
// どちらの引数が最も近い (closest) か、または最も遠い (farthest) かを見つけます。
|
||||
$now->closest($june, $november);
|
||||
$now->farthest($june, $november);
|
||||
|
||||
また、与えられた値のカレンダーに当たる場所について問い合わせできます。 ::
|
||||
|
||||
$now->isToday();
|
||||
$now->isYesterday();
|
||||
$now->isFuture();
|
||||
$now->isPast();
|
||||
|
||||
// 曜日をチェック
|
||||
$now->isWeekend();
|
||||
|
||||
// 他の曜日のメソッドも全て存在します。
|
||||
$now->isMonday();
|
||||
|
||||
また、値が相対的な期間内にあったかどうかを見つけることができます。 ::
|
||||
|
||||
$time->wasWithinLast('3 days');
|
||||
$time->isWithinNext('3 hours');
|
||||
|
||||
差の生成
|
||||
--------
|
||||
|
||||
日時比較に加えて、2つの値の差や変化の計算は一般的なタスクです。 ::
|
||||
|
||||
// 差をあらわす DateInterval を取得
|
||||
$first->diff($second);
|
||||
|
||||
// 特定の単位での差を取得
|
||||
$first->diffInHours($second);
|
||||
$first->diffInDays($second);
|
||||
$first->diffInWeeks($second);
|
||||
$first->diffInYears($second);
|
||||
|
||||
フィードやタイムラインで使用するのに適した、人が読める形式の差を生成することができます。 ::
|
||||
|
||||
// 現在からの差
|
||||
echo $date->diffForHumans();
|
||||
|
||||
// 別の時点からの差
|
||||
echo $date->diffForHumans($other); // 1時間前;
|
||||
|
||||
フォーマットの設定
|
||||
------------------
|
||||
|
||||
Chronos は、出力した日時オブジェクトを表示するための多くのメソッドを提供します。 ::
|
||||
|
||||
// setToStringFormat() が制御するフォーマットを使用します
|
||||
echo $date;
|
||||
|
||||
// 別の標準フォーマット
|
||||
echo $time->toAtomString(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toCookieString(); // Thursday, 25-Dec-1975 14:15:16 EST
|
||||
echo $time->toIso8601String(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toRfc822String(); // Thu, 25 Dec 75 14:15:16 -0500
|
||||
echo $time->toRfc850String(); // Thursday, 25-Dec-75 14:15:16 EST
|
||||
echo $time->toRfc1036String(); // Thu, 25 Dec 75 14:15:16 -0500
|
||||
echo $time->toRfc1123String(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toRfc2822String(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toRfc3339String(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toRssString(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toW3cString(); // 1975-12-25T14:15:16-05:00
|
||||
|
||||
// クォーター/週数を取得
|
||||
echo $time->toQuarter(); // 4;
|
||||
echo $time->toWeek(); // 52
|
||||
|
||||
// 一般的なフォーマット
|
||||
echo $time->toTimeString(); // 14:15:16
|
||||
echo $time->toDateString(); // 1975-12-25
|
||||
echo $time->toDateTimeString(); // 1975-12-25 14:15:16
|
||||
echo $time->toFormattedDateString(); // Dec 25, 1975
|
||||
echo $time->toDayDateTimeString(); // Thu, Dec 25, 1975 2:15 PM
|
||||
|
||||
日付要素の抽出
|
||||
--------------
|
||||
|
||||
日付オブジェクトのプロパティーに直接アクセスして要素を取得することができます。 ::
|
||||
|
||||
$time = new Chronos('2015-12-31 23:59:58');
|
||||
$time->year; // 2015
|
||||
$time->month; // 12
|
||||
$time->day; // 31
|
||||
$time->hour // 23
|
||||
$time->minute // 59
|
||||
$time->second // 58
|
||||
|
||||
以下のプロパティーにもアクセスできます。 :
|
||||
|
||||
- timezone
|
||||
- timezoneName
|
||||
- micro
|
||||
- dayOfWeek
|
||||
- dayOfMonth
|
||||
- dayOfYear
|
||||
- daysInMonth
|
||||
- timestamp
|
||||
- quarter
|
||||
- half
|
||||
|
||||
テストの支援
|
||||
------------
|
||||
|
||||
単体テストを書いている時、現在時刻を固定すると便利です。Chronos は、
|
||||
各クラスの現在時刻を修正することができます。
|
||||
テストスイートの bootstrap 処理に以下を含めることができます。 ::
|
||||
|
||||
Chronos::setTestNow(Chronos::now());
|
||||
MutableDateTime::setTestNow(MutableDateTime::now());
|
||||
ChronosDate::setTestNow(ChronosDate::parse(Chronos::now()));
|
||||
MutableDate::setTestNow(MutableDate::now());
|
||||
|
||||
これでテストスイートが開始された時点で全てのオブジェクトの現在時刻を修正します。
|
||||
|
||||
例えば、 ``Chronos`` を過去のある瞬間に固定した場合、新たな ``Chronos``
|
||||
のインスタンスが生成する ``now`` または相対時刻の文字列は、
|
||||
固定された時刻の相対を返却します。 ::
|
||||
|
||||
Chronos::setTestNow(new Chronos('1975-12-25 00:00:00'));
|
||||
|
||||
$time = new Chronos(); // 1975-12-25 00:00:00
|
||||
$time = new Chronos('1 hour ago'); // 1975-12-24 23:00:00
|
||||
|
||||
固定をリセットするには、 ``setTestNow()`` をパラメーター無し、または ``null`` を設定して
|
||||
再び呼び出してください。
|
||||
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
# Append the top level directory of the docs, so we can import from the config dir.
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# Pull in all the configuration options defined in the global config file..
|
||||
from config.all import *
|
||||
|
||||
language = 'pt'
|
||||
@@ -0,0 +1,7 @@
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: CakePHP Chronos
|
||||
|
||||
/index
|
||||
|
||||
API <https://api.cakephp.org/chronos>
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
Chronos
|
||||
#######
|
||||
|
||||
O Chronos oferece uma coleção independente de extensões para lidar com o objeto
|
||||
``DateTime``. Além de métodos de conveniência, o Chronos oferece:
|
||||
|
||||
* Objetos ``Date`` para representar datas de calendário.
|
||||
* Objetos *date* e *datetime* imutáveis.
|
||||
* Um sistema de tradução acoplável. Apenas traduções em inglês estão incluídas
|
||||
na biblioteca. Todavia, ``cakephp/i18n`` pode ser usado para suporte completo
|
||||
a idiomas.
|
||||
|
||||
Instalação
|
||||
----------
|
||||
|
||||
Para instalar o Chronos, você deve usar o ``composer``. A partir do diretório
|
||||
*ROOT* de sua aplicação (local onde o arquivo composer.json está localizado)
|
||||
execute o seguinte comando::
|
||||
|
||||
php composer.phar require cakephp/chronos "@stable"
|
||||
|
||||
Visão geral
|
||||
-----------
|
||||
|
||||
Chronos oferece extensões para lidar com objetos *DateTime* do PHP. 5 classes
|
||||
cobrem variantes de data/hora mutáveis e imutáveis e uma extensão do objeto
|
||||
``DateInterval``.
|
||||
|
||||
* ``Cake\Chronos\Chronos`` é um objeto *date & time* imutável.
|
||||
* ``Cake\Chronos\ChronosDate`` é um objeto *date* imutável.
|
||||
* ``Cake\Chronos\MutableDateTime`` é um objeto *date and time* mutável.
|
||||
* ``Cake\Chronos\MutableDate`` é um objeto *date* mutável.
|
||||
* ``Cake\Chronos\ChronosInterval`` é uma extensão do objeto ``DateInterval``.
|
||||
|
||||
Criando instâncias
|
||||
------------------
|
||||
|
||||
Existem várias maneiras de criar instâncias do Chronos ou mesmo, do objeto Date.
|
||||
Um número considerável de métodos padrão que funcionam com conjuntos diferentes
|
||||
de argumentos::
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
|
||||
$now = Chronos::now();
|
||||
$today = Chronos::today();
|
||||
$yesterday = Chronos::yesterday();
|
||||
$tomorrow = Chronos::tomorrow();
|
||||
|
||||
// Interpreta expressões relativas.
|
||||
$date = Chronos::parse('+2 days, +3 hours');
|
||||
|
||||
// Valores inteiros de Date e Time.
|
||||
$date = Chronos::create(2015, 12, 25, 4, 32, 58);
|
||||
|
||||
// Valores inteiros de Date ou Time.
|
||||
$date = Chronos::createFromDate(2015, 12, 25);
|
||||
$date = Chronos::createFromTime(11, 45, 10);
|
||||
|
||||
// Interpreta valores formatados.
|
||||
$date = Chronos::createFromFormat('m/d/Y', '06/15/2015');
|
||||
|
||||
Trabalhando com objetos imutáveis
|
||||
---------------------------------
|
||||
|
||||
Se você é familiarizado com os objetos ``DateTime`` do PHP, você se sentirá
|
||||
confortável com objetos *mutáveis*. Além de objetos mutáveis o Chronos também
|
||||
oferece objetos imutáveis que por sua vez criam cópias de objetos toda vez que
|
||||
um objeto é modificado. Devido ao fato de que metodos modificadores relativos
|
||||
a data e hora nem sempre serem transparentes, informações podem ser modificadas
|
||||
acidentalmente ou sem que o desenvolvedor saiba. Objetos imutáveis previnem
|
||||
essas alterações acidentais nos dados. Imutabilidade significa que você deverá
|
||||
lembrar de substituir variáveis usando modificadores::
|
||||
|
||||
// Esse código não funciona com objetos imutáveis
|
||||
$time->addDay(1);
|
||||
doSomething($time);
|
||||
return $time;
|
||||
|
||||
// Esse funciona como o esperado
|
||||
$time = $time->addDay(1);
|
||||
$time = doSomething($time);
|
||||
return $time;
|
||||
|
||||
Ao capturar o valor de retorno de cada modificação, seu código funcionará como o
|
||||
esperado. Se você tem um objeto imutável e quer criar um mutável a partir do
|
||||
mesmo, use ``toMutable()``::
|
||||
|
||||
$inplace = $time->toMutable();
|
||||
|
||||
Objetos Date
|
||||
------------
|
||||
|
||||
O PHP disponibiliza um único objeto DateTime. Representar datas de calendário
|
||||
pode ser um pouco desconfortável por essa classe, uma vez que ela inclui
|
||||
*timezones* e componentes de hora que realmente não se encaixam no conceito de
|
||||
'dia'. O Chronos oferece um objeto ``Date`` para representar datas. A hora e a
|
||||
zona desse objeto é sempre fixado em ``00:00:00 UTC`` e todos os métodos de
|
||||
formatação/diferença operam sob a resolução de dia::
|
||||
|
||||
use Cake\Chronos\ChronosDate;
|
||||
|
||||
$today = ChronosDate::today();
|
||||
|
||||
// Mudanças na hora/timezone são ignoradas
|
||||
$today->modify('+1 hours');
|
||||
|
||||
// Exibe '2016-08-15'
|
||||
echo $today;
|
||||
|
||||
Métodos modificadores
|
||||
---------------------
|
||||
|
||||
Objetos Chronos disponibilizam métodos que permitem a modificação de valores de
|
||||
forma granular::
|
||||
|
||||
// Define componentes do valor datetime
|
||||
$halloween = Chronos::create()
|
||||
->year(2015)
|
||||
->month(10)
|
||||
->day(31)
|
||||
->hour(20)
|
||||
->minute(30);
|
||||
|
||||
Você também pode modificar partes da data relativamente::
|
||||
|
||||
$future = Chronos::create()
|
||||
->addYear(1)
|
||||
->subMonth(2)
|
||||
->addDays(15)
|
||||
->addHours(20)
|
||||
->subMinutes(2);
|
||||
|
||||
Também é possível realizar grandes saltos para períodos definidos no tempo::
|
||||
|
||||
$time = Chronos::create();
|
||||
$time->startOfDay();
|
||||
$time->startOfMonth();
|
||||
$time->endOfMonth();
|
||||
$time->endOfYear();
|
||||
$time->startOfWeek();
|
||||
$time->endOfWeek();
|
||||
|
||||
Ou ainda para dias específicos da semana::
|
||||
|
||||
$time->next(Chronos::TUESDAY);
|
||||
$time->previous(Chronos::MONDAY);
|
||||
|
||||
Métodos de comparação
|
||||
---------------------
|
||||
|
||||
Uma vez que você possui 2 instâncias de objetos data/hora do Chronos, é possível
|
||||
compará-los de várias maneiras::
|
||||
|
||||
// Coleção completa de comparadores
|
||||
// equals, notEquals, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals
|
||||
$first->equals($second);
|
||||
$first->greaterThanOrEquals($second);
|
||||
|
||||
// Veja se o objeto atual está entre outros
|
||||
$now->between($start, $end);
|
||||
|
||||
// Encontre qual argumento está mais perto ou mais longe
|
||||
$now->closest($june, $november);
|
||||
$now->farthest($june, $november);
|
||||
|
||||
Você também pode arguir sobre quando um determinado valor cai no calendário::
|
||||
|
||||
$now->isToday();
|
||||
$now->isYesterday();
|
||||
$now->isFuture();
|
||||
$now->isPast();
|
||||
|
||||
// Verifica se o dia é no final de semana
|
||||
$now->isWeekend();
|
||||
|
||||
// Todos os métodos para outros dias da semana existem também
|
||||
$now->isMonday();
|
||||
|
||||
Você também pode verificar se um determinado valor está dentro de um período de
|
||||
tempo relativo::
|
||||
|
||||
$time->wasWithinLast('3 days');
|
||||
$time->isWithinNext('3 hours');
|
||||
|
||||
Gerando diferenças
|
||||
------------------
|
||||
|
||||
Em adição à comparação de *datetimes*, calcular diferenças ou deltas entre
|
||||
valores é uma tarefa simples::
|
||||
|
||||
// Recebe um DateInterval representando a diferença
|
||||
$first->diff($second);
|
||||
|
||||
// Recebe a diferença como um contador de unidades específicas
|
||||
$first->diffInHours($second);
|
||||
$first->diffInDays($second);
|
||||
$first->diffInWeeks($second);
|
||||
$first->diffInYears($second);
|
||||
|
||||
Você pode gerar diferenças de fácil leitura para humanos para usar em um *feed*
|
||||
ou *timeline*::
|
||||
|
||||
// Diferença em relação ao momento atual
|
||||
echo $date->diffForHumans();
|
||||
|
||||
// Diferença em relação a outro período no tempo
|
||||
echo $date->diffForHumans($other); // 1 hora atrás;
|
||||
|
||||
Formatando strings
|
||||
------------------
|
||||
|
||||
O Chronos disponibiliza métodos para exibir nossos objetos *datetime*::
|
||||
|
||||
// Usa o formato controlado por setToStringFormat()
|
||||
echo $date;
|
||||
|
||||
// Diferentes padrões de formato
|
||||
echo $time->toAtomString(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toCookieString(); // Thursday, 25-Dec-1975 14:15:16 EST
|
||||
echo $time->toIso8601String(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toRfc822String(); // Thu, 25 Dec 75 14:15:16 -0500
|
||||
echo $time->toRfc850String(); // Thursday, 25-Dec-75 14:15:16 EST
|
||||
echo $time->toRfc1036String(); // Thu, 25 Dec 75 14:15:16 -0500
|
||||
echo $time->toRfc1123String(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toRfc2822String(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toRfc3339String(); // 1975-12-25T14:15:16-05:00
|
||||
echo $time->toRssString(); // Thu, 25 Dec 1975 14:15:16 -0500
|
||||
echo $time->toW3cString(); // 1975-12-25T14:15:16-05:00
|
||||
|
||||
// Recebe o trimestre
|
||||
echo $time->toQuarter(); // 4;
|
||||
|
||||
Extraindo componentes de data
|
||||
-----------------------------
|
||||
|
||||
Podemos receber partes de um objeto *date* acessando propriedades::
|
||||
|
||||
$time = new Chronos('2015-12-31 23:59:58');
|
||||
$time->year; // 2015
|
||||
$time->month; // 12
|
||||
$time->day; // 31
|
||||
$time->hour // 23
|
||||
$time->minute // 59
|
||||
$time->second // 58
|
||||
|
||||
Outras propriedades que podem ser acessadas são:
|
||||
|
||||
- timezone
|
||||
- timezoneName
|
||||
- micro
|
||||
- dayOfWeek
|
||||
- dayOfMonth
|
||||
- dayOfYear
|
||||
- daysInMonth
|
||||
- timestamp
|
||||
- quarter
|
||||
- half
|
||||
|
||||
Auxílio para testes
|
||||
-------------------
|
||||
|
||||
Ao escrever testes unitários, fixar a hora atual é bastante útil. O Chronos
|
||||
lhe permite fixar a hora atual para cada classe. Como parte das suas ferramentas
|
||||
de testes, você pode incluir o seguinte::
|
||||
|
||||
Chronos::setTestNow(Chronos::now());
|
||||
MutableDateTime::setTestNow(MutableDateTime::now());
|
||||
ChronosDate::setTestNow(ChronosDate::parse(Chronos::now()));
|
||||
MutableDate::setTestNow(MutableDate::now());
|
||||
|
||||
Isso irá corrigir a hora atual de todos os objetos para o momento em que o
|
||||
processo de testes foi iniciado.
|
||||
|
||||
Por exemplo, se você fixar o ``Chronos`` em algum momento no passado, qualquer
|
||||
nova instância do ``Chronos`` criada com ``now`` ou uma *string* de tempo
|
||||
relativa, teremos um retorno referente ao tempo fixado::
|
||||
|
||||
Chronos::setTestNow(new Chronos('1975-12-25 00:00:00'));
|
||||
|
||||
$time = new Chronos(); // 1975-12-25 00:00:00
|
||||
$time = new Chronos('1 hour ago'); // 1975-12-24 23:00:00
|
||||
|
||||
+2719
File diff suppressed because it is too large
Load Diff
+1686
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Cake\Chronos;
|
||||
|
||||
use DatePeriod;
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* DatePeriod wrapper that returns Chronos instances.
|
||||
*
|
||||
* @template TKey int
|
||||
* @template TValue \Cake\Chronos\ChronosDate
|
||||
* @template-implements \Iterator<int, \Cake\Chronos\ChronosDate>
|
||||
*/
|
||||
class ChronosDatePeriod implements Iterator
|
||||
{
|
||||
/**
|
||||
* @var \Iterator<int, \DateTimeInterface>
|
||||
*/
|
||||
protected Iterator $iterator;
|
||||
|
||||
/**
|
||||
* @param \DatePeriod $period
|
||||
*/
|
||||
public function __construct(DatePeriod $period)
|
||||
{
|
||||
/** @var \Iterator<int, \DateTimeInterface> $iterator */
|
||||
$iterator = $period->getIterator();
|
||||
$this->iterator = $iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Cake\Chronos\ChronosDate
|
||||
*/
|
||||
public function current(): ChronosDate
|
||||
{
|
||||
return new ChronosDate($this->iterator->current());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function key(): int
|
||||
{
|
||||
return $this->iterator->key();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function next(): void
|
||||
{
|
||||
$this->iterator->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->iterator->rewind();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function valid(): bool
|
||||
{
|
||||
return $this->iterator->valid();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Cake\Chronos;
|
||||
|
||||
use DatePeriod;
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* DatePeriod wrapper that returns Chronos instances.
|
||||
*
|
||||
* @template TKey int
|
||||
* @template TValue \Cake\Chronos\Chronos
|
||||
* @template-implements \Iterator<int, \Cake\Chronos\Chronos>
|
||||
*/
|
||||
class ChronosPeriod implements Iterator
|
||||
{
|
||||
/**
|
||||
* @var \Iterator<int, \DateTimeInterface>
|
||||
*/
|
||||
protected Iterator $iterator;
|
||||
|
||||
/**
|
||||
* @param \DatePeriod $period
|
||||
*/
|
||||
public function __construct(DatePeriod $period)
|
||||
{
|
||||
/** @var \Iterator<int, \DateTimeInterface> $iterator */
|
||||
$iterator = $period->getIterator();
|
||||
$this->iterator = $iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Cake\Chronos\Chronos
|
||||
*/
|
||||
public function current(): Chronos
|
||||
{
|
||||
return new Chronos($this->iterator->current());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function key(): int
|
||||
{
|
||||
return $this->iterator->key();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function next(): void
|
||||
{
|
||||
$this->iterator->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->iterator->rewind();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function valid(): bool
|
||||
{
|
||||
return $this->iterator->valid();
|
||||
}
|
||||
}
|
||||
+493
@@ -0,0 +1,493 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Cake\Chronos;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use InvalidArgumentException;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @phpstan-consistent-constructor
|
||||
*/
|
||||
class ChronosTime implements Stringable
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected const TICKS_PER_MICROSECOND = 1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected const TICKS_PER_SECOND = 1000000;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected const TICKS_PER_MINUTE = self::TICKS_PER_SECOND * 60;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected const TICKS_PER_HOUR = self::TICKS_PER_MINUTE * 60;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected const TICKS_PER_DAY = self::TICKS_PER_HOUR * 24;
|
||||
|
||||
/**
|
||||
* Default format to use for __toString method.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const DEFAULT_TO_STRING_FORMAT = 'H:i:s';
|
||||
|
||||
/**
|
||||
* Format to use for __toString method.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static string $toStringFormat = self::DEFAULT_TO_STRING_FORMAT;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected int $ticks;
|
||||
|
||||
/**
|
||||
* Copies time from onther instance or from time string in the format HH[:.]mm or HH[:.]mm[:.]ss.u.
|
||||
*
|
||||
* Defaults to server time.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosTime|\DateTimeInterface|string|null $time Time
|
||||
* @param \DateTimeZone|string|null $timezone The timezone to use for now
|
||||
*/
|
||||
public function __construct(
|
||||
ChronosTime|DateTimeInterface|string|null $time = null,
|
||||
DateTimeZone|string|null $timezone = null,
|
||||
) {
|
||||
if ($time === null) {
|
||||
$time = Chronos::getTestNow() ?? Chronos::now();
|
||||
if ($timezone !== null) {
|
||||
$time = $time->setTimezone($timezone);
|
||||
}
|
||||
$this->ticks = static::parseString($time->format('H:i:s.u'));
|
||||
} elseif (is_string($time)) {
|
||||
$this->ticks = static::parseString($time);
|
||||
} elseif ($time instanceof ChronosTime) {
|
||||
$this->ticks = $time->ticks;
|
||||
} else {
|
||||
$this->ticks = static::parseString($time->format('H:i:s.u'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies time from onther instance or from string in the format HH[:.]mm or HH[:.]mm[:.]ss.u
|
||||
*
|
||||
* Defaults to server time.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosTime|\DateTimeInterface|string $time Time
|
||||
* @param \DateTimeZone|string|null $timezone The timezone to use for now
|
||||
* @return static
|
||||
*/
|
||||
public static function parse(
|
||||
ChronosTime|DateTimeInterface|string|null $time = null,
|
||||
DateTimeZone|string|null $timezone = null,
|
||||
): static {
|
||||
return new static($time, $timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $time Time string in the format HH[:.]mm or HH[:.]mm[:.]ss.u
|
||||
* @return int
|
||||
*/
|
||||
protected static function parseString(string $time): int
|
||||
{
|
||||
if (!preg_match('/^\s*(\d{1,2})[:.](\d{1,2})(?|[:.](\d{1,2})[.](\d+)|[:.](\d{1,2}))?\s*$/', $time, $matches)) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('Time string `%s` is not in expected format `HH[:.]mm` or `HH[:.]mm[:.]ss.u`.', $time),
|
||||
);
|
||||
}
|
||||
|
||||
$hours = (int)$matches[1];
|
||||
$minutes = (int)$matches[2];
|
||||
$seconds = (int)($matches[3] ?? 0);
|
||||
$microseconds = (int)substr($matches[4] ?? '', 0, 6);
|
||||
|
||||
if ($hours > 24 || $minutes > 59 || $seconds > 59 || $microseconds > 999_999) {
|
||||
throw new InvalidArgumentException(sprintf('Time string `%s` contains invalid values.', $time));
|
||||
}
|
||||
|
||||
$ticks = $hours * self::TICKS_PER_HOUR;
|
||||
$ticks += $minutes * self::TICKS_PER_MINUTE;
|
||||
$ticks += $seconds * self::TICKS_PER_SECOND;
|
||||
$ticks += $microseconds * self::TICKS_PER_MICROSECOND;
|
||||
|
||||
return $ticks % self::TICKS_PER_DAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns instance set to server time.
|
||||
*
|
||||
* @param \DateTimeZone|string|null $timezone The timezone to use for now
|
||||
* @return static
|
||||
*/
|
||||
public static function now(DateTimeZone|string|null $timezone = null): static
|
||||
{
|
||||
return new static(null, $timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns instance set to midnight.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function midnight(): static
|
||||
{
|
||||
return new static('00:00:00');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns instance set to noon.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function noon(): static
|
||||
{
|
||||
return new static('12:00:00');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns instance set to end of day - either
|
||||
* 23:59:59 or 23:59:59.999999 if `$microseconds` is true
|
||||
*
|
||||
* @param bool $microseconds Whether to set microseconds or not
|
||||
* @return static
|
||||
*/
|
||||
public static function endOfDay(bool $microseconds = false): static
|
||||
{
|
||||
if ($microseconds) {
|
||||
return new static('23:59:59.999999');
|
||||
}
|
||||
|
||||
return new static('23:59:59');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns clock microseconds.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMicroseconds(): int
|
||||
{
|
||||
return intdiv($this->ticks % self::TICKS_PER_SECOND, self::TICKS_PER_MICROSECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets clock microseconds.
|
||||
*
|
||||
* @param int $microseconds Clock microseconds
|
||||
* @return static
|
||||
*/
|
||||
public function setMicroseconds(int $microseconds): static
|
||||
{
|
||||
$baseTicks = $this->ticks - $this->ticks % self::TICKS_PER_SECOND;
|
||||
$newTicks = static::mod($baseTicks + $microseconds * self::TICKS_PER_MICROSECOND, self::TICKS_PER_DAY);
|
||||
|
||||
$clone = clone $this;
|
||||
$clone->ticks = $newTicks;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return clock seconds.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSeconds(): int
|
||||
{
|
||||
$secondsTicks = $this->ticks % self::TICKS_PER_MINUTE - $this->ticks % self::TICKS_PER_SECOND;
|
||||
|
||||
return intdiv($secondsTicks, self::TICKS_PER_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set clock seconds.
|
||||
*
|
||||
* @param int $seconds Clock seconds
|
||||
* @return static
|
||||
*/
|
||||
public function setSeconds(int $seconds): static
|
||||
{
|
||||
$baseTicks = $this->ticks - ($this->ticks % self::TICKS_PER_MINUTE - $this->ticks % self::TICKS_PER_SECOND);
|
||||
$newTicks = static::mod($baseTicks + $seconds * self::TICKS_PER_SECOND, self::TICKS_PER_DAY);
|
||||
|
||||
$clone = clone $this;
|
||||
$clone->ticks = $newTicks;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns clock minutes.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMinutes(): int
|
||||
{
|
||||
$minutesTicks = $this->ticks % self::TICKS_PER_HOUR - $this->ticks % self::TICKS_PER_MINUTE;
|
||||
|
||||
return intdiv($minutesTicks, self::TICKS_PER_MINUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set clock minutes.
|
||||
*
|
||||
* @param int $minutes Clock minutes
|
||||
* @return static
|
||||
*/
|
||||
public function setMinutes(int $minutes): static
|
||||
{
|
||||
$baseTicks = $this->ticks - ($this->ticks % self::TICKS_PER_HOUR - $this->ticks % self::TICKS_PER_MINUTE);
|
||||
$newTicks = static::mod($baseTicks + $minutes * self::TICKS_PER_MINUTE, self::TICKS_PER_DAY);
|
||||
|
||||
$clone = clone $this;
|
||||
$clone->ticks = $newTicks;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns clock hours.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHours(): int
|
||||
{
|
||||
$hoursInTicks = $this->ticks - $this->ticks % self::TICKS_PER_HOUR;
|
||||
|
||||
return intdiv($hoursInTicks, self::TICKS_PER_HOUR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set clock hours.
|
||||
*
|
||||
* @param int $hours Clock hours
|
||||
* @return static
|
||||
*/
|
||||
public function setHours(int $hours): static
|
||||
{
|
||||
$baseTicks = $this->ticks - ($this->ticks - $this->ticks % self::TICKS_PER_HOUR);
|
||||
$newTicks = static::mod($baseTicks + $hours * self::TICKS_PER_HOUR, self::TICKS_PER_DAY);
|
||||
|
||||
$clone = clone $this;
|
||||
$clone->ticks = $newTicks;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets clock time.
|
||||
*
|
||||
* @param int $hours Clock hours
|
||||
* @param int $minutes Clock minutes
|
||||
* @param int $seconds Clock seconds
|
||||
* @param int $microseconds Clock microseconds
|
||||
* @return static
|
||||
*/
|
||||
public function setTime(int $hours = 0, int $minutes = 0, int $seconds = 0, int $microseconds = 0): static
|
||||
{
|
||||
$ticks = $hours * self::TICKS_PER_HOUR +
|
||||
$minutes * self::TICKS_PER_MINUTE +
|
||||
$seconds * self::TICKS_PER_SECOND +
|
||||
$microseconds * self::TICKS_PER_MICROSECOND;
|
||||
$ticks = static::mod($ticks, self::TICKS_PER_DAY);
|
||||
|
||||
$clone = clone $this;
|
||||
$clone->ticks = $ticks;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $a Left side
|
||||
* @param int $a Right side
|
||||
* @return int
|
||||
*/
|
||||
protected static function mod(int $a, int $b): int
|
||||
{
|
||||
if ($a < 0) {
|
||||
return $a % $b + $b;
|
||||
}
|
||||
|
||||
return $a % $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats string using the same syntax as `DateTimeImmutable::format()`.
|
||||
*
|
||||
* As this uses DateTimeImmutable::format() to format the string, non-time formatters
|
||||
* will still be interpreted. Be sure to escape those characters first.
|
||||
*
|
||||
* @param string $format Format string
|
||||
* @return string
|
||||
*/
|
||||
public function format(string $format): string
|
||||
{
|
||||
return $this->toDateTimeImmutable()->format($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the format used to the default when converting to a string
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function resetToStringFormat(): void
|
||||
{
|
||||
static::setToStringFormat(static::DEFAULT_TO_STRING_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default format used when converting to a string
|
||||
*
|
||||
* @param string $format The format to use in future __toString() calls.
|
||||
* @return void
|
||||
*/
|
||||
public static function setToStringFormat(string $format): void
|
||||
{
|
||||
static::$toStringFormat = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as a string using the set format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->format(static::$toStringFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether time is equal to target time.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosTime $target Target time
|
||||
* @return bool
|
||||
*/
|
||||
public function equals(ChronosTime $target): bool
|
||||
{
|
||||
return $this->ticks === $target->ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether time is greater than target time.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosTime $target Target time
|
||||
* @return bool
|
||||
*/
|
||||
public function greaterThan(ChronosTime $target): bool
|
||||
{
|
||||
return $this->ticks > $target->ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether time is greater than or equal to target time.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosTime $target Target time
|
||||
* @return bool
|
||||
*/
|
||||
public function greaterThanOrEquals(ChronosTime $target): bool
|
||||
{
|
||||
return $this->ticks >= $target->ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether time is less than target time.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosTime $target Target time
|
||||
* @return bool
|
||||
*/
|
||||
public function lessThan(ChronosTime $target): bool
|
||||
{
|
||||
return $this->ticks < $target->ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether time is less than or equal to target time.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosTime $target Target time
|
||||
* @return bool
|
||||
*/
|
||||
public function lessThanOrEquals(ChronosTime $target): bool
|
||||
{
|
||||
return $this->ticks <= $target->ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether time is between time range.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosTime $start Start of target range
|
||||
* @param \Cake\Chronos\ChronosTime $end End of target range
|
||||
* @param bool $equals Whether to include the beginning and end of range
|
||||
* @return bool
|
||||
*/
|
||||
public function between(ChronosTime $start, ChronosTime $end, bool $equals = true): bool
|
||||
{
|
||||
if ($start->greaterThan($end)) {
|
||||
[$start, $end] = [$end, $start];
|
||||
}
|
||||
|
||||
if ($equals) {
|
||||
return $this->greaterThanOrEquals($start) && $this->lessThanOrEquals($end);
|
||||
}
|
||||
|
||||
return $this->greaterThan($start) && $this->lessThan($end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an `DateTimeImmutable` instance set to this clock time.
|
||||
*
|
||||
* @param \DateTimeZone|string|null $timezone Time zone the DateTimeImmutable instance will be in
|
||||
* @return \DateTimeImmutable
|
||||
*/
|
||||
public function toDateTimeImmutable(DateTimeZone|string|null $timezone = null): DateTimeImmutable
|
||||
{
|
||||
$timezone = is_string($timezone) ? new DateTimeZone($timezone) : $timezone;
|
||||
|
||||
return (new DateTimeImmutable(timezone: $timezone))->setTime(
|
||||
$this->getHours(),
|
||||
$this->getMinutes(),
|
||||
$this->getSeconds(),
|
||||
$this->getMicroseconds(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an `DateTimeImmutable` instance set to this clock time.
|
||||
*
|
||||
* Alias of `toDateTimeImmutable()`.
|
||||
*
|
||||
* @param \DateTimeZone|string|null $timezone Time zone the DateTimeImmutable instance will be in
|
||||
* @return \DateTimeImmutable
|
||||
*/
|
||||
public function toNative(DateTimeZone|string|null $timezone = null): DateTimeImmutable
|
||||
{
|
||||
return $this->toDateTimeImmutable($timezone);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Cake\Chronos;
|
||||
|
||||
/**
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
/**
|
||||
* PSR-20 Clock implementation.
|
||||
*/
|
||||
class ClockFactory implements ClockInterface
|
||||
{
|
||||
private DateTimeZone|string|null $timezone;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \DateTimeZone|string|null $timezone The timezone
|
||||
*/
|
||||
public function __construct(DateTimeZone|string|null $timezone = null)
|
||||
{
|
||||
$this->timezone = $timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time object.
|
||||
*
|
||||
* @return \Cake\Chronos\Chronos The current time
|
||||
*/
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return Chronos::now($this->timezone);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @copyright Copyright (c) Brian Nesbitt <brian@nesbot.com>
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Chronos;
|
||||
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* Handles formatting differences in text.
|
||||
*
|
||||
* Provides a swappable component for other libraries to leverage.
|
||||
* when localizing or customizing the difference output.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DifferenceFormatter implements DifferenceFormatterInterface
|
||||
{
|
||||
/**
|
||||
* The text translator object
|
||||
*
|
||||
* @var \Cake\Chronos\Translator
|
||||
*/
|
||||
protected Translator $translate;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Cake\Chronos\Translator|null $translate The text translator object.
|
||||
*/
|
||||
public function __construct(?Translator $translate = null)
|
||||
{
|
||||
$this->translate = $translate ?: new Translator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function diffForHumans(
|
||||
ChronosDate|DateTimeInterface $first,
|
||||
ChronosDate|DateTimeInterface|null $second = null,
|
||||
bool $absolute = false,
|
||||
): string {
|
||||
$isNow = $second === null;
|
||||
if ($second === null) {
|
||||
if ($first instanceof ChronosDate) {
|
||||
$second = new ChronosDate(Chronos::now());
|
||||
} else {
|
||||
$second = Chronos::now($first->getTimezone());
|
||||
}
|
||||
}
|
||||
assert(
|
||||
($first instanceof ChronosDate && $second instanceof ChronosDate) ||
|
||||
($first instanceof DateTimeInterface && $second instanceof DateTimeInterface),
|
||||
);
|
||||
|
||||
$diffInterval = $first->diff($second);
|
||||
|
||||
switch (true) {
|
||||
case $diffInterval->y > 0:
|
||||
$unit = 'year';
|
||||
$count = $diffInterval->y;
|
||||
break;
|
||||
case $diffInterval->m >= 2:
|
||||
$unit = 'month';
|
||||
$count = $diffInterval->m;
|
||||
break;
|
||||
case $diffInterval->days >= Chronos::DAYS_PER_WEEK * 3:
|
||||
$unit = 'week';
|
||||
$count = (int)($diffInterval->days / Chronos::DAYS_PER_WEEK);
|
||||
break;
|
||||
case $diffInterval->d > 0:
|
||||
$unit = 'day';
|
||||
$count = $diffInterval->d;
|
||||
break;
|
||||
case $diffInterval->h > 0:
|
||||
$unit = 'hour';
|
||||
$count = $diffInterval->h;
|
||||
break;
|
||||
case $diffInterval->i > 0:
|
||||
$unit = 'minute';
|
||||
$count = $diffInterval->i;
|
||||
break;
|
||||
default:
|
||||
$count = $diffInterval->s;
|
||||
$unit = 'second';
|
||||
break;
|
||||
}
|
||||
$time = $this->translate->plural($unit, $count, ['count' => $count]);
|
||||
if ($absolute) {
|
||||
return $time;
|
||||
}
|
||||
$isFuture = $diffInterval->invert === 1;
|
||||
$transId = $isNow ? ($isFuture ? 'from_now' : 'ago') : ($isFuture ? 'after' : 'before');
|
||||
|
||||
// Some langs have special pluralization for past and future tense.
|
||||
$tryKeyExists = $unit . '_' . $transId;
|
||||
if ($this->translate->exists($tryKeyExists)) {
|
||||
$time = $this->translate->plural($tryKeyExists, $count, ['count' => $count]);
|
||||
}
|
||||
|
||||
return $this->translate->singular($transId, ['time' => $time]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Chronos;
|
||||
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* Interface for formatting differences in text.
|
||||
*/
|
||||
interface DifferenceFormatterInterface
|
||||
{
|
||||
/**
|
||||
* Get the difference in a human readable format.
|
||||
*
|
||||
* @param \Cake\Chronos\ChronosDate|\DateTimeInterface $first The datetime to start with.
|
||||
* @param \Cake\Chronos\ChronosDate|\DateTimeInterface|null $second The datetime to compare against.
|
||||
* @param bool $absolute removes time difference modifiers ago, after, etc
|
||||
* @return string The difference between the two days in a human readable format
|
||||
*/
|
||||
public function diffForHumans(
|
||||
ChronosDate|DateTimeInterface $first,
|
||||
ChronosDate|DateTimeInterface|null $second = null,
|
||||
bool $absolute = false,
|
||||
): string;
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @copyright Copyright (c) Brian Nesbitt <brian@nesbot.com>
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Chronos;
|
||||
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* Provides string formatting methods for datetime instances.
|
||||
*
|
||||
* Expects implementing classes to define static::$toStringFormat
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait FormattingTrait
|
||||
{
|
||||
/**
|
||||
* Resets the __toString() format to ``DEFAULT_TO_STRING_FORMAT``.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function resetToStringFormat(): void
|
||||
{
|
||||
static::setToStringFormat(static::DEFAULT_TO_STRING_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the __toString() format.
|
||||
*
|
||||
* @param string $format See ``format()`` for accepted specifiers.
|
||||
* @return void
|
||||
*/
|
||||
public static function setToStringFormat(string $format): void
|
||||
{
|
||||
static::$toStringFormat = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted string specified by ``setToStringFormat()``
|
||||
* or the default ``DEFAULT_TO_STRING_FORMAT`` format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->format(static::$toStringFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as date
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toDateString(): string
|
||||
{
|
||||
return $this->format('Y-m-d');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as a readable date
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toFormattedDateString(): string
|
||||
{
|
||||
return $this->format('M j, Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as time
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toTimeString(): string
|
||||
{
|
||||
return $this->format('H:i:s');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as date and time
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toDateTimeString(): string
|
||||
{
|
||||
return $this->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance with day, date and time
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toDayDateTimeString(): string
|
||||
{
|
||||
return $this->format('D, M j, Y g:i A');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as ATOM
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toAtomString(): string
|
||||
{
|
||||
return $this->format(DateTime::ATOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as COOKIE
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toCookieString(): string
|
||||
{
|
||||
return $this->format(DateTime::COOKIE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as ISO8601
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toIso8601String(): string
|
||||
{
|
||||
return $this->format(DateTime::ATOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as RFC822
|
||||
*
|
||||
* @return string
|
||||
* @link https://tools.ietf.org/html/rfc822
|
||||
*/
|
||||
public function toRfc822String(): string
|
||||
{
|
||||
return $this->format(DateTime::RFC822);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as RFC850
|
||||
*
|
||||
* @return string
|
||||
* @link https://tools.ietf.org/html/rfc850
|
||||
*/
|
||||
public function toRfc850String(): string
|
||||
{
|
||||
return $this->format(DateTime::RFC850);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as RFC1036
|
||||
*
|
||||
* @return string
|
||||
* @link https://tools.ietf.org/html/rfc1036
|
||||
*/
|
||||
public function toRfc1036String(): string
|
||||
{
|
||||
return $this->format(DateTime::RFC1036);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as RFC1123
|
||||
*
|
||||
* @return string
|
||||
* @link https://tools.ietf.org/html/rfc1123
|
||||
*/
|
||||
public function toRfc1123String(): string
|
||||
{
|
||||
return $this->format(DateTime::RFC1123);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as RFC2822
|
||||
*
|
||||
* @return string
|
||||
* @link https://tools.ietf.org/html/rfc2822
|
||||
*/
|
||||
public function toRfc2822String(): string
|
||||
{
|
||||
return $this->format(DateTime::RFC2822);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as RFC3339
|
||||
*
|
||||
* @return string
|
||||
* @link https://tools.ietf.org/html/rfc3339
|
||||
*/
|
||||
public function toRfc3339String(): string
|
||||
{
|
||||
return $this->format(DateTime::RFC3339);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as RSS
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toRssString(): string
|
||||
{
|
||||
return $this->format(DateTime::RSS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the instance as W3C
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toW3cString(): string
|
||||
{
|
||||
return $this->format(DateTime::W3C);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a UNIX timestamp.
|
||||
*
|
||||
* @return string UNIX timestamp
|
||||
*/
|
||||
public function toUnixString(): string
|
||||
{
|
||||
return $this->format('U');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quarter
|
||||
*
|
||||
* Deprecated 3.3.0: The $range parameter is deprecated. Use toQuarterRange() for quarter ranges.
|
||||
*
|
||||
* @param bool $range Range.
|
||||
* @return array|int 1, 2, 3, or 4 quarter of year or array if $range true
|
||||
*/
|
||||
public function toQuarter(bool $range = false): int|array
|
||||
{
|
||||
$quarter = (int)ceil((int)$this->format('m') / 3);
|
||||
if ($range === false) {
|
||||
return $quarter;
|
||||
}
|
||||
|
||||
trigger_error(
|
||||
'Using toQuarter() with `$range=true` is deprecated. Use `toQuarterRange()` instead.',
|
||||
E_USER_DEPRECATED,
|
||||
);
|
||||
|
||||
return $this->toQuarterRange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quarter range
|
||||
*
|
||||
* @return array{0: string, 1: string} Array with start and end date of quarter in Y-m-d format
|
||||
*/
|
||||
public function toQuarterRange(): array
|
||||
{
|
||||
/** @var int<1, 4> $quarter */
|
||||
$quarter = (int)ceil((int)$this->format('m') / 3);
|
||||
$year = $this->format('Y');
|
||||
|
||||
return match ($quarter) {
|
||||
1 => [$year . '-01-01', $year . '-03-31'],
|
||||
2 => [$year . '-04-01', $year . '-06-30'],
|
||||
3 => [$year . '-07-01', $year . '-09-30'],
|
||||
4 => [$year . '-10-01', $year . '-12-31'],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ISO 8601 week number of year, weeks starting on Monday
|
||||
*
|
||||
* @return int ISO 8601 week number of year
|
||||
*/
|
||||
public function toWeek(): int
|
||||
{
|
||||
return (int)$this->format('W');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Chronos;
|
||||
|
||||
/**
|
||||
* Basic english only 'translator' for diffForHumans()
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Translator
|
||||
{
|
||||
/**
|
||||
* Translation strings.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static array $strings = [
|
||||
'year' => '1 year',
|
||||
'year_plural' => '{count} years',
|
||||
'month' => '1 month',
|
||||
'month_plural' => '{count} months',
|
||||
'week' => '1 week',
|
||||
'week_plural' => '{count} weeks',
|
||||
'day' => '1 day',
|
||||
'day_plural' => '{count} days',
|
||||
'hour' => '1 hour',
|
||||
'hour_plural' => '{count} hours',
|
||||
'minute' => '1 minute',
|
||||
'minute_plural' => '{count} minutes',
|
||||
'second' => '1 second',
|
||||
'second_plural' => '{count} seconds',
|
||||
'ago' => '{time} ago',
|
||||
'from_now' => '{time} from now',
|
||||
'after' => '{time} after',
|
||||
'before' => '{time} before',
|
||||
];
|
||||
|
||||
/**
|
||||
* Check if a translation key exists.
|
||||
*
|
||||
* @param string $key The key to check.
|
||||
* @return bool Whether the key exists.
|
||||
*/
|
||||
public function exists(string $key): bool
|
||||
{
|
||||
return isset(static::$strings[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a plural message.
|
||||
*
|
||||
* @param string $key The key to use.
|
||||
* @param int $count The number of items in the translation.
|
||||
* @param array $vars Additional context variables.
|
||||
* @return string The translated message or ''.
|
||||
*/
|
||||
public function plural(string $key, int $count, array $vars = []): string
|
||||
{
|
||||
if ($count === 1) {
|
||||
return $this->singular($key, $vars);
|
||||
}
|
||||
|
||||
return $this->singular($key . '_plural', ['count' => $count] + $vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a singular message.
|
||||
*
|
||||
* @param string $key The key to use.
|
||||
* @param array $vars Additional context variables.
|
||||
* @return string The translated message or ''.
|
||||
*/
|
||||
public function singular(string $key, array $vars = []): string
|
||||
{
|
||||
if (isset(static::$strings[$key])) {
|
||||
$varKeys = array_keys($vars);
|
||||
foreach ($varKeys as $i => $k) {
|
||||
$varKeys[$i] = '{' . $k . '}';
|
||||
}
|
||||
|
||||
return str_replace($varKeys, $vars, static::$strings[$key]);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user