From f86b04d54b1dfb3bf9628c2e04b2034644ff660d Mon Sep 17 00:00:00 2001 From: Benn Oshrin Date: Sat, 30 Nov 2024 10:19:29 -0500 Subject: [PATCH] Improve timezone handling CFM-394) --- app/src/Controller/AppController.php | 13 +++++++++++-- app/src/Lib/Util/StringUtilities.php | 2 +- app/src/Model/Behavior/TimezoneBehavior.php | 10 ++++------ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/app/src/Controller/AppController.php b/app/src/Controller/AppController.php index f2f049923..d69902448 100644 --- a/app/src/Controller/AppController.php +++ b/app/src/Controller/AppController.php @@ -657,13 +657,22 @@ protected function setTZ() { // See if we've collected it from the browser in a previous page load. Otherwise, // use the system default. If the user set a preferred timezone, we'll catch that below. - $tz = date_default_timezone_get(); + $tz = new \DateTimeZone(date_default_timezone_get()); if(!empty($_COOKIE['cm_registry_tz_auto'])) { // We have an auto-detected timezone from a previous page render from the browser. // Note we don't call date_default_timezone_set() because we still want to record // times internally in UTC (at the expense of having to convert back and forth). - $tz = $_COOKIE['cm_registry_tz_auto']; + + try { + // If the cookie value is invalid, this will throw an Exception, and we'll eventually + // reset the browser cookie based on the detected timezone (for the next page load) + $tz = new \DateTimeZone($_COOKIE['cm_registry_tz_auto']); + } + catch(\Exception $e) { + // We'll fall back to the default timezone, and we'll reset the cookie when the + // default layout renders (so no need to do anything here) + } } // XXX need to implement person-specific timezone detection (after CoPerson model and diff --git a/app/src/Lib/Util/StringUtilities.php b/app/src/Lib/Util/StringUtilities.php index 97437c183..758e97d56 100644 --- a/app/src/Lib/Util/StringUtilities.php +++ b/app/src/Lib/Util/StringUtilities.php @@ -79,7 +79,7 @@ public static function columnKey($modelsName, $c, $tz=null, $useCustomClMdlLabel if($tz) { // If there is a timezone aware label, use that - $label = __d('field', $c.'.tz', [$tz]); + $label = __d('field', $c.'.tz', [$tz->getName()]); if($label != $c.'.tz') { return $label; diff --git a/app/src/Model/Behavior/TimezoneBehavior.php b/app/src/Model/Behavior/TimezoneBehavior.php index 17f9306ad..6c782da64 100644 --- a/app/src/Model/Behavior/TimezoneBehavior.php +++ b/app/src/Model/Behavior/TimezoneBehavior.php @@ -56,16 +56,14 @@ class TimezoneBehavior extends Behavior */ public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options) { - if($this->tz && $this->tz != 'UTC') { + if($this->tz && $this->tz->getName() != 'UTC') { // There's some Cake support for doing timezone conversion, but it's not really // well documented, so we use PHP calls directly. - $localTZ = new \DateTimeZone($this->tz); - foreach($this->fields as $f) { if(!empty($data[$f])) { // This returns a DateTime object adjusting for localTZ - $offsetDT = new \DateTime($data[$f], $localTZ); + $offsetDT = new \DateTime($data[$f], $this->tz); // strftime converts a timestamp according to server localtime (which should be UTC) $data[$f] = strftime("%F %T", $offsetDT->getTimestamp()); @@ -78,10 +76,10 @@ public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $opti * Set the current timezone. * * @since COmanage Registry v5.0.0 - * @param string $tz Timezone, eg as determined by AppController::beforeFilter + * @param DateTimeZone $tz Timezone, eg as determined by AppController::beforeFilter */ - public function setTimeZone(string $tz) { + public function setTimeZone(\DateTimeZone $tz) { $this->tz = $tz; } } \ No newline at end of file