xref: /dokuwiki/vendor/php81_bc/strftime/src/IntlLocaleFormatter.php (revision db9267247e06d4aae1a33463c71b2c22d7f7a2a7)
1*db926724SAndreas Gohr<?php
2*db926724SAndreas Gohr
3*db926724SAndreas Gohrnamespace PHP81_BC\strftime;
4*db926724SAndreas Gohr
5*db926724SAndreas Gohruse DateTimeInterface;
6*db926724SAndreas Gohruse IntlDateFormatter;
7*db926724SAndreas Gohruse IntlGregorianCalendar;
8*db926724SAndreas Gohr
9*db926724SAndreas Gohr/**
10*db926724SAndreas Gohr * This formatter uses the IntlDateFormatter class to do proper, locale aware formatting
11*db926724SAndreas Gohr */
12*db926724SAndreas Gohrclass IntlLocaleFormatter extends AbstractLocaleFormatter
13*db926724SAndreas Gohr{
14*db926724SAndreas Gohr
15*db926724SAndreas Gohr  /** @var string[] strftime to ICU placeholders */
16*db926724SAndreas Gohr  protected $formats = [
17*db926724SAndreas Gohr    '%a' => 'EEE',  // An abbreviated textual representation of the day	Sun through Sat
18*db926724SAndreas Gohr    '%A' => 'EEEE',  // A full textual representation of the day	Sunday through Saturday
19*db926724SAndreas Gohr    '%b' => 'MMM',  // Abbreviated month name, based on the locale	Jan through Dec
20*db926724SAndreas Gohr    '%B' => 'MMMM',  // Full month name, based on the locale	January through December
21*db926724SAndreas Gohr    '%h' => 'MMM',  // Abbreviated month name, based on the locale (an alias of %b)	Jan through Dec
22*db926724SAndreas Gohr  ];
23*db926724SAndreas Gohr
24*db926724SAndreas Gohr  /** @inheritdoc */
25*db926724SAndreas Gohr  public function __invoke(DateTimeInterface $timestamp, string $format)
26*db926724SAndreas Gohr  {
27*db926724SAndreas Gohr    $tz = $timestamp->getTimezone();
28*db926724SAndreas Gohr    $date_type = IntlDateFormatter::FULL;
29*db926724SAndreas Gohr    $time_type = IntlDateFormatter::FULL;
30*db926724SAndreas Gohr    $pattern = '';
31*db926724SAndreas Gohr
32*db926724SAndreas Gohr    switch ($format) {
33*db926724SAndreas Gohr      // %c = Preferred date and time stamp based on locale
34*db926724SAndreas Gohr      // Example: Tue Feb 5 00:45:10 2009 for February 5, 2009 at 12:45:10 AM
35*db926724SAndreas Gohr      case '%c':
36*db926724SAndreas Gohr        $date_type = IntlDateFormatter::LONG;
37*db926724SAndreas Gohr        $time_type = IntlDateFormatter::SHORT;
38*db926724SAndreas Gohr        break;
39*db926724SAndreas Gohr
40*db926724SAndreas Gohr      // %x = Preferred date representation based on locale, without the time
41*db926724SAndreas Gohr      // Example: 02/05/09 for February 5, 2009
42*db926724SAndreas Gohr      case '%x':
43*db926724SAndreas Gohr        $date_type = IntlDateFormatter::SHORT;
44*db926724SAndreas Gohr        $time_type = IntlDateFormatter::NONE;
45*db926724SAndreas Gohr        break;
46*db926724SAndreas Gohr
47*db926724SAndreas Gohr      // Localized time format
48*db926724SAndreas Gohr      case '%X':
49*db926724SAndreas Gohr        $date_type = IntlDateFormatter::NONE;
50*db926724SAndreas Gohr        $time_type = IntlDateFormatter::MEDIUM;
51*db926724SAndreas Gohr        break;
52*db926724SAndreas Gohr
53*db926724SAndreas Gohr      default:
54*db926724SAndreas Gohr        if (!isset($this->formats[$format])) {
55*db926724SAndreas Gohr          throw new \RuntimeException("'$format' is not a supported locale placeholder");
56*db926724SAndreas Gohr        }
57*db926724SAndreas Gohr        $pattern = $this->formats[$format];
58*db926724SAndreas Gohr    }
59*db926724SAndreas Gohr
60*db926724SAndreas Gohr    // In October 1582, the Gregorian calendar replaced the Julian in much of Europe, and
61*db926724SAndreas Gohr    //  the 4th October was followed by the 15th October.
62*db926724SAndreas Gohr    // ICU (including IntlDateFormattter) interprets and formats dates based on this cutover.
63*db926724SAndreas Gohr    // Posix (including strftime) and timelib (including DateTimeImmutable) instead use
64*db926724SAndreas Gohr    //  a "proleptic Gregorian calendar" - they pretend the Gregorian calendar has existed forever.
65*db926724SAndreas Gohr    // This leads to the same instants in time, as expressed in Unix time, having different representations
66*db926724SAndreas Gohr    //  in formatted strings.
67*db926724SAndreas Gohr    // To adjust for this, a custom calendar can be supplied with a cutover date arbitrarily far in the past.
68*db926724SAndreas Gohr    $calendar = IntlGregorianCalendar::createInstance();
69*db926724SAndreas Gohr    // NOTE: IntlGregorianCalendar::createInstance DOES NOT return an IntlGregorianCalendar instance when
70*db926724SAndreas Gohr    // using a non-Gregorian locale (e.g. fa_IR)! In that case, setGregorianChange will not exist.
71*db926724SAndreas Gohr    if (method_exists($calendar, 'setGregorianChange')) $calendar->setGregorianChange(PHP_INT_MIN);
72*db926724SAndreas Gohr
73*db926724SAndreas Gohr    return (new IntlDateFormatter($this->locale, $date_type, $time_type, $tz, $calendar, $pattern))->format($timestamp);
74*db926724SAndreas Gohr  }
75*db926724SAndreas Gohr
76*db926724SAndreas Gohr}
77