From 3a2f9a24b580d46382891fb9dc39fabc7ad2bc74 Mon Sep 17 00:00:00 2001 From: Naomi <naomiaro@gmail.com> Date: Tue, 10 Dec 2013 16:45:05 -0500 Subject: [PATCH 1/2] CC-5627 : Check all Application_Common_DateHelper calculations that use timezone. working on getting widgets to work properly returning station local time. --- airtime_mvc/application/common/DateHelper.php | 98 ++++++++++++++----- .../application/controllers/ApiController.php | 94 +++++++++--------- .../controllers/ScheduleController.php | 24 +++-- airtime_mvc/application/models/Show.php | 32 +----- 4 files changed, 139 insertions(+), 109 deletions(-) diff --git a/airtime_mvc/application/common/DateHelper.php b/airtime_mvc/application/common/DateHelper.php index a5792f0a9..63ee75e26 100644 --- a/airtime_mvc/application/common/DateHelper.php +++ b/airtime_mvc/application/common/DateHelper.php @@ -45,18 +45,29 @@ class Application_Common_DateHelper return gmdate("H:i:s", $this->_dateTime); } - /** - * Get the week start date of this week in the format - * YYYY-MM-DD + /** * - * @return String - week start date + * @return DateTime - YYYY-MM-DD 00:00 in station timezone */ - function getWeekStartDate() + public static function getWeekStartDateTime() { + $stationTimezone = new DateTimeZone(Application_Model_Preference::GetDefaultTimezone()); + $now = new DateTime("now", $stationTimezone); + //want it to be the start of the day. + $now->setTime(0, 0, 0); + // our week starts on monday, but php week starts on sunday. - $startDate = date('w') == 0 ? date('Y-m-d', strtotime('monday last week')) : date('Y-m-d', strtotime('monday this week')); - $startDateTime = new DateTime($startDate); - return $startDateTime->format('Y-m-d H:i:s'); + $day = $now->format('w'); + if ($day == 0) { + $day = 7; + } + + $dayDiff = $day - 1; + if ($dayDiff > 0) { + $now->sub(new DateInterval("P{$dayDiff}D")); + } + + return $now; } /** @@ -234,24 +245,6 @@ class Application_Common_DateHelper return $dateTime; } - /* Convenience method to return a date formatted into a String rather than a - * DateTime object. Note that if an empty string is provided for $p_dateString - * then the current time is provided. - * - * @param $p_dateString - * Date string in UTC timezone. - * @param $p_format - * Format which the string should be returned in. - * - * @return string - * Date String in localtime - * */ - public static function ConvertToLocalDateTimeString($p_dateString, $p_format="Y-m-d H:i:s"){ - if (is_null($p_dateString) || strlen($p_dateString) == 0) - return $p_dateString; - return self::ConvertToLocalDateTime($p_dateString)->format($p_format); - } - public static function ConvertToUtcDateTimeString($p_dateString, $p_format="Y-m-d H:i:s"){ if (is_null($p_dateString) || strlen($p_dateString) == 0) return $p_dateString; @@ -325,6 +318,59 @@ class Application_Common_DateHelper return $retVal; } + /* + * @param $datetime string Y-m-d H:i:s in UTC timezone + * + * @return string in $format default Y-m-d H:i:s in station timezone + */ + public static function UTCStringToStationTimezoneString($datetime, $format="Y-m-d H:i:s") { + $stationTimezone = new DateTimeZone(Application_Model_Preference::GetDefaultTimezone()); + $utcTimezone = new DateTimeZone("UTC"); + + $d = new DateTime($datetime, $utcTimezone); + $d->setTimezone($stationTimezone); + + return $d->format($format); + } + + /* + * @param $datetime string Y-m-d H:i:s in UTC timezone + * + * @return string Y-m-d H:i:s in user's timezone + */ + public static function UTCStringToUserTimezoneString($datetime, $format="Y-m-d H:i:s") { + $userTimezone = new DateTimeZone(Application_Model_Preference::GetUserTimezone()); + $utcTimezone = new DateTimeZone("UTC"); + + $d = new DateTime($datetime, $utcTimezone); + $d->setTimezone($userTimezone); + + return $d->format($format); + } + + /** + * Convert the columns given in the array $columnsToConvert in the + * database result $rows to local timezone. + * + * @param array $rows arrays of arrays containing database query result + * @param array $columnsToConvert array of column names to convert + * @param string (station|user) convert to either station or user timezone. + */ + public static function convertTimestamps(&$rows, $columnsToConvert, $domain="station") + { + if (!is_array($rows)) { + return; + } + + $converter = "UTCStringTo".ucfirst($domain)."TimezoneString"; + + foreach ($rows as &$row) { + foreach ($columnsToConvert as $column) { + $row[$column] = self::$converter($row[$column]); + } + } + } + /** * This function is used for calculations! Don't modify for display purposes! * diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 73fb60896..cfff4a76b 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -267,9 +267,8 @@ class ApiController extends Zend_Controller_Action // disable the view and the layout $this->view->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); - - $date = new Application_Common_DateHelper; - $utcTimeNow = $date->getUtcTimestamp(); + + $utcTimeNow = gmdate("Y-m-d H:i:s"); $utcTimeEnd = ""; // if empty, getNextShows will use interval instead of end of day $request = $this->getRequest(); @@ -285,43 +284,37 @@ class ApiController extends Zend_Controller_Action // make getNextShows use end of day $utcTimeEnd = Application_Common_DateHelper::GetDayEndTimestampInUtc(); - $result = array("env"=>APPLICATION_ENV, - "schedulerTime"=>gmdate("Y-m-d H:i:s"), - "currentShow"=>Application_Model_Show::getCurrentShow($utcTimeNow), - "nextShow"=>Application_Model_Show::getNextShows($utcTimeNow, $limit, $utcTimeEnd) - ); - // XSS exploit prevention - foreach ($result["currentShow"] as &$current) { - $current["name"] = htmlspecialchars($current["name"]); - } - foreach ($result["nextShow"] as &$next) { - $next["name"] = htmlspecialchars($next["name"]); - } - - Application_Model_Show::convertToLocalTimeZone($result["currentShow"], - array("starts", "ends", "start_timestamp", "end_timestamp")); - Application_Model_Show::convertToLocalTimeZone($result["nextShow"], - array("starts", "ends", "start_timestamp", "end_timestamp")); - } else { + $result = array( + "env" => APPLICATION_ENV, + "schedulerTime" => $utcTimeNow, + "currentShow" => Application_Model_Show::getCurrentShow($utcTimeNow), + "nextShow" => Application_Model_Show::getNextShows($utcTimeNow, $limit, $utcTimeEnd) + ); + } + else { $result = Application_Model_Schedule::GetPlayOrderRange(); // XSS exploit prevention $result["previous"]["name"] = htmlspecialchars($result["previous"]["name"]); $result["current"]["name"] = htmlspecialchars($result["current"]["name"]); - $result["next"]["name"] = htmlspecialchars($result["next"]["name"]); - foreach ($result["currentShow"] as &$current) { - $current["name"] = htmlspecialchars($current["name"]); - } - foreach ($result["nextShow"] as &$next) { - $next["name"] = htmlspecialchars($next["name"]); - } - - //Convert from UTC to localtime for Web Browser. - Application_Model_Show::ConvertToLocalTimeZone($result["currentShow"], - array("starts", "ends", "start_timestamp", "end_timestamp")); - Application_Model_Show::ConvertToLocalTimeZone($result["nextShow"], - array("starts", "ends", "start_timestamp", "end_timestamp")); + $result["next"]["name"] = htmlspecialchars($result["next"]["name"]); } + + // XSS exploit prevention + foreach ($result["currentShow"] as &$current) { + $current["name"] = htmlspecialchars($current["name"]); + } + foreach ($result["nextShow"] as &$next) { + $next["name"] = htmlspecialchars($next["name"]); + } + + //Convert from UTC to station time for Web Browser. + Application_Common_DateHelper::convertTimestamps($result["currentShow"], + array("starts", "ends", "start_timestamp", "end_timestamp"), + "station"); + Application_Common_DateHelper::convertTimestamps($result["nextShow"], + array("starts", "ends", "start_timestamp", "end_timestamp"), + "station"); //used by caller to determine if the airtime they are running or widgets in use is out of date. $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; @@ -343,23 +336,33 @@ class ApiController extends Zend_Controller_Action $this->view->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); - $date = new Application_Common_DateHelper; - $dayStart = $date->getWeekStartDate(); - $utcDayStart = Application_Common_DateHelper::ConvertToUtcDateTimeString($dayStart); - + //weekStart is in station time. + $weekStartDateTime = Application_Common_DateHelper::getWeekStartDateTime(); + $dow = array("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", "nextmonday", "nexttuesday", "nextwednesday", "nextthursday", "nextfriday", "nextsaturday", "nextsunday"); $result = array(); - for ($i=0; $i<14; $i++) { - $utcDayEnd = Application_Common_DateHelper::GetDayEndTimestamp($utcDayStart); + $utcTimezone = new DateTimeZone("UTC"); + $stationTimezone = new DateTimeZone(Application_Model_Preference::GetDefaultTimezone()); + + $weekStartDateTime->setTimezone($utcTimezone); + $utcDayStart = $weekStartDateTime->format("Y-m-d H:i:s"); + for ($i = 0; $i < 14; $i++) { + + $weekStartDateTime->setTimezone($stationTimezone); + $weekStartDateTime->add(new DateInterval('P1D')); + + $utcDayEnd = $weekStartDateTime->format("Y-m-d H:i:s"); $shows = Application_Model_Show::getNextShows($utcDayStart, "ALL", $utcDayEnd); $utcDayStart = $utcDayEnd; - Application_Model_Show::convertToLocalTimeZone($shows, - array("starts", "ends", "start_timestamp", - "end_timestamp")); + Application_Common_DateHelper::convertTimestamps( + $shows, + array("starts", "ends", "start_timestamp","end_timestamp"), + "station" + ); $result[$dow[$i]] = $shows; } @@ -493,9 +496,8 @@ class ApiController extends Zend_Controller_Action try { $show_inst = new Application_Model_ShowInstance($show_instance_id); $show_inst->setRecordedFile($file_id); - //$show_start_time = Application_Common_DateHelper::ConvertToLocalDateTimeString($show_inst->getShowInstanceStart()); - - } catch (Exception $e) { + } + catch (Exception $e) { //we've reached here probably because the show was //cancelled, and therefore the show instance does not exist //anymore (ShowInstance constructor threw this error). We've diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index 12150c3db..2f1d62e0e 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -263,20 +263,28 @@ class ScheduleController extends Zend_Controller_Action /* Convert all UTC times to localtime before sending back to user. */ if (isset($range["previous"])) { - $range["previous"]["starts"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["previous"]["starts"]); - $range["previous"]["ends"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["previous"]["ends"]); + $range["previous"]["starts"] = Application_Common_DateHelper::UTCStringToUserTimezoneString($range["previous"]["starts"]); + $range["previous"]["ends"] = Application_Common_DateHelper::UTCStringToUserTimezoneString($range["previous"]["ends"]); } if (isset($range["current"])) { - $range["current"]["starts"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["current"]["starts"]); - $range["current"]["ends"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["current"]["ends"]); + $range["current"]["starts"] = Application_Common_DateHelper::UTCStringToUserTimezoneString($range["current"]["starts"]); + $range["current"]["ends"] = Application_Common_DateHelper::UTCStringToUserTimezoneString($range["current"]["ends"]); } if (isset($range["next"])) { - $range["next"]["starts"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["next"]["starts"]); - $range["next"]["ends"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["next"]["ends"]); + $range["next"]["starts"] = Application_Common_DateHelper::UTCStringToUserTimezoneString($range["next"]["starts"]); + $range["next"]["ends"] = Application_Common_DateHelper::UTCStringToUserTimezoneString($range["next"]["ends"]); } - Application_Model_Show::convertToLocalTimeZone($range["currentShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); - Application_Model_Show::convertToLocalTimeZone($range["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); + Application_Common_DateHelper::convertTimestamps( + $range["currentShow"], + array("starts", "ends", "start_timestamp", "end_timestamp"), + "user" + ); + Application_Common_DateHelper::convertTimestamps( + $range["nextShow"], + array("starts", "ends", "start_timestamp", "end_timestamp"), + "user" + ); $source_status = array(); $switch_status = array(); diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index efc8274a8..674533ad7 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -658,10 +658,7 @@ SQL; */ public function isStartDateTimeInPast() { - $date = new Application_Common_DateHelper; - $current_timestamp = $date->getUtcTimestamp(); - - return ($current_timestamp > ($this->getStartDate()." ".$this->getStartTime())); + return (gmdate("Y-m-d H:i:s") > ($this->getStartDate()." ".$this->getStartTime())); } /** @@ -702,9 +699,7 @@ SQL; { //need to update cc_show_instances, cc_show_days $con = Propel::getConnection(); - - $date = new Application_Common_DateHelper; - $timestamp = $date->getUtcTimestamp(); + $timestamp = gmdate("Y-m-d H:i:s"); $stmt = $con->prepare("UPDATE cc_show_days " ."SET duration = :add_show_duration " @@ -1080,11 +1075,9 @@ SQL; */ public static function getCurrentShow($timeNow=null) { - $CC_CONFIG = Config::getConfig(); $con = Propel::getConnection(); if ($timeNow == null) { - $date = new Application_Common_DateHelper; - $timeNow = $date->getUtcTimestamp(); + $timeNow = gmdate("Y-m-d H:i:s"); } //TODO, returning starts + ends twice (once with an alias). Unify this after the 2.0 release. --Martin $sql = <<<SQL @@ -1302,25 +1295,6 @@ SQL; return Application_Common_Database::prepareAndExecute( $sql, $params, 'all'); } - /** - * Convert the columns given in the array $columnsToConvert in the - * database result $rows to local timezone. - * - * @param type $rows arrays of arrays containing database query result - * @param type $columnsToConvert array of column names to convert - */ - public static function convertToLocalTimeZone(&$rows, $columnsToConvert) - { - if (!is_array($rows)) { - return; - } - foreach ($rows as &$row) { - foreach ($columnsToConvert as $column) { - $row[$column] = Application_Common_DateHelper::ConvertToLocalDateTimeString($row[$column]); - } - } - } - public static function getMaxLengths() { $sql = <<<SQL From 3d1f0b0d0e53286533f31b878e83379b29fe1393 Mon Sep 17 00:00:00 2001 From: Naomi <naomiaro@gmail.com> Date: Tue, 10 Dec 2013 17:41:59 -0500 Subject: [PATCH 2/2] CC-5627 : Check all Application_Common_DateHelper calculations that use timezone. --- airtime_mvc/application/common/DateHelper.php | 36 ++++++++++++++++--- .../application/controllers/ApiController.php | 23 ++++++++---- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/airtime_mvc/application/common/DateHelper.php b/airtime_mvc/application/common/DateHelper.php index 63ee75e26..cf1d8291b 100644 --- a/airtime_mvc/application/common/DateHelper.php +++ b/airtime_mvc/application/common/DateHelper.php @@ -45,23 +45,49 @@ class Application_Common_DateHelper return gmdate("H:i:s", $this->_dateTime); } + /** + * + * @return DateTime - YYYY-MM-DD 00:00 in station timezone of today + */ + public static function getTodayStationStartDateTime() + { + $stationTimezone = new DateTimeZone(Application_Model_Preference::GetDefaultTimezone()); + $now = new DateTime("now", $stationTimezone); + + $now->setTime(0, 0, 0); + + return $now; + } + + /** + * + * @return DateTime - YYYY-MM-DD 00:00 in station timezone of tomorrow + */ + public static function getTodayStationEndDateTime() + { + $stationTimezone = new DateTimeZone(Application_Model_Preference::GetDefaultTimezone()); + $now = new DateTime("now", $stationTimezone); + + $now->add(new DateInterval("P1D")); + $now->setTime(0, 0, 0); + + return $now; + } + /** * * @return DateTime - YYYY-MM-DD 00:00 in station timezone */ public static function getWeekStartDateTime() { - $stationTimezone = new DateTimeZone(Application_Model_Preference::GetDefaultTimezone()); - $now = new DateTime("now", $stationTimezone); - //want it to be the start of the day. - $now->setTime(0, 0, 0); + $now = self::getTodayStationStartDateTime(); // our week starts on monday, but php week starts on sunday. $day = $now->format('w'); if ($day == 0) { $day = 7; } - + $dayDiff = $day - 1; if ($dayDiff > 0) { $now->sub(new DateInterval("P{$dayDiff}D")); diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index cfff4a76b..a15e0081e 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -80,13 +80,16 @@ class ApiController extends Zend_Controller_Action return; } + + $tz = new DateTimeZone(Application_Model_Preference::GetUserTimezone()); + $now = new DateTime("now", $tz); $this->view->calendarInit = array( - "timestamp" => time(), - "timezoneOffset" => date("Z"), - "timeScale" => Application_Model_Preference::GetCalendarTimeScale(), - "timeInterval" => Application_Model_Preference::GetCalendarTimeInterval(), - "weekStartDay" => Application_Model_Preference::GetWeekStartDay() + "timestamp" => time(), + "timezoneOffset" => $now->format("Z"), + "timeScale" => Application_Model_Preference::GetCalendarTimeScale(), + "timeInterval" => Application_Model_Preference::GetCalendarTimeInterval(), + "weekStartDay" => Application_Model_Preference::GetWeekStartDay() ); $this->_helper->json->sendJson(array()); @@ -283,7 +286,9 @@ class ApiController extends Zend_Controller_Action } // make getNextShows use end of day - $utcTimeEnd = Application_Common_DateHelper::GetDayEndTimestampInUtc(); + $end = Application_Common_DateHelper::getTodayStationEndDateTime(); + $end->setTimezone(new DateTimeZone("UTC")); + $utcTimeEnd = $end->format("Y-m-d H:i:s"); $result = array( "env" => APPLICATION_ENV, "schedulerTime" => $utcTimeNow, @@ -351,13 +356,17 @@ class ApiController extends Zend_Controller_Action $utcDayStart = $weekStartDateTime->format("Y-m-d H:i:s"); for ($i = 0; $i < 14; $i++) { + //have to be in station timezone when adding 1 day for daylight savings. $weekStartDateTime->setTimezone($stationTimezone); $weekStartDateTime->add(new DateInterval('P1D')); + //convert back to UTC to get the actual timestamp used for search. + $weekStartDateTime->setTimezone($utcTimezone); + $utcDayEnd = $weekStartDateTime->format("Y-m-d H:i:s"); $shows = Application_Model_Show::getNextShows($utcDayStart, "ALL", $utcDayEnd); $utcDayStart = $utcDayEnd; - + Application_Common_DateHelper::convertTimestamps( $shows, array("starts", "ends", "start_timestamp","end_timestamp"),