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"),