Date & Time

  • class Cake\I18n\FrozenTime

If you need TimeHelper functionalities outside of a View,use the FrozenTime class:

  1. use Cake\I18n\FrozenTime;
  2.  
  3. class UsersController extends AppController
  4. {
  5. public function initialize(): void
  6. {
  7. parent::initialize();
  8. $this->loadComponent('Auth');
  9. }
  10.  
  11. public function afterLogin()
  12. {
  13. $time = new FrozenTime($this->Auth->user('date_of_birth'));
  14. if ($time->isToday()) {
  15. // Greet user with a happy birthday message
  16. $this->Flash->success(__('Happy birthday to you...'));
  17. }
  18. }
  19. }

Under the hood, CakePHP uses Chronosto power its FrozenTime utility. Anything you can do with Chronos andDateTime, you can do with FrozenTime and FrozenDate.

For more details on Chronos please see the API documentation.

Creating Time Instances

There are a few ways to create FrozenTime instances:

  1. use Cake\I18n\FrozenTime;
  2.  
  3. // Create from a string datetime.
  4. $time = FrozenTime::createFromFormat(
  5. 'Y-m-d H:i:s',
  6. $datetime,
  7. 'America/New_York'
  8. );
  9.  
  10. // Create from a timestamp
  11. $time = FrozenTime::createFromTimestamp($ts);
  12.  
  13. // Get the current time.
  14. $time = FrozenTime::now();
  15.  
  16. // Or just use 'new'
  17. $time = new FrozenTime('2014-01-10 11:11', 'America/New_York');
  18.  
  19. $time = new FrozenTime('2 hours ago');

The FrozenTime class constructor can take any parameter that the internal DateTimeImmutablePHP class can. When passing a number or numeric string, it will be interpretedas a UNIX timestamp.

In test cases you can mock out now() using setTestNow():

  1. // Fixate time.
  2. $now = new FrozenTime('2014-04-12 12:22:30');
  3. FrozenTime::setTestNow($now);
  4.  
  5. // Returns '2014-04-12 12:22:30'
  6. $now = FrozenTime::now();
  7.  
  8. // Returns '2014-04-12 12:22:30'
  9. $now = FrozenTime::parse('now');

Manipulation

Once created, you can manipulate FrozenTime instances using setter methods:

  1. $now = FrozenTime::now();
  2. $now->year(2013)
  3. ->month(10)
  4. ->day(31);

You can also use the methods provided by PHP’s built-in DateTime class:

  1. $now = $now->setDate(2013, 10, 31);

Dates can be modified through subtraction and addition of their components:

  1. $now = FrozenTime::now();
  2. $now = $now->subDays(5)
  3. ->addMonth(1);
  4.  
  5. // Using strtotime strings.
  6. $now = $now->modify('+5 days');

You can get the internal components of a date by accessing its properties:

  1. $now = FrozenTime::now();
  2. echo $now->year; // 2014
  3. echo $now->month; // 5
  4. echo $now->day; // 10
  5. echo $now->timezone; // America/New_York

Formatting

  • static Cake\I18n\FrozenTime::setJsonEncodeFormat($format)

This method sets the default format used when converting an object to json:

  1. Time::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss'); // For any mutable DateTime
  2. FrozenTime::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss'); // For any immutable DateTime
  3. Date::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss'); // For any mutable Date
  4. FrozenDate::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss'); // For any immutable Date

Note

This method must be called statically.

  • Cake\I18n\FrozenTime::i18nFormat($format = null, $timezone = null, $locale = null)

A very common thing to do with Time instances is to print out formatteddates. CakePHP makes this a snap:

  1. $now = Time::parse('2014-10-31');
  2.  
  3. // Prints a localized datetime stamp.
  4. echo $now;
  5.  
  6. // Outputs '10/31/14, 12:00 AM' for the en-US locale
  7. $now->i18nFormat();
  8.  
  9. // Use the full date and time format
  10. $now->i18nFormat(\IntlDateFormatter::FULL);
  11.  
  12. // Use full date but short time format
  13. $now->i18nFormat([\IntlDateFormatter::FULL, \IntlDateFormatter::SHORT]);
  14.  
  15. // Outputs '2014-10-31 00:00:00'
  16. $now->i18nFormat('yyyy-MM-dd HH:mm:ss');

