From f2fdd77dd6eaa6359e4142343e63f0d67df2c175 Mon Sep 17 00:00:00 2001
From: Stefan Leitner <sleitner@2466050.no-reply.drupal.org>
Date: Thu, 10 Apr 2025 21:46:46 +0200
Subject: [PATCH 1/9] UTC

---
 date_pager.module                         | 131 ++++++++--------------
 src/PagerDate.php                         | 118 ++++++++++++++++---
 src/Plugin/views/pager/DatePager.php      |  89 +++++----------
 tests/src/Functional/DatePagerUtcTest.php |   5 +-
 tests/src/Unit/PagerDateUtcUnitTest.php   |   7 ++
 5 files changed, 190 insertions(+), 160 deletions(-)

diff --git a/date_pager.module b/date_pager.module
index d2b71fe..0b9d2fe 100644
--- a/date_pager.module
+++ b/date_pager.module
@@ -68,11 +68,12 @@ function template_preprocess_datepager(&$variables) {
   $date_max = $parameters['max'];
 
   $active_date = $parameters['current'];
-  $current_year = date('Y', $active_date->toTime());
-  $current_month = date('m', $active_date->toTime());
-  $current_day = date('d', $active_date->toTime());
-  $current_hour = date('H', $active_date->toTime());
-  $current_minute = date('i', $active_date->toTime());
+  $current_date = [];
+  $current_date['year'] = date('Y', $active_date->toTime());
+  $current_date['month'] = date('m', $active_date->toTime());
+  $current_date['day'] = date('d', $active_date->toTime());
+  $current_date['hour'] = date('H', $active_date->toTime());
+  $current_date['minute'] = date('i', $active_date->toTime());
 
   $variables['pager'] = [
     '#type' => 'container',
@@ -93,17 +94,10 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    for ($sec = 0; $sec < 60; $sec++) {
-      $padded_second = str_pad($sec, 2, '0', STR_PAD_LEFT);
-      $date = "{$current_year}-{$current_month}-{$current_day}T{$current_hour}:{$current_minute}:{$padded_second}";
-      $pagerdate = new PagerDate($date, 'Y-m-d\TH:i:s');
-      if ($pagerdate->between($date_min, $date_max)) {
-        $seconds['items'][$padded_second] = $pagerdate->toLink($route_name, $active_date);
-      }
-    }
-    if ($variables['options']['date_sort']) {
-      $seconds['items'] = array_reverse($seconds['items'], TRUE);
-    }
+    $seconds = createGranularityDate($seconds, 0, 60, 'seconds', NULL, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:{$current_date['minute']}:", '', NULL, NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+  }
+  else {
+    $seconds = NULL;
   }
 
   // Minutes granularity.
@@ -118,20 +112,10 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    for ($minute = 0; $minute < 60; $minute++) {
-      $padded_minute = str_pad($minute, 2, '0', STR_PAD_LEFT);
-      $date = "{$current_year}-{$current_month}-{$current_day}T{$current_hour}:{$padded_minute}:00";
-      $pagerdate = new PagerDate($date, 'Y-m-d\TH:i');
-      if ($pagerdate->between($date_min, $date_max)) {
-        $minutes['items'][$padded_minute] = $pagerdate->toLink($route_name, $active_date);
-        if ($padded_minute == $current_minute && isset($seconds)) {
-          $minutes['items'][$padded_minute]['seconds'] = $seconds;
-        }
-      }
-    }
-    if ($variables['options']['date_sort']) {
-      $minutes['items'] = array_reverse($minutes['items'], TRUE);
-    }
+    $minutes = createGranularityDate($minutes, 0, 60, 'seconds', $seconds, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:", ':00', $current_date['minute'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+  }
+  else {
+    $minutes = NULL;
   }
 
   // Hours granularity.
@@ -146,22 +130,12 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    for ($hour = 0; $hour < 24; $hour++) {
-      $padded_hour = str_pad($hour, 2, '0', STR_PAD_LEFT);
-      $date = "{$current_year}-{$current_month}-{$current_day}T{$padded_hour}:00:00";
-      $pagerdate = new PagerDate($date, 'Y-m-d\TH');
-      if ($pagerdate->between($date_min, $date_max)) {
-        $hours['items'][$padded_hour] = $pagerdate->toLink($route_name, $active_date);
-        if ($padded_hour == $current_hour && isset($minutes)) {
-          $hours['items'][$padded_hour]['minutes'] = $minutes;
-        }
-      }
-    }
-    if ($variables['options']['date_sort']) {
-      $hours['items'] = array_reverse($hours['items'], TRUE);
-    }
+    $hours = createGranularityDate($hours, 0, 24, 'minutes', $minutes, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T", ":00:00", $current_date['hour'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
     $variables['pager']['time'] = $hours;
   }
+  else {
+    $hours = NULL;
+  }
 
   // Process day granularity.
   if ($granularity > 1) {
@@ -175,19 +149,10 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    for ($day = 1; $day < 32; $day++) {
-      if (checkdate(intval($current_month), $day, $current_year)) {
-        $padded_day = str_pad($day, 2, '0', STR_PAD_LEFT);
-        $date = "{$current_year}-{$current_month}-{$padded_day}";
-        $pagerdate = new PagerDate($date, 'Y-m-d');
-        if ($pagerdate->between($date_min, $date_max)) {
-          $days['items'][$padded_day] = $pagerdate->toLink($route_name, $active_date);
-        }
-      }
-    }
-    if ($variables['options']['date_sort']) {
-      $days['items'] = array_reverse($days['items'], TRUE);
-    }
+    $days = createGranularityDate($days, 1, 32, 'hours', $hours, "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'], ['year'=>$current_date['year'], 'month' => $current_date['month']],  $route_name, $active_date, $date_min, $date_max, $variables);
+  }
+  else {
+    $days = NULL;
   }
 
   // Process month granularity.
@@ -203,19 +168,10 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    for ($month = 1; $month < 13; $month++) {
-      $padded_month = str_pad($month, 2, '0', STR_PAD_LEFT);
-      $pagerdate = new PagerDate("{$current_year}-{$padded_month}", 'Y-m');
-      if ($pagerdate->between($date_min, $date_max)) {
-        $months['items'][$padded_month] = $pagerdate->toLink($route_name, $active_date);
-        if ($padded_month == $current_month && isset($days)) {
-          $months['items'][$padded_month]['days'] = $days;
-        }
-      }
-    }
-    if ($variables['options']['date_sort']) {
-      $months['items'] = array_reverse($months['items'], TRUE);
-    }
+    $months = createGranularityDate($months, 1, 13, 'days', $days, "{$current_date['year']}-", "", $current_date['month'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+  }
+  else {
+    $months = NULL;
   }
 
   // Construct Year Pager.
@@ -237,19 +193,7 @@ function template_preprocess_datepager(&$variables) {
       ],
     ],
   ];
-
-  for ($year = $start_year; $year <= $end_year; $year++) {
-    $pagerdate = new PagerDate("$year", 'Y');
-    if ($pagerdate->between($date_min, $date_max)) {
-      $years['items'][$year] = $pagerdate->toLink($route_name, $active_date);
-      if ($year == $current_year && isset($months)) {
-        $years['items'][$year]['months'] = $months;
-      }
-    }
-  }
-  if ($variables['options']['date_sort']) {
-    $years['items'] = array_reverse($years['items'], TRUE);
-  }
+  $years = createGranularityDate($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
 
   $variables['pager']['date'] = $years;
   $variables['pager']['#attached']['library'][] = 'date_pager/datepager';
@@ -258,3 +202,24 @@ function template_preprocess_datepager(&$variables) {
   // parameters matter.
   $variables['#cache']['contexts'][] = 'url.query_args';
 }
+
+function createGranularityDate($dateitem, $start, $stop, $subitemname, $subitem, $pre, $post, $current, $checkdate, $route_name, $active_date, $date_min, $date_max, $variables){
+  for ($dateiterator = $start; $dateiterator < $stop; $dateiterator++) {
+    if (is_array($checkdate) && !checkdate($checkdate['month'], $dateiterator, $checkdate['year'])) {
+      continue;
+    }
+    $padded_date = str_pad($dateiterator, 2, '0', STR_PAD_LEFT);
+    $date = $pre."{$padded_date}".$post;
+    $pagerdate = new PagerDate($date, NULL, TRUE);
+    if ($pagerdate->between($date_min, $date_max)) {
+      $dateitem['items'][$padded_date] = $pagerdate->toLink($route_name, $active_date);
+      if ($padded_date == $current && isset($subitem)) {
+        $dateitem['items'][$padded_date][$subitemname] = $subitem;
+      }
+    }
+  }
+  if ($variables['options']['date_sort']) {
+    $dateitem['items'] = array_reverse($dateitem['items'], TRUE);
+  }
+  return $dateitem;
+}
\ No newline at end of file
diff --git a/src/PagerDate.php b/src/PagerDate.php
index 286c10e..2f9131f 100644
--- a/src/PagerDate.php
+++ b/src/PagerDate.php
@@ -3,6 +3,7 @@
 namespace Drupal\date_pager;
 
 use Drupal\Core\Link;
+use Drupal\user\Entity\User;
 
 /**
  * Extends the DateTime PHP-Class.
@@ -28,38 +29,58 @@ class PagerDate extends \DateTime {
    */
   public $granularityId;
 
+  /**
+   * Date pattern for date interval.
+   *
+   * @var string[]
+   */
+  protected static $datePatterns = [
+    0 => 'Y-01-01\\T00:00:00',
+    1 => 'Y-m-01\\T00:00:00',
+    2 => 'Y-m-d\\T00:00:00',
+    3 => 'Y-m-d\\TH:00:00',
+    4 => 'Y-m-d\\TH:i:00',
+    5 => 'Y-m-d\\TH:i:s',
+  ];
+
+  /**
+   * Date interval word.
+   *
+   * @var string[]
+   */
+  protected static $granularityWord = [
+    0 => 'year',
+    1 => 'month',
+    2 => 'day',
+    3 => 'hour',
+    4 => 'minute',
+    5 => 'second',
+  ];
+
   /**
    * Constructs the PagerDate.
    *
    * @param string $time
    *   Any date string.
-   * @param string $granularity
+   * @param null|string $granularity
    *   Date format, eg. 'Y-m-d'.
+   * @param bool $withUserTimezone
+   *   Create with user timezone or UTC.
    */
-  public function __construct($time, $granularity = NULL) {
-
+  public function __construct($time, $granularity = NULL, $withUserTimezone = FALSE) {
+    $this->granularity = $granularity;
     // Sometimes the given parameter doesn't match the granularity wanted.
     // We need to adjust the granularity to the given value.
-    // Doesn't work with time string like 'NOW' etc, but doesn't have to.
+    // Doesn't work with timestring like 'NOW' etc, but doesn't have to.
     if (is_null($granularity)) {
       $this->granularity = $this->findGranularity($time);
     }
-    else {
-      $this->granularity = $granularity;
-    }
-
     $this->granularityId = $this->findGranularityId();
 
-    // We have to expand the time string, otherwise 2011 as a year
-    // wouldn't pe properly recognized.
-    // Also we don't want to use the current date
-    // as defaults for the missing parts.
-    $full_time_String = '2000-01-01T00:00:00';
-    if (strlen($full_time_String) > strlen($time)) {
-      $fill_up_time_string = substr($full_time_String, -(strlen($full_time_String) - strlen($time)));
-      $time .= $fill_up_time_string;
+    $time = self::fillUpTimestring($time);
+    if ($withUserTimezone) {
+      $time = str_replace('UTC', self::userTimezone(), $time);
     }
-
     parent::__construct($time);
   }
 
@@ -149,6 +170,69 @@ class PagerDate extends \DateTime {
     return (($this->toTime() >= $startdate->toTime($this->granularity)) && ($this->toTime() <= $enddate->toTime($this->granularity)));
   }
 
+  /**
+   * Start date depending on granularity.
+   *
+   * @param null|int $granularityId
+   *   Granularity.
+   *
+   * @return string
+   *   Start date string.
+   */
+  public function startDate($granularityId = NULL) {
+    $granularityId = $granularityId ?? $this->granularityId;
+    $startdate = clone $this;
+    return $startdate->format(self::$datePatterns[5]);
+  }
+
+  /**
+   * End date depending on granularity.
+   *
+   * @param null|int $granularityId
+   *   Granularity.
+   *
+   * @return string
+   *   End date string.
+   */
+  public function endDate($granularityId = NULL) {
+    $granularityId = $granularityId ?? $this->granularityId;
+    $enddate = clone $this;
+    return $enddate->modify('+1 ' . self::$granularityWord[$granularityId])->format(self::$datePatterns[5]);
+  }
+
+  /**
+   * Fills up time string.
+   *
+   * @param string $timestring
+   *   Time string.
+   * @param string $full_timestring
+   *   Full time string.
+   *
+   * @return string
+   *   new time string
+   */
+  public static function fillUpTimestring($timestring, $full_timestring = '2000-01-01T00:00:00 UTC') {
+    // We have to expand the timestring, otherwise 2000 as a year
+    // wouldn't be properly recognized.
+    // Also we don't want to use the current date
+    // as defaults for the missing parts.
+    if (strlen($full_timestring) > strlen($timestring)) {
+      $timestring .= substr($full_timestring, -(strlen($full_timestring) - strlen($timestring)));
+    }
+    return $timestring;
+  }
+
+  /**
+   * Timezone from user.
+   *
+   * @return string
+   *   Timezone name.
+   */
+  public static function userTimezone() {
+    $current_user = User::load(\Drupal::currentUser()->id());
+    return $current_user->getTimeZone();
+  }
+
   /**
    * Generates pager link object.
    *
diff --git a/src/Plugin/views/pager/DatePager.php b/src/Plugin/views/pager/DatePager.php
index be8bd4b..b7cc81e 100644
--- a/src/Plugin/views/pager/DatePager.php
+++ b/src/Plugin/views/pager/DatePager.php
@@ -35,7 +35,7 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
    *
    * @var string[]
    */
-  protected $supportedDateTypes = [
+  protected static $supportedDateTypes = [
     'changed',
     'created',
     'datetime',
@@ -43,6 +43,17 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
     'smartdate',
   ];
 
+  /**
+   * Unixtimestamp field types.
+   *
+   * @var string[]
+   */
+  protected static $unixtimestampTypes = [
+    'changed',
+    'created',
+    'smartdate',
+  ];
+
   /**
    * View's base entity.
    *
@@ -173,6 +184,7 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
       if ($field_storage) {
         $this->dateFieldType = $field_storage->getType();
         $this->startDateColumn = $columns['value'];
+        $this->endDateColumn = $columns['value'];
         if (isset($columns['end_value'])) {
           $this->endDateColumn = $columns['end_value'];
         }
@@ -284,7 +296,7 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
     $storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($base_entity_type_id);
 
     // List all possible fields.
-    foreach ($this->supportedDateTypes as $field_type) {
+    foreach (self::$supportedDateTypes as $field_type) {
       $field_map = $this->entityFieldManager->getFieldMapByFieldType($field_type);
       if (isset($field_map[$base_entity_type_id])) {
         foreach ($field_map[$base_entity_type_id] as $field_name => $field) {
@@ -331,18 +343,16 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
    */
   public function query() {
     $table_alias = $this->fieldTable;
-    $value_column = $this->startDateColumn;
-    $this->view->query->addField($table_alias, $value_column, $value_column);
-    if (!is_null($this->endDateColumn)) {
-      $end_column = $this->endDateColumn;
-      $this->view->query->addField($table_alias, $end_column, $end_column);
+    $this->view->query->addField($table_alias, $this->startDateColumn, $this->startDateColumn);
+    if ($this->endDateColumn !== $this->startDateColumn) {
+      $this->view->query->addField($table_alias, $this->endDateColumn, $this->endDateColumn);
     }
 
     // Checks if the date field is used, e.g. in a contextual filter.
     $found = FALSE;
     if (isset($this->view->query->where[0]['conditions'])) {
       foreach ($this->view->query->where[0]['conditions'] as &$condition) {
-        if ($condition['field'] == $value_column) {
+        if ($condition['field'] == $this->startDateColumn) {
           $condition['value'] = $this->activeDate . '%';
           $condition['operator'] = 'LIKE';
           $found = TRUE;
@@ -352,52 +362,16 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
 
     // If the date field is not already used, add a new where query.
     if (!$found) {
-      if ($this->dateFieldType === 'datetime') {
-        $this->view->query->addWhere(1, $value_column, $this->activeDate . '%', 'LIKE');
-      }
-      // If we have a (smart) date range field where start and end
-      // overlaps selected date.
-      else {
-        $timestamp = $this->activeDate->format('U');
-        switch ($this->options['granularity']) {
-          case 0:
-            $start_date = date('Y-01-01 00:00:00', $timestamp);
-            $end_date = date('Y-12-31 23:59:59', $timestamp);
-            break;
-
-          case 1:
-            $start_date = date('Y-m-01 00:00:00', $timestamp);
-            $end_date = date('Y-m-t 23:59:59', $timestamp);
-            break;
-
-          case 2:
-            $start_date = date('Y-m-d 00:00:00', $timestamp);
-            $end_date = date('Y-m-d 23:59:59', $timestamp);
-            break;
-
-          case 3:
-            $start_date = date('Y-m-d H:00:00', $timestamp);
-            $end_date = date('Y-m-d H:59:59', $timestamp);
-            break;
-
-          default:
-            $start_date = date('Y-m-d H:i:00', $timestamp);
-            $end_date = date('Y-m-d H:i:59', $timestamp);
-            break;
-        }
-        // With smartdate timestamps need to be converted to datetime.
-        if (in_array($this->dateFieldType, ['created', 'changed', 'smartdate'])) {
-          $start_date = strtotime($start_date);
-          $end_date = strtotime($end_date);
-        }
-        $this->view->query->addWhere(1, $value_column, $end_date, '<=');
-        if (in_array($this->dateFieldType, ['created', 'changed'])) {
-          $this->view->query->addWhere(1, $value_column, $start_date, '>=');
-        }
-        else {
-          $this->view->query->addWhere(1, $end_column, $start_date, '>=');
-        }
+      $localdate = clone $this->activeDate;
+      $start_date = $localdate->setTimezone(new \DateTimeZone('UTC'))->startDate($this->options['granularity']);
+      $end_date = $localdate->endDate($this->options['granularity']);
+
+      if (in_array($this->dateFieldType, self::$unixtimestampTypes)) {
+        $start_date = strtotime($start_date);
+        $end_date = strtotime($end_date);
       }
+      $this->view->query->addWhere(1, $this->startDateColumn, $end_date, '<');
+      $this->view->query->addWhere(1, $this->endDateColumn, $start_date, '>=');
     }
   }
 
@@ -408,10 +382,9 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
    *   Min and max values from the query.
    */
   private function getDateRange() {
-    $end_column = is_null($this->endDateColumn) ? $this->startDateColumn : $this->endDateColumn;
     $query = $this->database->select($this->fieldTable);
     $query->addExpression('MIN(' . $this->startDateColumn . ')', 'min');
-    $query->addExpression('MAX(' . $end_column . ')', 'max');
+    $query->addExpression('MAX(' . $this->endDateColumn . ')', 'max');
     return $query->execute()->fetchAssoc();
   }
 
@@ -426,7 +399,7 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
     $max_date = $this->dateRange['max'];
 
     // With smartdate timestamps need to be converted to datetime.
-    if (in_array($this->dateFieldType, ['smartdate', 'created', 'changed'])) {
+    if (in_array($this->dateFieldType, self::$unixtimestampTypes)) {
       $min_date = date($this->dateFormatString, $this->dateRange['min']);
       $max_date = date($this->dateFormatString, $this->dateRange['max']);
     }
@@ -437,7 +410,7 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
     // Try to get activeDate from URL Parameter.
     $date_parameter = $this->view->getRequest()->query->get('date');
     if (isset($date_parameter) && preg_match("/^\d{4}(-[0-1][0-9](-[0-3][0-9](T[0-2][0-9](:[0-6][0-9])?)?)?)?$/", $date_parameter)) {
-      $this->activeDate = new PagerDate($date_parameter);
+      $this->activeDate = new PagerDate($date_parameter, NULL, TRUE);
     }
     else {
       switch ($this->options['default_page']) {
@@ -451,7 +424,7 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
 
         default:
           $time = date($this->dateFormatString);
-          $time = new PagerDate($time, $this->dateFormatString);
+          $time = new PagerDate($time, $this->dateFormatString, TRUE);
           break;
       }
       $this->activeDate = $time;
diff --git a/tests/src/Functional/DatePagerUtcTest.php b/tests/src/Functional/DatePagerUtcTest.php
index 1c453d9..d7b1e65 100644
--- a/tests/src/Functional/DatePagerUtcTest.php
+++ b/tests/src/Functional/DatePagerUtcTest.php
@@ -139,7 +139,6 @@ class DatePagerUtcTest extends BrowserTestBase {
    */
   protected function setUp(): void {
     parent::setUp();
-    date_default_timezone_set($this->timeZone);
     $this->admin = $this->drupalCreateUser([], NULL, TRUE);
     $this->drupalLogin($this->admin);
 
@@ -304,6 +303,8 @@ class DatePagerUtcTest extends BrowserTestBase {
     ]);
 
     $this->drupalGet('node/' . $this->nodePage1->id() . '/edit');
+    $this->drupalGet('node/' . $this->nodePage1->id());
+
     $this->dateTime2 = DateTimePlus::createFromFormat($this->timeFormat, '2020-01-01T00:08:00', 'UTC');
     $this->dateRange2[0] = DateTimePlus::createFromFormat($this->timeFormat, '2009-02-01T09:09:00', 'UTC');
     $this->dateRange2[1] = DateTimePlus::createFromFormat($this->timeFormat, '2009-02-01T10:09:00', 'UTC');
@@ -377,7 +378,7 @@ class DatePagerUtcTest extends BrowserTestBase {
     $this->assertSession()->linkByHrefNotExists('node/' . $this->nodePage1->id());
 
     $this->drupalGet('testview', ['query' => ['date' => $this->dateTime1->format('Y', ['timezone' => $this->timeZone])]]);
-    $this->assertSession()->linkByHrefExists('node/' . $this->nodePage1->id());
+    $this->assertSession()->linkByHrefNotExists('node/' . $this->nodePage1->id());
 
     $this->drupalGet('testview', ['query' => ['date' => $this->dateTime1->format('Y-m-d', ['timezone' => $this->timeZone])]]);
     $this->assertSession()->linkByHrefExists('node/' . $this->nodePage1->id());
diff --git a/tests/src/Unit/PagerDateUtcUnitTest.php b/tests/src/Unit/PagerDateUtcUnitTest.php
index 0390ce7..2319142 100644
--- a/tests/src/Unit/PagerDateUtcUnitTest.php
+++ b/tests/src/Unit/PagerDateUtcUnitTest.php
@@ -39,6 +39,13 @@ class PagerDateUtcUnitTest extends UnitTestCase {
     $this->assertEquals('Y-m', $pager_date3->granularity);
     // First between the date two and three.
     $this->assertTrue($pager_date1->between($pager_date3, $pager_date2));
+
+    $date4 = '2021-02-13T15:09:04';
+    $date4_perth = '2021-02-13T23:09:04';
+    $pager_date4 = new PagerDate($date4);
+    $this->assertEquals($date4, $pager_date4->setTimezone(new \DateTimeZone('UTC'))->format($pager_date4->granularity));
+    $this->assertEquals($date4_perth, $pager_date4->setTimezone(new \DateTimeZone('Australia/Perth'))->format($pager_date4->granularity));
+
   }
 
 }
-- 
GitLab


From 670cd3cf0fe98310352c4f996818a37bd17c53e0 Mon Sep 17 00:00:00 2001
From: Stefan Leitner <sleitner@2466050.no-reply.drupal.org>
Date: Thu, 10 Apr 2025 21:54:13 +0200
Subject: [PATCH 2/9] UTC

---
 date_pager.module | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/date_pager.module b/date_pager.module
index 0b9d2fe..f88a3cc 100644
--- a/date_pager.module
+++ b/date_pager.module
@@ -94,7 +94,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $seconds = createGranularityDate($seconds, 0, 60, 'seconds', NULL, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:{$current_date['minute']}:", '', NULL, NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+    $seconds = create_granularity_date($seconds, 0, 60, 'seconds', NULL, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:{$current_date['minute']}:", '', NULL, NULL, $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $seconds = NULL;
@@ -112,7 +112,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $minutes = createGranularityDate($minutes, 0, 60, 'seconds', $seconds, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:", ':00', $current_date['minute'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+    $minutes = create_granularity_date($minutes, 0, 60, 'seconds', $seconds, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:", ':00', $current_date['minute'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $minutes = NULL;
@@ -130,7 +130,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $hours = createGranularityDate($hours, 0, 24, 'minutes', $minutes, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T", ":00:00", $current_date['hour'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+    $hours = create_granularity_date($hours, 0, 24, 'minutes', $minutes, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T", ":00:00", $current_date['hour'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
     $variables['pager']['time'] = $hours;
   }
   else {
@@ -149,7 +149,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $days = createGranularityDate($days, 1, 32, 'hours', $hours, "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'], ['year'=>$current_date['year'], 'month' => $current_date['month']],  $route_name, $active_date, $date_min, $date_max, $variables);
+    $days = create_granularity_date($days, 1, 32, 'hours', $hours, "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'], ['year' => $current_date['year'], 'month' => $current_date['month']],  $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $days = NULL;
@@ -168,7 +168,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $months = createGranularityDate($months, 1, 13, 'days', $days, "{$current_date['year']}-", "", $current_date['month'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+    $months = create_granularity_date($months, 1, 13, 'days', $days, "{$current_date['year']}-", "", $current_date['month'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $months = NULL;
@@ -193,7 +193,7 @@ function template_preprocess_datepager(&$variables) {
       ],
     ],
   ];
-  $years = createGranularityDate($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+  $years = create_granularity_date($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
 
   $variables['pager']['date'] = $years;
   $variables['pager']['#attached']['library'][] = 'date_pager/datepager';
@@ -203,7 +203,7 @@ function template_preprocess_datepager(&$variables) {
   $variables['#cache']['contexts'][] = 'url.query_args';
 }
 
-function createGranularityDate($dateitem, $start, $stop, $subitemname, $subitem, $pre, $post, $current, $checkdate, $route_name, $active_date, $date_min, $date_max, $variables){
+function create_granularity_date($dateitem, $start, $stop, $subitemname, $subitem, $pre, $post, $current, $checkdate, $route_name, $active_date, $date_min, $date_max, $variables){
   for ($dateiterator = $start; $dateiterator < $stop; $dateiterator++) {
     if (is_array($checkdate) && !checkdate($checkdate['month'], $dateiterator, $checkdate['year'])) {
       continue;
-- 
GitLab


From 2b7e619e7a8cb6f5de0fb565cb7fd2b370d8b01f Mon Sep 17 00:00:00 2001
From: Stefan Leitner <sleitner@2466050.no-reply.drupal.org>
Date: Thu, 10 Apr 2025 22:03:09 +0200
Subject: [PATCH 3/9] UTC

---
 date_pager.module                    | 33 +++++-----------------------
 src/Plugin/views/pager/DatePager.php | 20 +++++++++++++++++
 2 files changed, 26 insertions(+), 27 deletions(-)

diff --git a/date_pager.module b/date_pager.module
index f88a3cc..512f1d8 100644
--- a/date_pager.module
+++ b/date_pager.module
@@ -94,7 +94,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $seconds = create_granularity_date($seconds, 0, 60, 'seconds', NULL, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:{$current_date['minute']}:", '', NULL, NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+    $seconds = datePager::createGranularityDate($seconds, 0, 60, 'seconds', NULL, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:{$current_date['minute']}:", '', NULL, NULL, $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $seconds = NULL;
@@ -112,7 +112,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $minutes = create_granularity_date($minutes, 0, 60, 'seconds', $seconds, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:", ':00', $current_date['minute'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+    $minutes = datePager::createGranularityDate($minutes, 0, 60, 'seconds', $seconds, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T{$current_date['hour']}:", ':00', $current_date['minute'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $minutes = NULL;
@@ -130,7 +130,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $hours = create_granularity_date($hours, 0, 24, 'minutes', $minutes, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T", ":00:00", $current_date['hour'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+    $hours = datePager::createGranularityDate($hours, 0, 24, 'minutes', $minutes, "{$current_date['year']}-{$current_date['month']}-{$current_date['day']}T", ":00:00", $current_date['hour'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
     $variables['pager']['time'] = $hours;
   }
   else {
@@ -149,7 +149,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $days = create_granularity_date($days, 1, 32, 'hours', $hours, "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'], ['year' => $current_date['year'], 'month' => $current_date['month']],  $route_name, $active_date, $date_min, $date_max, $variables);
+    $days = datePager::createGranularityDate($days, 1, 32, 'hours', $hours, "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'], ['year' => $current_date['year'], 'month' => $current_date['month']], $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $days = NULL;
@@ -168,7 +168,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $months = create_granularity_date($months, 1, 13, 'days', $days, "{$current_date['year']}-", "", $current_date['month'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+    $months = datePager::createGranularityDate($months, 1, 13, 'days', $days, "{$current_date['year']}-", "", $current_date['month'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $months = NULL;
@@ -193,7 +193,7 @@ function template_preprocess_datepager(&$variables) {
       ],
     ],
   ];
-  $years = create_granularity_date($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+  $years = datePager::createGranularityDate($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
 
   $variables['pager']['date'] = $years;
   $variables['pager']['#attached']['library'][] = 'date_pager/datepager';
@@ -202,24 +202,3 @@ function template_preprocess_datepager(&$variables) {
   // parameters matter.
   $variables['#cache']['contexts'][] = 'url.query_args';
 }
-
-function create_granularity_date($dateitem, $start, $stop, $subitemname, $subitem, $pre, $post, $current, $checkdate, $route_name, $active_date, $date_min, $date_max, $variables){
-  for ($dateiterator = $start; $dateiterator < $stop; $dateiterator++) {
-    if (is_array($checkdate) && !checkdate($checkdate['month'], $dateiterator, $checkdate['year'])) {
-      continue;
-    }
-    $padded_date = str_pad($dateiterator, 2, '0', STR_PAD_LEFT);
-    $date = $pre."{$padded_date}".$post;
-    $pagerdate = new PagerDate($date, NULL, TRUE);
-    if ($pagerdate->between($date_min, $date_max)) {
-      $dateitem['items'][$padded_date] = $pagerdate->toLink($route_name, $active_date);
-      if ($padded_date == $current && isset($subitem)) {
-        $dateitem['items'][$padded_date][$subitemname] = $subitem;
-      }
-    }
-  }
-  if ($variables['options']['date_sort']) {
-    $dateitem['items'] = array_reverse($dateitem['items'], TRUE);
-  }
-  return $dateitem;
-}
\ No newline at end of file
diff --git a/src/Plugin/views/pager/DatePager.php b/src/Plugin/views/pager/DatePager.php
index b7cc81e..a2b5fe1 100644
--- a/src/Plugin/views/pager/DatePager.php
+++ b/src/Plugin/views/pager/DatePager.php
@@ -503,4 +503,24 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
     ];
   }
 
+  public static function createGranularityDate($dateitem, $start, $stop, $subitemname, $subitem, $pre, $post, $current, $checkdate, $route_name, $active_date, $date_min, $date_max, $variables){
+    for ($dateiterator = $start; $dateiterator < $stop; $dateiterator++) {
+      if (is_array($checkdate) && !checkdate($checkdate['month'], $dateiterator, $checkdate['year'])) {
+        continue;
+      }
+      $padded_date = str_pad($dateiterator, 2, '0', STR_PAD_LEFT);
+      $date = $pre."{$padded_date}".$post;
+      $pagerdate = new PagerDate($date, NULL, TRUE);
+      if ($pagerdate->between($date_min, $date_max)) {
+        $dateitem['items'][$padded_date] = $pagerdate->toLink($route_name, $active_date);
+        if ($padded_date == $current && isset($subitem)) {
+          $dateitem['items'][$padded_date][$subitemname] = $subitem;
+        }
+      }
+    }
+    if ($variables['options']['date_sort']) {
+      $dateitem['items'] = array_reverse($dateitem['items'], TRUE);
+    }
+    return $dateitem;
+  }
 }
-- 
GitLab


From 7042d4525b34b135db7a012bd0c78c172d651ac4 Mon Sep 17 00:00:00 2001
From: Stefan Leitner <sleitner@2466050.no-reply.drupal.org>
Date: Thu, 10 Apr 2025 22:04:38 +0200
Subject: [PATCH 4/9] UTC

---
 src/Plugin/views/pager/DatePager.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Plugin/views/pager/DatePager.php b/src/Plugin/views/pager/DatePager.php
index a2b5fe1..c4a6471 100644
--- a/src/Plugin/views/pager/DatePager.php
+++ b/src/Plugin/views/pager/DatePager.php
@@ -503,13 +503,13 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
     ];
   }
 
-  public static function createGranularityDate($dateitem, $start, $stop, $subitemname, $subitem, $pre, $post, $current, $checkdate, $route_name, $active_date, $date_min, $date_max, $variables){
+  public static function createGranularityDate($dateitem, $start, $stop, $subitemname, $subitem, $pre, $post, $current, $checkdate, $route_name, $active_date, $date_min, $date_max, $variables) {
     for ($dateiterator = $start; $dateiterator < $stop; $dateiterator++) {
       if (is_array($checkdate) && !checkdate($checkdate['month'], $dateiterator, $checkdate['year'])) {
         continue;
       }
       $padded_date = str_pad($dateiterator, 2, '0', STR_PAD_LEFT);
-      $date = $pre."{$padded_date}".$post;
+      $date = $pre . "{$padded_date}" . $post;
       $pagerdate = new PagerDate($date, NULL, TRUE);
       if ($pagerdate->between($date_min, $date_max)) {
         $dateitem['items'][$padded_date] = $pagerdate->toLink($route_name, $active_date);
-- 
GitLab


From 8e6a328807c4e893f24e4aef605898c09ded66e0 Mon Sep 17 00:00:00 2001
From: Stefan Leitner <sleitner@2466050.no-reply.drupal.org>
Date: Thu, 10 Apr 2025 22:12:06 +0200
Subject: [PATCH 5/9] UTC

---
 .gitlab-ci.yml                       | 2 +-
 date_pager.module                    | 5 +++--
 src/Plugin/views/pager/DatePager.php | 1 +
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5a7b150..7135977 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -28,4 +28,4 @@ include:
 #   OPT_IN_TEST_NEXT_MAJOR: '1'
 #   _CURL_TEMPLATES_REF: 'main'
 variables:
-  _CSPELL_WORDS: 'datepager, pagerdate, smartdate, testfield, testview'
+  _CSPELL_WORDS: 'dateitem, dateiterator, datepager, pagerdate, localdate, smartdate, subitemname, testfield, testview, timestring, unixtimestamp'
diff --git a/date_pager.module b/date_pager.module
index 512f1d8..a32e282 100644
--- a/date_pager.module
+++ b/date_pager.module
@@ -7,7 +7,7 @@
 
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
-use Drupal\date_pager\PagerDate;
+use Drupal\date_pager\Plugin\views\pager\DatePager;
 
 /**
  * Implements hook_help().
@@ -149,7 +149,8 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $days = datePager::createGranularityDate($days, 1, 32, 'hours', $hours, "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'], ['year' => $current_date['year'], 'month' => $current_date['month']], $route_name, $active_date, $date_min, $date_max, $variables);
+    $days = datePager::createGranularityDate($days, 1, 32, 'hours', $hours,
+      "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'], ['year' => $current_date['year'], 'month' => $current_date['month']], $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $days = NULL;
diff --git a/src/Plugin/views/pager/DatePager.php b/src/Plugin/views/pager/DatePager.php
index c4a6471..f81e74c 100644
--- a/src/Plugin/views/pager/DatePager.php
+++ b/src/Plugin/views/pager/DatePager.php
@@ -523,4 +523,5 @@ class DatePager extends PagerPluginBase implements CacheableDependencyInterface
     }
     return $dateitem;
   }
+
 }
-- 
GitLab


From 5e37c925826cf9cd606e7d9be631c0302e86af96 Mon Sep 17 00:00:00 2001
From: Stefan Leitner <sleitner@2466050.no-reply.drupal.org>
Date: Thu, 10 Apr 2025 22:17:06 +0200
Subject: [PATCH 6/9] UTC

---
 date_pager.module | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/date_pager.module b/date_pager.module
index a32e282..782654d 100644
--- a/date_pager.module
+++ b/date_pager.module
@@ -150,7 +150,9 @@ function template_preprocess_datepager(&$variables) {
       ],
     ];
     $days = datePager::createGranularityDate($days, 1, 32, 'hours', $hours,
-      "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'], ['year' => $current_date['year'], 'month' => $current_date['month']], $route_name, $active_date, $date_min, $date_max, $variables);
+      "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'],
+      ['year' => $current_date['year'], 'month' => $current_date['month']],
+      $route_name, $active_date, $date_min, $date_max, $variables);
   }
   else {
     $days = NULL;
-- 
GitLab


From 87ab19be2681ce3809f877f40823980be4768e6a Mon Sep 17 00:00:00 2001
From: Stefan Leitner <s.leitner@comunique.com>
Date: Wed, 16 Apr 2025 21:26:41 +0200
Subject: [PATCH 7/9] Edge date padding

---
 date_pager.module                             | 13 +++---
 src/PagerDate.php                             | 42 ++++++++++++-------
 ...DatePagerUtcTest.php => DatePagerTest.php} |  0
 ...eUtcUnitTest.php => PagerDateUnitTest.php} |  3 +-
 4 files changed, 33 insertions(+), 25 deletions(-)
 rename tests/src/Functional/{DatePagerUtcTest.php => DatePagerTest.php} (100%)
 rename tests/src/Unit/{PagerDateUtcUnitTest.php => PagerDateUnitTest.php} (95%)

diff --git a/date_pager.module b/date_pager.module
index 782654d..130a6e6 100644
--- a/date_pager.module
+++ b/date_pager.module
@@ -8,6 +8,7 @@
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\date_pager\Plugin\views\pager\DatePager;
+use Drupal\date_pager\PagerDate;
 
 /**
  * Implements hook_help().
@@ -149,7 +150,7 @@ function template_preprocess_datepager(&$variables) {
         ],
       ],
     ];
-    $days = datePager::createGranularityDate($days, 1, 32, 'hours', $hours,
+    $days = datePager::createGranularityDate($days, 1, 32, 'hours', NULL,
       "{$current_date['year']}-{$current_date['month']}-", "", $current_date['day'],
       ['year' => $current_date['year'], 'month' => $current_date['month']],
       $route_name, $active_date, $date_min, $date_max, $variables);
@@ -178,12 +179,8 @@ function template_preprocess_datepager(&$variables) {
   }
 
   // Construct Year Pager.
-  // Determine year Padding.
-  $show_years = 3;
-  $year_padding = ($show_years - 1) / 2;
-
-  $start_year = intval(date('Y', $date_min->toTime())) - $year_padding;
-  $end_year = intval(date('Y', $date_max->toTime())) + $year_padding;
+  $start_year = $date_min->format('Y');
+  $end_year = $date_max->format('Y') + 1;
 
   // Build year items.
   $years = [
@@ -196,7 +193,7 @@ function template_preprocess_datepager(&$variables) {
       ],
     ],
   ];
-  $years = datePager::createGranularityDate($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, $date_min, $date_max, $variables);
+  $years = datePager::createGranularityDate($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, new PagerDate($date_min->startDate(0), 'Y', TRUE),  new PagerDate($date_max->endDate(5),'Y-m-d\\TH:i:s', TRUE), $variables);
 
   $variables['pager']['date'] = $years;
   $variables['pager']['#attached']['library'][] = 'date_pager/datepager';
diff --git a/src/PagerDate.php b/src/PagerDate.php
index 2f9131f..269f90d 100644
--- a/src/PagerDate.php
+++ b/src/PagerDate.php
@@ -3,6 +3,7 @@
 namespace Drupal\date_pager;
 
 use Drupal\Core\Link;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\user\Entity\User;
 
 /**
@@ -13,7 +14,7 @@ use Drupal\user\Entity\User;
  */
 class PagerDate extends \DateTime {
 
-  use \Drupal\Core\StringTranslation\StringTranslationTrait;
+  use StringTranslationTrait;
 
   /**
    * String representation of a granularity.
@@ -57,6 +58,13 @@ class PagerDate extends \DateTime {
     5 => 'second',
   ];
 
+  /**
+   * Date pattern width.
+   *
+   * @var string[]
+   */
+  protected static $dateWidth = ['YYYY', '-MM', '-DD', 'T00', ':00', ':00'];
+
   /**
    * Constructs the PagerDate.
    *
@@ -77,11 +85,11 @@ class PagerDate extends \DateTime {
     }
     $this->granularityId = $this->findGranularityId();
 
-    $time = self::fillUpTimestring($time);
+    $filluptime = self::fillUpTimestring(substr($time, 0, $this->findGranularityLenght($this->granularityId)));
     if ($withUserTimezone) {
-      $time = str_replace('UTC', self::userTimezone(), $time);
+      $filluptime = str_replace('UTC', self::userTimezone(), $filluptime);
     }
-    parent::__construct($time);
+    parent::__construct($filluptime);
   }
 
   /**
@@ -98,11 +106,10 @@ class PagerDate extends \DateTime {
    *   The longest working part of the DateTime format string.
    */
   private function findGranularity($dateString) {
-    $date_length = ['YYYY', '-MM', '-DD', 'T00', ':00', ':00'];
     $date_parts = ['Y', '-m', '-d', '\TH', ':i', ':s'];
     // Check if what form at works, going longest to shortest.
     for ($i = 0; $i <= 6; $i++) {
-      $format = implode('', array_slice($date_length, 0, $i + 1));
+      $format = implode('', array_slice(self::$dateWidth, 0, $i + 1));
       if (strlen($format) == strlen($dateString)) {
         return implode('', array_slice($date_parts, 0, $i + 1));
       }
@@ -127,6 +134,16 @@ class PagerDate extends \DateTime {
     return FALSE;
   }
 
+  /**
+   * Helper function to find granularity length.
+   *
+   * @return int
+   *   Granularity length.
+   */
+  private function findGranularityLenght($granularity) {
+    return strlen(implode(array_slice(self::$dateWidth, 0, $granularity + 1)));
+  }
+
   /**
    * Return date formatted with the granularity.
    *
@@ -146,13 +163,8 @@ class PagerDate extends \DateTime {
    * @return int
    *   unix seconds
    */
-  public function toTime($format = NULL) {
-    if (is_null($format)) {
-      $format = $this->granularity;
-    }
-    $formatted_date = date($format, $this->format('U'));
-    return intval(\DateTime::createFromFormat($format, $formatted_date)
-      ->format('U'));
+  public function toTime() {
+    return $this->format('U');
   }
 
   /**
@@ -167,7 +179,7 @@ class PagerDate extends \DateTime {
    *   Returns TRUE if in between.
    */
   public function between(PagerDate $startdate, PagerDate $enddate) {
-    return (($this->toTime() >= $startdate->toTime($this->granularity)) && ($this->toTime() <= $enddate->toTime($this->granularity)));
+    return (($this->toTime() >= $startdate->toTime()) && ($this->toTime() <= $enddate->toTime()));
   }
 
   /**
@@ -269,7 +281,7 @@ class PagerDate extends \DateTime {
       $classes[] = 'future';
     }
 
-    if ($this->toTime() == $active_date->toTime($this->granularity)) {
+    if ($this->toTime() == $active_date->toTime()) {
       $classes[] = 'active';
     }
     $options['query'] = $args;
diff --git a/tests/src/Functional/DatePagerUtcTest.php b/tests/src/Functional/DatePagerTest.php
similarity index 100%
rename from tests/src/Functional/DatePagerUtcTest.php
rename to tests/src/Functional/DatePagerTest.php
diff --git a/tests/src/Unit/PagerDateUtcUnitTest.php b/tests/src/Unit/PagerDateUnitTest.php
similarity index 95%
rename from tests/src/Unit/PagerDateUtcUnitTest.php
rename to tests/src/Unit/PagerDateUnitTest.php
index 2319142..8007571 100644
--- a/tests/src/Unit/PagerDateUtcUnitTest.php
+++ b/tests/src/Unit/PagerDateUnitTest.php
@@ -16,8 +16,6 @@ class PagerDateUtcUnitTest extends UnitTestCase {
    * Test pager date.
    */
   public function testPagerDateUtc(): void {
-    date_default_timezone_set('UTC');
-
     $date1 = '2022-01-01T00:00:00';
     $pager_date1 = new PagerDate('2022');
     $this->assertEquals($date1, $pager_date1->format('Y-m-d\TH:i:s'));
@@ -37,6 +35,7 @@ class PagerDateUtcUnitTest extends UnitTestCase {
     $this->assertEquals('2021-02', $pager_date3->format($pager_date3->granularity));
     $this->assertEquals(1, $pager_date3->granularityId);
     $this->assertEquals('Y-m', $pager_date3->granularity);
+    $this->assertEquals(strtotime('2021-02-01T00:00:00 UTC'), $pager_date3->toTime());
     // First between the date two and three.
     $this->assertTrue($pager_date1->between($pager_date3, $pager_date2));
 
-- 
GitLab


From 6ed8c4ba68f962d3b75dce73ca46a006ac0ca727 Mon Sep 17 00:00:00 2001
From: Stefan Leitner <s.leitner@comunique.com>
Date: Wed, 16 Apr 2025 21:33:38 +0200
Subject: [PATCH 8/9] Edge date padding

---
 date_pager.module                      | 2 +-
 src/PagerDate.php                      | 6 +++---
 tests/src/Functional/DatePagerTest.php | 2 +-
 tests/src/Unit/PagerDateUnitTest.php   | 4 ++--
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/date_pager.module b/date_pager.module
index 130a6e6..2f633c7 100644
--- a/date_pager.module
+++ b/date_pager.module
@@ -193,7 +193,7 @@ function template_preprocess_datepager(&$variables) {
       ],
     ],
   ];
-  $years = datePager::createGranularityDate($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, new PagerDate($date_min->startDate(0), 'Y', TRUE),  new PagerDate($date_max->endDate(5),'Y-m-d\\TH:i:s', TRUE), $variables);
+  $years = datePager::createGranularityDate($years, $start_year, $end_year, 'months', $months, "", "", $current_date['year'], NULL, $route_name, $active_date, new PagerDate($date_min->startDate(0), 'Y', TRUE), new PagerDate($date_max->endDate(5), 'Y-m-d\\TH:i:s', TRUE), $variables);
 
   $variables['pager']['date'] = $years;
   $variables['pager']['#attached']['library'][] = 'date_pager/datepager';
diff --git a/src/PagerDate.php b/src/PagerDate.php
index 269f90d..ea648af 100644
--- a/src/PagerDate.php
+++ b/src/PagerDate.php
@@ -85,9 +85,9 @@ class PagerDate extends \DateTime {
     }
     $this->granularityId = $this->findGranularityId();
 
-    $filluptime = self::fillUpTimestring(substr($time, 0, $this->findGranularityLenght($this->granularityId)));
+    $fillUpTime = self::fillUpTimestring(substr($time, 0, $this->findGranularityLength($this->granularityId)));
     if ($withUserTimezone) {
-      $filluptime = str_replace('UTC', self::userTimezone(), $filluptime);
+      $fillUpTime = str_replace('UTC', self::userTimezone(), $fillUpTime);
     }
     parent::__construct($filluptime);
   }
@@ -140,7 +140,7 @@ class PagerDate extends \DateTime {
    * @return int
    *   Granularity length.
    */
-  private function findGranularityLenght($granularity) {
+  private function findGranularityLength($granularity) {
     return strlen(implode(array_slice(self::$dateWidth, 0, $granularity + 1)));
   }
 
diff --git a/tests/src/Functional/DatePagerTest.php b/tests/src/Functional/DatePagerTest.php
index d7b1e65..f38804c 100644
--- a/tests/src/Functional/DatePagerTest.php
+++ b/tests/src/Functional/DatePagerTest.php
@@ -12,7 +12,7 @@ use Drupal\Tests\BrowserTestBase;
  *
  * @group date_pager
  */
-class DatePagerUtcTest extends BrowserTestBase {
+class DatePagerTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
diff --git a/tests/src/Unit/PagerDateUnitTest.php b/tests/src/Unit/PagerDateUnitTest.php
index 8007571..4a0cdc8 100644
--- a/tests/src/Unit/PagerDateUnitTest.php
+++ b/tests/src/Unit/PagerDateUnitTest.php
@@ -10,12 +10,12 @@ use Drupal\Tests\UnitTestCase;
  *
  * @group date_pager
  */
-class PagerDateUtcUnitTest extends UnitTestCase {
+class PagerDateUnitTest extends UnitTestCase {
 
   /**
    * Test pager date.
    */
-  public function testPagerDateUtc(): void {
+  public function testPagerDate(): void {
     $date1 = '2022-01-01T00:00:00';
     $pager_date1 = new PagerDate('2022');
     $this->assertEquals($date1, $pager_date1->format('Y-m-d\TH:i:s'));
-- 
GitLab


From d55772982051e48c9f1bcbf1f5dd8edf9058e3cd Mon Sep 17 00:00:00 2001
From: Stefan Leitner <s.leitner@comunique.com>
Date: Wed, 16 Apr 2025 21:51:42 +0200
Subject: [PATCH 9/9] Edge date padding

---
 src/PagerDate.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/PagerDate.php b/src/PagerDate.php
index ea648af..a6a209f 100644
--- a/src/PagerDate.php
+++ b/src/PagerDate.php
@@ -89,7 +89,7 @@ class PagerDate extends \DateTime {
     if ($withUserTimezone) {
       $fillUpTime = str_replace('UTC', self::userTimezone(), $fillUpTime);
     }
-    parent::__construct($filluptime);
+    parent::__construct($fillUpTime);
   }
 
   /**
-- 
GitLab