Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat;
   4  
   5  use PhpOffice\PhpSpreadsheet\Shared\Date;
   6  
   7  class DateFormatter
   8  {
   9      /**
  10       * Search/replace values to convert Excel date/time format masks to PHP format masks.
  11       *
  12       * @var array
  13       */
  14      private static $dateFormatReplacements = [
  15          // first remove escapes related to non-format characters
  16          '\\' => '',
  17          //    12-hour suffix
  18          'am/pm' => 'A',
  19          //    4-digit year
  20          'e' => 'Y',
  21          'yyyy' => 'Y',
  22          //    2-digit year
  23          'yy' => 'y',
  24          //    first letter of month - no php equivalent
  25          'mmmmm' => 'M',
  26          //    full month name
  27          'mmmm' => 'F',
  28          //    short month name
  29          'mmm' => 'M',
  30          //    mm is minutes if time, but can also be month w/leading zero
  31          //    so we try to identify times be the inclusion of a : separator in the mask
  32          //    It isn't perfect, but the best way I know how
  33          ':mm' => ':i',
  34          'mm:' => 'i:',
  35          //    month leading zero
  36          'mm' => 'm',
  37          //    month no leading zero
  38          'm' => 'n',
  39          //    full day of week name
  40          'dddd' => 'l',
  41          //    short day of week name
  42          'ddd' => 'D',
  43          //    days leading zero
  44          'dd' => 'd',
  45          //    days no leading zero
  46          'd' => 'j',
  47          //    seconds
  48          'ss' => 's',
  49          //    fractional seconds - no php equivalent
  50          '.s' => '',
  51      ];
  52  
  53      /**
  54       * Search/replace values to convert Excel date/time format masks hours to PHP format masks (24 hr clock).
  55       *
  56       * @var array
  57       */
  58      private static $dateFormatReplacements24 = [
  59          'hh' => 'H',
  60          'h' => 'G',
  61      ];
  62  
  63      /**
  64       * Search/replace values to convert Excel date/time format masks hours to PHP format masks (12 hr clock).
  65       *
  66       * @var array
  67       */
  68      private static $dateFormatReplacements12 = [
  69          'hh' => 'h',
  70          'h' => 'g',
  71      ];
  72  
  73      public static function format($value, string $format): string
  74      {
  75          // strip off first part containing e.g. [$-F800] or [$USD-409]
  76          // general syntax: [$<Currency string>-<language info>]
  77          // language info is in hexadecimal
  78          // strip off chinese part like [DBNum1][$-804]
  79          $format = preg_replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format);
  80  
  81          // OpenOffice.org uses upper-case number formats, e.g. 'YYYY', convert to lower-case;
  82          //    but we don't want to change any quoted strings
  83          $format = preg_replace_callback('/(?:^|")([^"]*)(?:$|")/', ['self', 'setLowercaseCallback'], $format);
  84  
  85          // Only process the non-quoted blocks for date format characters
  86          $blocks = explode('"', $format);
  87          foreach ($blocks as $key => &$block) {
  88              if ($key % 2 == 0) {
  89                  $block = strtr($block, self::$dateFormatReplacements);
  90                  if (!strpos($block, 'A')) {
  91                      // 24-hour time format
  92                      // when [h]:mm format, the [h] should replace to the hours of the value * 24
  93                      if (false !== strpos($block, '[h]')) {
  94                          $hours = (int) ($value * 24);
  95                          $block = str_replace('[h]', $hours, $block);
  96  
  97                          continue;
  98                      }
  99                      $block = strtr($block, self::$dateFormatReplacements24);
 100                  } else {
 101                      // 12-hour time format
 102                      $block = strtr($block, self::$dateFormatReplacements12);
 103                  }
 104              }
 105          }
 106          $format = implode('"', $blocks);
 107  
 108          // escape any quoted characters so that DateTime format() will render them correctly
 109          $format = preg_replace_callback('/"(.*)"/U', ['self', 'escapeQuotesCallback'], $format);
 110  
 111          $dateObj = Date::excelToDateTimeObject($value);
 112          // If the colon preceding minute had been quoted, as happens in
 113          // Excel 2003 XML formats, m will not have been changed to i above.
 114          // Change it now.
 115          $format = \preg_replace('/\\\\:m/', ':i', $format);
 116  
 117          return $dateObj->format($format);
 118      }
 119  
 120      private static function setLowercaseCallback($matches): string
 121      {
 122          return mb_strtolower($matches[0]);
 123      }
 124  
 125      private static function escapeQuotesCallback($matches): string
 126      {
 127          return '\\' . implode('\\', str_split($matches[1]));
 128      }
 129  }