It is possible to specify the desired format for the string to be displayed.You can either pass IntlDateFormatter constants as the firstargument of this function, or pass a full ICU date formatting string asspecified in the following resource:http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details.

You can also format dates with non-gregorian calendars:

  1. // Outputs 'Friday, Aban 9, 1393 AP at 12:00:00 AM GMT'
  2. $result = $now->i18nFormat(\IntlDateFormatter::FULL, null, 'en-IR@calendar=persian');

The following calendar types are supported:

  • japanese
  • buddhist
  • chinese
  • persian
  • indian
  • islamic
  • hebrew
  • coptic
  • ethiopic

Note

For constant strings i.e. IntlDateFormatter::FULL Intl uses ICU librarythat feeds its data from CLDR (http://cldr.unicode.org/) which versionmay vary depending on PHP installation and give different results.

  • Cake\I18n\FrozenTime::nice()

Print out a predefined ‘nice’ format:

  1. $now = Time::parse('2014-10-31');
  2.  
  3. // Outputs 'Oct 31, 2014 12:00 AM' in en-US
  4. echo $now->nice();

You can alter the timezone in which the date is displayed without altering theTime object itself. This is useful when you store dates in one timezone, butwant to display them in a user’s own timezone:

  1. $now->i18nFormat(\IntlDateFormatter::FULL, 'Europe/Paris');

Leaving the first parameter as null will use the default formatting string:

  1. $now->i18nFormat(null, 'Europe/Paris');

Finally, it is possible to use a different locale for displaying a date:

  1. echo $now->i18nFormat(\IntlDateFormatter::FULL, 'Europe/Paris', 'fr-FR');
  2.  
  3. echo $now->nice('Europe/Paris', 'fr-FR');

Setting the Default Locale and Format String

The default locale in which dates are displayed when using nicei18nFormat is taken from the directiveintl.default_locale.You can, however, modify this default at runtime:

  1. Time::setDefaultLocale('es-ES'); // For any mutable DateTime
  2. FrozenTime::setDefaultLocale('es-ES'); // For any immutable DateTime
  3. Date::setDefaultLocale('es-ES'); // For any mutable Date
  4. FrozenDate::setDefaultLocale('es-ES'); // For any immutable Date

From now on, datetimes will be displayed in the Spanish preferred format unlessa different locale is specified directly in the formatting method.

Likewise, it is possible to alter the default formatting string to be used fori18nFormat:

  1. Time::setToStringFormat(\IntlDateFormatter::SHORT); // For any mutable DateTime
  2. FrozenTime::setToStringFormat(\IntlDateFormatter::SHORT); // For any immutable DateTime
  3. Date::setToStringFormat(\IntlDateFormatter::SHORT); // For any mutable Date
  4. FrozenDate::setToStringFormat(\IntlDateFormatter::SHORT); // For any immutable Date
  5.  
  6. // The same method exists on Date, FrozenDate and FrozenTime
  7. Time::setToStringFormat([
  8. \IntlDateFormatter::FULL,
  9. \IntlDateFormatter::SHORT
  10. ]);
  11.  
  12. // The same method exists on Date, FrozenDate and FrozenTime
  13. Time::setToStringFormat('yyyy-MM-dd HH:mm:ss');

It is recommended to always use the constants instead of directly passing a dateformat string.

Formatting Relative Times

  • Cake\I18n\FrozenTime::timeAgoInWords(array $options = [])

Often it is useful to print times relative to the present:

  1. $now = new Time('Aug 22, 2011');
  2. echo $now->timeAgoInWords(
  3. ['format' => 'MMM d, YYY', 'end' => '+1 year']
  4. );
  5. // On Nov 10th, 2011 this would display: 2 months, 2 weeks, 6 days ago

The end option lets you define at which point after which relative timesshould be formatted using the format option. The accuracy option letsus control what level of detail should be used for each interval range:

  1. // If $timestamp is 1 month, 1 week, 5 days and 6 hours ago
  2. echo $timestamp->timeAgoInWords([
  3. 'accuracy' => ['month' => 'month'],
  4. 'end' => '1 year'
  5. ]);
  6. // Outputs '1 month ago'

By setting accuracy to a string, you can specify what is the maximum levelof detail you want output:

  1. $time = new Time('+23 hours');
  2. // Outputs 'in about a day'
  3. $result = $time->timeAgoInWords([
  4. 'accuracy' => 'day'
  5. ]);

Conversion

  • Cake\I18n\FrozenTime::toQuarter()

Once created, you can convert Time instances into timestamps or quartervalues:

  1. $time = new Time('2014-06-15');
  2. $time->toQuarter();
  3. $time->toUnixString();

Comparing With the Present

  • Cake\I18n\FrozenTime::isYesterday()
  • Cake\I18n\FrozenTime::isThisWeek()
  • Cake\I18n\FrozenTime::isThisMonth()
  • Cake\I18n\FrozenTime::isThisYear()

You can compare a Time instance with the present in a variety of ways:

  1. $time = new Time('2014-06-15');
  2.  
  3. echo $time->isYesterday();
  4. echo $time->isThisWeek();
  5. echo $time->isThisMonth();
  6. echo $time->isThisYear();

Each of the above methods will return true/false based on whether ornot the Time instance matches the present.

Comparing With Intervals

  • Cake\I18n\FrozenTime::isWithinNext($interval)

You can see if a Time instance falls within a given range usingwasWithinLast() and isWithinNext():

  1. $time = new Time('2014-06-15');
  2.  
  3. // Within 2 days.
  4. echo $time->isWithinNext(2);
  5.  
  6. // Within 2 next weeks.
  7. echo $time->isWithinNext('2 weeks');
  • Cake\I18n\FrozenTime::wasWithinLast($interval)

You can also compare a Time instance within a range in the past:

  1. // Within past 2 days.
  2. echo $time->wasWithinLast(2);
  3.  
  4. // Within past 2 weeks.
  5. echo $time->wasWithinLast('2 weeks');

Dates

The Date class in CakePHP implements the same API and methods asCake\I18n\Time does. The main difference between Time andDate is that Date does not track time components, and is always in UTC.As an example:

  1. use Cake\I18n\Date;
  2. $date = new Date('2015-06-15');
  3.  
  4. $date->modify('+2 hours');
  5. // Outputs 2015-06-15 00:00:00
  6. echo $date->format('Y-m-d H:i:s');
  7.  
  8. $date->modify('+36 hours');
  9. // Outputs 2015-06-15 00:00:00
  10. echo $date->format('Y-m-d H:i:s');

Attempts to modify the timezone on a Date instance are also ignored:

  1. use Cake\I18n\Date;
  2. $date = new Date('2015-06-15');
  3. $date->setTimezone(new \DateTimeZone('America/New_York'));
  4.  
  5. // Outputs UTC
  6. echo $date->format('e');

Immutable Dates and Times

  • class Cake\I18n\FrozenTime
  • class Cake\I18n\FrozenDate

CakePHP uses immutable date and time classes that implement the same interfaceas their mutable siblings. Immutable objects are useful when you want to preventaccidental changes to data, or when you want to avoid order based dependencyissues. Take the following code:

  1. use Cake\I18n\Time;
  2. $time = new Time('2015-06-15 08:23:45');
  3. $time->modify('+2 hours');
  4.  
  5. // This method also modifies the $time instancegg/
  6. $this->someOtherFunction($time);
  7.  
  8. // Output here is unknown.
  9. echo $time->format('Y-m-d H:i:s');

If the method call was re-ordered, or if someOtherFunction changed theoutput could be unexpected. The mutability of our object creates temporalcoupling. If we were to use immutable objects, we could avoid this issue:

  1. use Cake\I18n\FrozenTime;
  2. $time = new FrozenTime('2015-06-15 08:23:45');
  3. $time = $time->modify('+2 hours');
  4.  
  5. // This method's modifications don't change $time
  6. $this->someOtherFunction($time);
  7.  
  8. // Output here is known.
  9. echo $time->format('Y-m-d H:i:s');

Immutable dates and times are useful in entities as they preventaccidental modifications, and force changes to be explicit. Usingimmutable objects helps the ORM to more easily track changes, and ensure thatdate and datetime columns are persisted correctly:

  1. // This change will be lost when the article is saved.
  2. $article->updated->modify('+1 hour');
  3.  
  4. // By replacing the time object the property will be saved.
  5. $article->updated = $article->updated->modify('+1 hour');

Accepting Localized Request Data

When creating text inputs that manipulate dates, you’ll probably want to acceptand parse localized datetime strings. See the Parsing Localized Datetime Data.

Supported Timezones

CakePHP supports all valid PHP timezones. For a list of supported timezones, see this page.