From 52ba3b8146dd01c1c7d057359f4485aae5813124 Mon Sep 17 00:00:00 2001 From: Jim Hu Date: Thu, 25 Dec 2008 18:45:26 +0000 Subject: progress on timezones and daylight time --- calendars/recur_tests/ex_set2.ics | 2 +- calendars/recur_tests/ex_set3.ics | 1 - calendars/recur_tests/ex_set4.ics | 2 - calendars/test.ics | 29 +- config.inc.php | 4 +- functions/date_functions.php | 143 +++--- functions/is_daylight.php | 292 +++++++++++ functions/parse/end_vevent.php | 86 ++-- functions/parse/recur_functions.php | 3 +- functions/timezones.php | 976 ++++++++++++++++++------------------ 10 files changed, 940 insertions(+), 598 deletions(-) create mode 100644 functions/is_daylight.php diff --git a/calendars/recur_tests/ex_set2.ics b/calendars/recur_tests/ex_set2.ics index d57e5d8..ceb3a60 100644 --- a/calendars/recur_tests/ex_set2.ics +++ b/calendars/recur_tests/ex_set2.ics @@ -63,7 +63,7 @@ END:VEVENT BEGIN:VEVENT SEQUENCE:7 DTSTAMP:20020918T224617Z -SUMMARY:Weekly on Tuesday and Thursday for 5 weeks - goes 1 extra? +SUMMARY:Weekly on Tuesday and Thursday for 5 weeks STATUS:CONFIRMED DURATION:PT1H30M DTSTART;TZID=US/Eastern:19970902T090000 diff --git a/calendars/recur_tests/ex_set3.ics b/calendars/recur_tests/ex_set3.ics index c657b6e..69029af 100644 --- a/calendars/recur_tests/ex_set3.ics +++ b/calendars/recur_tests/ex_set3.ics @@ -69,7 +69,6 @@ DURATION:PT1H30M DTSTART;TZID=US/Eastern:19970907T090000 RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU END:VEVENT -END:VCALENDAR BEGIN:VEVENT SEQUENCE:7 DTSTAMP:20020918T224617Z diff --git a/calendars/recur_tests/ex_set4.ics b/calendars/recur_tests/ex_set4.ics index 64e785d..9b0e179 100644 --- a/calendars/recur_tests/ex_set4.ics +++ b/calendars/recur_tests/ex_set4.ics @@ -51,7 +51,6 @@ DURATION:PT1H30M DTSTART;TZID=US/Eastern:19970910T090000 RRULE:FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15 END:VEVENT -END:VCALENDAR BEGIN:VEVENT SEQUENCE:7 DTSTAMP:20020918T224617Z @@ -61,7 +60,6 @@ DURATION:PT1H30M DTSTART;TZID=US/Eastern:19970902T090000 RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU END:VEVENT -END:VCALENDAR BEGIN:VEVENT SEQUENCE:7 DTSTAMP:20020918T224617Z diff --git a/calendars/test.ics b/calendars/test.ics index 4bb03d4..9a9ce53 100644 --- a/calendars/test.ics +++ b/calendars/test.ics @@ -28,7 +28,7 @@ BEGIN:VEVENT UID:20081128T075152Z-3660-100-1-5@sietchtabr DTSTAMP:20081128T075151Z LAST-MODIFIED:20081128T075152 -SUMMARY:Witchcraft +SUMMARY:Witchcraft Paris CATEGORIES:jdr DTSTART;TZID=/softwarestudio.org/Tzfile/Europe/Paris:20081213T210000 DTEND;TZID=/softwarestudio.org/Tzfile/Europe/Paris:20081213T230000 @@ -37,4 +37,31 @@ SEQUENCE:1 CREATED:20081128T075152 END:VEVENT +BEGIN:VEVENT +UID:20081128T075152Z-3660-100-1-6@sietchtabr2 +DTSTAMP:20081128T075151Z +LAST-MODIFIED:20081128T075152 +SUMMARY:Witchcraft PST +CATEGORIES:jdr +DTSTART;TZID=US/Pacific:20081213T210000 +DTEND;TZID=US/Pacific:20081213T230000 +CLASS:PUBLIC +SEQUENCE:1 +CREATED:20081128T075152 +END:VEVENT + +BEGIN:VEVENT +UID:20081128T075152Z-3660-100-1-7@sietchtabr2 +DTSTAMP:20081128T075151Z +LAST-MODIFIED:20081128T075152 +SUMMARY:daylight test PST +CATEGORIES:jdr +DTSTART;TZID=US/Pacific:20060331T010000 +DTEND;TZID=US/Pacific:20060331T020000 +RRULE:FREQ=DAILY; +CLASS:PUBLIC +SEQUENCE:1 +CREATED:20081128T075152 +END:VEVENT + END:VCALENDAR diff --git a/config.inc.php b/config.inc.php index 78532e4..506d7ba 100644 --- a/config.inc.php +++ b/config.inc.php @@ -4,7 +4,7 @@ phpicalendar 2.3 should work with no additional configuration. This file can be changed to customize the behavior of phpicalendar. In version 2.3, there has been a change in the way configuration works in order to reduce the number of confusing global variables. Unfortunately, this means that config.inc.php files from older installations will have to be translated to the new format. The conversion is simple: use the old variable names as array keys for the $configs array below: */ - +$secs = 6*60*60; $configs = array( # 'calendar_path' => '/Library/WebServer/Documents/phpicalendar/calendars', # 'timezone' => 'US/Central', @@ -13,6 +13,8 @@ $configs = array( 'allow_preferences' => 'yes', # 'show_search' => 'yes', # 'show_todos' => 'no', + 'timezone' => 'US/Central', +# 'second_offset' => $secs, # 'cookie_uri' => '' ); diff --git a/functions/date_functions.php b/functions/date_functions.php index 3ba1b94..07745c1 100644 --- a/functions/date_functions.php +++ b/functions/date_functions.php @@ -153,7 +153,7 @@ function chooseOffset($time, $timezone = '') { break; default: if (is_array($tz_array) && array_key_exists($timezone, $tz_array)) { - $dlst = date('I', $time); + $dlst = is_daylight($time, $timezone); $offset = $tz_array[$timezone][$dlst]; } else { $offset = '+0000'; @@ -208,76 +208,105 @@ $return = " return $return; } -// Returns an array of the date and time extracted from the data -// passed in. This array contains (unixtime, date, time, allday). -// -// $data = A string representing a date-time per RFC2445. -// $property = The property being examined, e.g. DTSTART, DTEND. -// $field = The full field being examined, e.g. DTSTART;TZID=US/Pacific -function extractDateTime($data, $property, $field) { - global $tz_array, $phpiCal_config; - - // Initialize values. - unset($unixtime, $date, $time, $allday); +/* Returns an array of the date and time extracted from the data + passed in. This array contains (unixtime, date, time, allday). + + $data = A string representing a date-time per RFC2445. + $property = The property being examined, e.g. DTSTART, DTEND. + $field = The full field being examined, e.g. DTSTART;TZID=US/Pacific +See:http://phpicalendar.org/documentation/index.php/Property_Value_Data_Types#4.3.5___Date-Time +*/ +function extractDateTime($data, $property, $field) { + global $tz_array, $phpiCal_config, $calendar_tz; + $allday =''; #suppress error on returning undef. // Check for zulu time. $zulu_time = false; if (substr($data,-1) == 'Z') $zulu_time = true; - $data = str_replace('Z', '', $data); - - // Remove some substrings we don't want to look at. - $data = str_replace('T', '', $data); - $field = str_replace(';VALUE=DATE-TIME', '', $field); + // Pull out the timezone, or use GMT if zulu time was indicated. + if (preg_match('/^'.$property.';TZID=/i', $field)) { + $tz_tmp = explode('=', $field); + $tz_dt = match_tz($tz_tmp[1]); #echo "$tz_dt
"; + } elseif ($zulu_time) { + $tz_dt = 'GMT'; + } // Extract date-only values. - if ((preg_match('/^'.$property.';VALUE=DATE/i', $field)) || (ereg ('^([0-9]{4})([0-9]{2})([0-9]{2})$', $data))) { + if ((preg_match('/^'.$property.';VALUE=DATE:/i', $field)) || (ereg ('^([0-9]{4})([0-9]{2})([0-9]{2})$', $data))) { // Pull out the date value. Minimum year is 1970. ereg ('([0-9]{4})([0-9]{2})([0-9]{2})', $data, $dt_check); if ($dt_check[1] < 1970) { $data = '1971'.$dt_check[2].$dt_check[3]; - } - - // Set the values. - $unixtime = strtotime($data); - $date = date('Ymd', $unixtime); + } + # convert to date-time + $data = $dt_check[1].$dt_check[2].$dt_check[3]."T000000"; $time = ''; $allday = $data; - }else{ // Extract date-time values. - - // Pull out the timezone, or use GMT if zulu time was indicated. - if (preg_match('/^'.$property.';TZID=/i', $field)) { - $tz_tmp = explode('=', $field); - $tz_dt = $tz_tmp[1]; - unset($tz_tmp); - } elseif ($zulu_time) { - $tz_dt = 'GMT'; - } - - // Pull out the date and time values. Minimum year is 1970. - preg_match ('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})/', $data, $regs); - if ($regs[1] < 1970) { - $regs[1] = '1971'; - } - $date = $regs[1] . $regs[2] . $regs[3]; - $time = $regs[4] . $regs[5]; - $unixtime = mktime($regs[4], $regs[5], 0, $regs[2], $regs[3], $regs[1]); - // Check for daylight savings time. - $dlst = date('I', $unixtime); - $server_offset_tmp = chooseOffset($unixtime, $phpiCal_config->timezone); - if (isset($tz_dt)) { - $offset_tmp = chooseOffset($unixtime, $tz_dt); - } elseif (isset($calendar_tz)) { - $offset_tmp = chooseOffset($unixtime, $calendar_tz); - } else { - $offset_tmp = $server_offset_tmp; - } - // Set the values. - $unixtime = calcTime($offset_tmp, $server_offset_tmp, $unixtime); - $date = date('Ymd', $unixtime); - $time = date('Hi', $unixtime); - } + } + // Extract date-time values. + // Pull out the date and time values. Minimum year is 1970. + preg_match ('/([0-9]{4})([0-9]{2})([0-9]{2})T{0,1}([0-9]{0,2})([0-9]{0,2})/', $data, $regs); + if ($regs[1] < 1970) { + $regs[1] = '1971'; + } + $date = $regs[1] . $regs[2] . $regs[3]; + $time = $regs[4] . $regs[5]; + $unixtime = mktime($regs[4], $regs[5], 0, $regs[2], $regs[3], $regs[1]); + # chooseOffset checks for Daylight Saving Time + $server_offset_tmp = chooseOffset($unixtime, $phpiCal_config->timezone); + if (isset($tz_dt)) { + $offset_tmp = chooseOffset($unixtime, $tz_dt); + } elseif (isset($calendar_tz)) { + $offset_tmp = chooseOffset($unixtime, $calendar_tz); + } else { + $offset_tmp = $server_offset_tmp; + } + // Set the values. + $unixtime = calcTime($offset_tmp, $server_offset_tmp, $unixtime); + #echo "offset_tmp $offset_tmp, server_offset_tmp $server_offset_tmp, $unixtime =".date("Ymd His",$unixtime)." $time
"; + $date = date('Ymd', $unixtime); + if ($allday == '') $time = date('Hi', $unixtime); + // Return the results. return array($unixtime, $date, $time, $allday); } + +/* TZIDs in calendars often contain leading information that should be stripped +Example: TZID=/mozilla.org/20050126_1/Europe/Berlin +if this has been set by the parse_tzs scanning the file, then it should be OK, but sometimes a calendar may have a tzid without having defined the vtimezone, expecting a match (This will often happen when users send isolated events in bug reports; the calendars should have vtimezones). + +Need to return the part that matches a key in $tz_array +*/ +function match_tz($data){ + global $tz_array; + if (isset($tz_array[$data])) return $data; + foreach ($tz_array as $key=>$val){ + if (strpos(" $data",$key) > 0) return $key; + } + return $data; +} + +require_once(BASE."functions/is_daylight.php"); +/* function is_daylight($date, $timezone) returns 1 if daylight time, 0 if not + + default is to use the server's date function. This will be off when the timezone's rules are not the same as the server's rules. In php5.2+ there seems to be a better way to do this, but we can't count on users having php5.2+. + + Although we set dt_start and st_start in parse_tzs.php, these are not rrules and I don't know how to use them yet. So we'll do it by brute force for the ones we know about, from: http://www.webexhibits.org/daylightsaving/g.html + + Note that this sends a screwy time value - it's not necessarily UTC unixtime, since the mktime functions that create the time are not using the timezone. + +function is_daylight($time, $timezone){ + global $tz_array; + # default to std time, overwrite if daylight. + $dlst = 0; + switch ($timezone){ + default: + $dlst = date('I', $time); + } + + return $dlst; + +} +*/ ?> \ No newline at end of file diff --git a/functions/is_daylight.php b/functions/is_daylight.php new file mode 100644 index 0000000..c6f79ef --- /dev/null +++ b/functions/is_daylight.php @@ -0,0 +1,292 @@ += $start && $time < $end) $dlst = 1; + echo "$summary $dlst
"; + + return $dlst; + +} +?> \ No newline at end of file diff --git a/functions/parse/end_vevent.php b/functions/parse/end_vevent.php index 1dfe221..5970e65 100644 --- a/functions/parse/end_vevent.php +++ b/functions/parse/end_vevent.php @@ -320,7 +320,6 @@ foreach($recur_data as $recur_data_unixtime) { } else { $start_unixtime_tmp = mktime($recur_data_hour,$recur_data_minute,0,$recur_data_month,$recur_data_day,$recur_data_year); $end_unixtime_tmp = $start_unixtime_tmp + $length; - if (($end_time >= $phpiCal_config->bleed_time) && ($bleed_check == '-1')) { $start_tmp = strtotime(date('Ymd',$start_unixtime_tmp)); $end_date_tmp = date('Ymd',$end_unixtime_tmp); @@ -339,57 +338,18 @@ foreach($recur_data as $recur_data_unixtime) { $end_time_tmp = '2400'; $display_end_tmp = $end_time; } - - // Let's double check the until to not write past it - $until_check = $start_date_tmp.$time_tmp.'00'; - if (@$until > $until_check) { - $master_array[$start_date_tmp][$time_tmp][$uid] = array ( - 'event_start' => $start_time_tmp, - 'event_end' => $end_time_tmp, - 'start_unixtime' => $start_unixtime_tmp, - 'end_unixtime' => $end_unixtime_tmp, - 'event_text' => $summary, - 'event_length' => $length, - 'event_overlap' => 0, - 'description' => $description, - 'status' => $status, - 'class' => $class, - 'spans_day' => true, - 'location' => $location, - 'organizer' => serialize($organizer), - 'attendee' => serialize($attendee), - 'calnumber' => $calnumber, - 'calname' => $actual_calname, - 'url' => $url, - 'recur' => $recur); - if (isset($display_end_tmp)){ - $master_array[$start_date_tmp][$time_tmp][$uid]['display_end'] = $display_end_tmp; - } - checkOverlap($start_date_tmp, $time_tmp, $uid); - } - $start_tmp = strtotime('+1 day',$start_tmp); - } - } else { - if ($bleed_check == '-1') { - $display_end_tmp = $end_time; - $end_time_tmp1 = '2400'; - - } - if (!isset($end_time_tmp1)) $end_time_tmp1 = $end_time; - - // Let's double check the until to not write past it - $master_array[($recur_data_date)][($hour.$minute)][$uid] = array ( - 'event_start' => $start_time, - 'event_end' => $end_time_tmp1, + $master_array[$start_date_tmp][$time_tmp][$uid] = array ( + 'event_start' => $start_time_tmp, + 'event_end' => $end_time_tmp, 'start_unixtime' => $start_unixtime_tmp, 'end_unixtime' => $end_unixtime_tmp, - 'event_text' => $summary, + 'event_text' => $summary, # 'event_length' => $length, 'event_overlap' => 0, 'description' => $description, 'status' => $status, 'class' => $class, - 'spans_day' => false, + 'spans_day' => true, 'location' => $location, 'organizer' => serialize($organizer), 'attendee' => serialize($attendee), @@ -398,9 +358,41 @@ foreach($recur_data as $recur_data_unixtime) { 'url' => $url, 'recur' => $recur); if (isset($display_end_tmp)){ - $master_array[($recur_data_date)][($hour.$minute)][$uid]['display_end'] = $display_end_tmp; + $master_array[$start_date_tmp][$time_tmp][$uid]['display_end'] = $display_end_tmp; } - checkOverlap($recur_data_date, ($hour.$minute), $uid); + checkOverlap($start_date_tmp, $time_tmp, $uid); + $start_tmp = strtotime('+1 day',$start_tmp); + } + } else { + if ($bleed_check == '-1') { + $display_end_tmp = $end_time; + $end_time_tmp1 = '2400'; + + } + if (!isset($end_time_tmp1)) $end_time_tmp1 = $end_time; + $master_array[($recur_data_date)][($hour.$minute)][$uid] = array ( + 'event_start' => $start_time, + 'event_end' => $end_time_tmp1, + 'start_unixtime' => $start_unixtime_tmp, + 'end_unixtime' => $end_unixtime_tmp, + 'event_text' => $summary, + 'event_length' => $length, + 'event_overlap' => 0, + 'description' => $description, + 'status' => $status, + 'class' => $class, + 'spans_day' => false, + 'location' => $location, + 'organizer' => serialize($organizer), + 'attendee' => serialize($attendee), + 'calnumber' => $calnumber, + 'calname' => $actual_calname, + 'url' => $url, + 'recur' => $recur); + if (isset($display_end_tmp)){ + $master_array[($recur_data_date)][($hour.$minute)][$uid]['display_end'] = $display_end_tmp; + } + checkOverlap($recur_data_date, ($hour.$minute), $uid); } } diff --git a/functions/parse/recur_functions.php b/functions/parse/recur_functions.php index e45f4aa..6a58d2d 100644 --- a/functions/parse/recur_functions.php +++ b/functions/parse/recur_functions.php @@ -28,6 +28,7 @@ function add_recur($times,$freq=''){ if (!is_array($times)) $times = array($times); /*BYMONTH, BYWEEKNO, BYYEARDAY, BYMONTHDAY, BYDAY, BYHOUR, BYMINUTE, BYSECOND and BYSETPOS*/ +#dump_times($times); $times = restrict_bymonth($times,$freq); # $times = restrict_byweekno($times,$freq); $times = restrict_byyearday($times,$freq); @@ -253,6 +254,6 @@ function dump_times($times){ global $summary; echo "
$summary times:";
 	#var_dump($times);
-	foreach($times as $time) echo "\ndate:".date("Ymd his",$time);
+	foreach($times as $time) echo "\ndate:".date("Y-m-d H:i:s",$time);
 	echo "
"; } diff --git a/functions/timezones.php b/functions/timezones.php index 5c27a02..ae140f0 100644 --- a/functions/timezones.php +++ b/functions/timezones.php @@ -1,489 +1,491 @@ \ No newline at end of file -- cgit v1.2.3