root / drupal7 / sites / all / libraries / iCalcreator-2.22.1 / lib / iCal.tz.inc.php @ b0d73b57
1 |
<?php
|
---|---|
2 |
/*********************************************************************************/
|
3 |
/* Additional functions to use with vtimezone components */
|
4 |
/*********************************************************************************/
|
5 |
/**
|
6 |
* For use with
|
7 |
* iCalcreator (kigkonsult.se/iCalcreator/index.php)
|
8 |
* copyright (c) 2011 Yitzchok Lavi
|
9 |
* icalcreator@onebigsystem.com
|
10 |
* @version 2.22
|
11 |
*
|
12 |
* This library is free software; you can redistribute it and/or
|
13 |
* modify it under the terms of the GNU Lesser General Public
|
14 |
* License as published by the Free Software Foundation; either
|
15 |
* version 2.1 of the License, or (at your option) any later version.
|
16 |
*
|
17 |
* This library is distributed in the hope that it will be useful,
|
18 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
20 |
* Lesser General Public License for more details.
|
21 |
*
|
22 |
* You should have received a copy of the GNU Lesser General Public
|
23 |
* License along with this library; if not, write to the Free Software
|
24 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
25 |
*/
|
26 |
/**
|
27 |
* Additional functions to use with vtimezone components
|
28 |
*
|
29 |
* Before calling the functions, set time zone 'GMT' ('date_default_timezone_set')!
|
30 |
*
|
31 |
* @author Yitzchok Lavi <icalcreator@onebigsystem.com>
|
32 |
* adjusted for iCalcreator Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
33 |
* @version 1.0.2 - 2011-02-24
|
34 |
*
|
35 |
*/
|
36 |
/**
|
37 |
* Returns array with the offset information from UTC for a (UTC) datetime/timestamp in the
|
38 |
* timezone, according to the VTIMEZONE information in the input array.
|
39 |
*
|
40 |
* @param array $timezonesarray output from function getTimezonesAsDateArrays (below)
|
41 |
* @param string $tzid time zone identifier
|
42 |
* @param mixed $timestamp timestamp or a UTC datetime (in array format)
|
43 |
* @return array time zone data with keys for 'offsetHis', 'offsetSec' and 'tzname'
|
44 |
*
|
45 |
*/
|
46 |
function getTzOffsetForDate($timezonesarray, $tzid, $timestamp) { |
47 |
if( is_array( $timestamp )) { |
48 |
//$disp = sprintf( '%04d%02d%02d %02d%02d%02d', $timestamp['year'], $timestamp['month'], $timestamp['day'], $timestamp['hour'], $timestamp['min'], $timestamp['sec'] ); // test ###
|
49 |
$timestamp = gmmktime( |
50 |
$timestamp['hour'], |
51 |
$timestamp['min'], |
52 |
$timestamp['sec'], |
53 |
$timestamp['month'], |
54 |
$timestamp['day'], |
55 |
$timestamp['year'] |
56 |
) ; |
57 |
} |
58 |
$tzoffset = array(); |
59 |
// something to return if all goes wrong (such as if $tzid doesn't find us an array of dates)
|
60 |
$tzoffset['offsetHis'] = '+0000'; |
61 |
$tzoffset['offsetSec'] = 0; |
62 |
$tzoffset['tzname'] = '?'; |
63 |
if( !isset( $timezonesarray[$tzid] )) |
64 |
return $tzoffset; |
65 |
$tzdatearray = $timezonesarray[$tzid]; |
66 |
if ( is_array($tzdatearray) ) { |
67 |
sort($tzdatearray); // just in case |
68 |
if ( $timestamp < $tzdatearray[0]['timestamp'] ) { |
69 |
// our date is before the first change
|
70 |
$tzoffset['offsetHis'] = $tzdatearray[0]['tzbefore']['offsetHis'] ; |
71 |
$tzoffset['offsetSec'] = $tzdatearray[0]['tzbefore']['offsetSec'] ; |
72 |
$tzoffset['tzname'] = $tzdatearray[0]['tzbefore']['offsetHis'] ; // we don't know the tzname in this case |
73 |
} elseif ( $timestamp >= $tzdatearray[count($tzdatearray)-1]['timestamp'] ) { |
74 |
// our date is after the last change (we do this so our scan can stop at the last record but one)
|
75 |
$tzoffset['offsetHis'] = $tzdatearray[count($tzdatearray)-1]['tzafter']['offsetHis'] ; |
76 |
$tzoffset['offsetSec'] = $tzdatearray[count($tzdatearray)-1]['tzafter']['offsetSec'] ; |
77 |
$tzoffset['tzname'] = $tzdatearray[count($tzdatearray)-1]['tzafter']['tzname'] ; |
78 |
} else {
|
79 |
// our date somewhere in between
|
80 |
// loop through the list of dates and stop at the one where the timestamp is before our date and the next one is after it
|
81 |
// we don't include the last date in our loop as there isn't one after it to check
|
82 |
for ( $i = 0 ; $i <= count($tzdatearray)-2 ; $i++ ) { |
83 |
if(( $timestamp >= $tzdatearray[$i]['timestamp'] ) && ( $timestamp < $tzdatearray[$i+1]['timestamp'] )) { |
84 |
$tzoffset['offsetHis'] = $tzdatearray[$i]['tzafter']['offsetHis'] ; |
85 |
$tzoffset['offsetSec'] = $tzdatearray[$i]['tzafter']['offsetSec'] ; |
86 |
$tzoffset['tzname'] = $tzdatearray[$i]['tzafter']['tzname'] ; |
87 |
break;
|
88 |
} |
89 |
} |
90 |
} |
91 |
} |
92 |
return $tzoffset; |
93 |
} |
94 |
/**
|
95 |
* Returns an array containing all the timezone data in the vcalendar object
|
96 |
*
|
97 |
* @param object $vcalendar iCalcreator calendar instance
|
98 |
* @return array time zone transition timestamp, array before(offsetHis, offsetSec), array after(offsetHis, offsetSec, tzname)
|
99 |
* based on the timezone data in the vcalendar object
|
100 |
*
|
101 |
*/
|
102 |
function getTimezonesAsDateArrays($vcalendar) { |
103 |
$timezonedata = array(); |
104 |
while( $vtz = $vcalendar->getComponent( 'vtimezone' )) { |
105 |
$tzid = $vtz->getProperty('tzid'); |
106 |
$alltzdates = array(); |
107 |
while ( $vtzc = $vtz->getComponent( 'standard' )) { |
108 |
$newtzdates = expandTimezoneDates($vtzc); |
109 |
$alltzdates = array_merge($alltzdates, $newtzdates); |
110 |
} |
111 |
while ( $vtzc = $vtz->getComponent( 'daylight' )) { |
112 |
$newtzdates = expandTimezoneDates($vtzc); |
113 |
$alltzdates = array_merge($alltzdates, $newtzdates); |
114 |
} |
115 |
sort($alltzdates); |
116 |
$timezonedata[$tzid] = $alltzdates; |
117 |
} |
118 |
return $timezonedata; |
119 |
} |
120 |
/**
|
121 |
* Returns an array containing time zone data from vtimezone standard/daylight instances
|
122 |
*
|
123 |
* @param object $vtzc an iCalcreator calendar standard/daylight instance
|
124 |
* @return array time zone data; array before(offsetHis, offsetSec), array after(offsetHis, offsetSec, tzname)
|
125 |
*
|
126 |
*/
|
127 |
function expandTimezoneDates($vtzc) { |
128 |
$tzdates = array(); |
129 |
// prepare time zone "description" to attach to each change
|
130 |
$tzbefore = array(); |
131 |
$tzbefore['offsetHis'] = $vtzc->getProperty('tzoffsetfrom') ; |
132 |
$tzbefore['offsetSec'] = iCalUtilityFunctions::_tz2offset($tzbefore['offsetHis']); |
133 |
if(( '-' != substr( (string) $tzbefore['offsetSec'], 0, 1 )) && ( '+' != substr( (string) $tzbefore['offsetSec'], 0, 1 ))) |
134 |
$tzbefore['offsetSec'] = '+'.$tzbefore['offsetSec']; |
135 |
$tzafter = array(); |
136 |
$tzafter['offsetHis'] = $vtzc->getProperty('tzoffsetto') ; |
137 |
$tzafter['offsetSec'] = iCalUtilityFunctions::_tz2offset($tzafter['offsetHis']); |
138 |
if(( '-' != substr( (string) $tzafter['offsetSec'], 0, 1 )) && ( '+' != substr( (string) $tzafter['offsetSec'], 0, 1 ))) |
139 |
$tzafter['offsetSec'] = '+'.$tzafter['offsetSec']; |
140 |
if( FALSE === ( $tzafter['tzname'] = $vtzc->getProperty('tzname'))) |
141 |
$tzafter['tzname'] = $tzafter['offsetHis']; |
142 |
// find out where to start from
|
143 |
$dtstart = $vtzc->getProperty('dtstart'); |
144 |
$dtstarttimestamp = mktime( |
145 |
$dtstart['hour'], |
146 |
$dtstart['min'], |
147 |
$dtstart['sec'], |
148 |
$dtstart['month'], |
149 |
$dtstart['day'], |
150 |
$dtstart['year'] |
151 |
) ; |
152 |
if( !isset( $dtstart['unparsedtext'] )) // ?? |
153 |
$dtstart['unparsedtext'] = sprintf( '%04d%02d%02dT%02d%02d%02d', $dtstart['year'], $dtstart['month'], $dtstart['day'], $dtstart['hour'], $dtstart['min'], $dtstart['sec'] ); |
154 |
if ( $dtstarttimestamp == 0 ) { |
155 |
// it seems that the dtstart string may not have parsed correctly
|
156 |
// let's set a timestamp starting from 1902, using the time part of the original string
|
157 |
// so that the time will change at the right time of day
|
158 |
// at worst we'll get midnight again
|
159 |
$origdtstartsplit = explode('T',$dtstart['unparsedtext']) ; |
160 |
$dtstarttimestamp = strtotime("19020101",0); |
161 |
$dtstarttimestamp = strtotime($origdtstartsplit[1],$dtstarttimestamp); |
162 |
} |
163 |
// the date (in dtstart and opt RDATE/RRULE) is ALWAYS LOCAL (not utc!!), adjust from 'utc' to 'local' timestamp
|
164 |
$diff = -1 * $tzbefore['offsetSec']; |
165 |
$dtstarttimestamp += $diff; |
166 |
// add this (start) change to the array of changes
|
167 |
$tzdates[] = array( |
168 |
'timestamp' => $dtstarttimestamp, |
169 |
'tzbefore' => $tzbefore, |
170 |
'tzafter' => $tzafter |
171 |
); |
172 |
$datearray = getdate($dtstarttimestamp); |
173 |
// save original array to use time parts, because strtotime (used below) apparently loses the time
|
174 |
$changetime = $datearray ; |
175 |
// generate dates according to an RRULE line
|
176 |
$rrule = $vtzc->getProperty('rrule') ; |
177 |
if ( is_array($rrule) ) { |
178 |
if ( $rrule['FREQ'] == 'YEARLY' ) { |
179 |
// calculate transition dates starting from DTSTART
|
180 |
$offsetchangetimestamp = $dtstarttimestamp; |
181 |
// calculate transition dates until 10 years in the future
|
182 |
$stoptimestamp = strtotime("+10 year",time()); |
183 |
// if UNTIL is set, calculate until then (however far ahead)
|
184 |
if ( isset( $rrule['UNTIL'] ) && ( $rrule['UNTIL'] != '' )) { |
185 |
$stoptimestamp = mktime( |
186 |
$rrule['UNTIL']['hour'], |
187 |
$rrule['UNTIL']['min'], |
188 |
$rrule['UNTIL']['sec'], |
189 |
$rrule['UNTIL']['month'], |
190 |
$rrule['UNTIL']['day'], |
191 |
$rrule['UNTIL']['year'] |
192 |
) ; |
193 |
} |
194 |
$count = 0 ; |
195 |
$stopcount = isset( $rrule['COUNT'] ) ? $rrule['COUNT'] : 0 ; |
196 |
$daynames = array( |
197 |
'SU' => 'Sunday', |
198 |
'MO' => 'Monday', |
199 |
'TU' => 'Tuesday', |
200 |
'WE' => 'Wednesday', |
201 |
'TH' => 'Thursday', |
202 |
'FR' => 'Friday', |
203 |
'SA' => 'Saturday' |
204 |
); |
205 |
// repeat so long as we're between DTSTART and UNTIL, or we haven't prepared COUNT dates
|
206 |
while ( $offsetchangetimestamp < $stoptimestamp && ( $stopcount == 0 || $count < $stopcount ) ) { |
207 |
// break up the timestamp into its parts
|
208 |
$datearray = getdate($offsetchangetimestamp); |
209 |
if ( isset( $rrule['BYMONTH'] ) && ( $rrule['BYMONTH'] != 0 )) { |
210 |
// set the month
|
211 |
$datearray['mon'] = $rrule['BYMONTH'] ; |
212 |
} |
213 |
if ( isset( $rrule['BYMONTHDAY'] ) && ( $rrule['BYMONTHDAY'] != 0 )) { |
214 |
// set specific day of month
|
215 |
$datearray['mday'] = $rrule['BYMONTHDAY']; |
216 |
} elseif ( is_array($rrule['BYDAY']) ) { |
217 |
// find the Xth WKDAY in the month
|
218 |
// the starting point for this process is the first of the month set above
|
219 |
$datearray['mday'] = 1 ; |
220 |
// turn $datearray as it is now back into a timestamp
|
221 |
$offsetchangetimestamp = mktime( |
222 |
$datearray['hours'], |
223 |
$datearray['minutes'], |
224 |
$datearray['seconds'], |
225 |
$datearray['mon'], |
226 |
$datearray['mday'], |
227 |
$datearray['year'] |
228 |
); |
229 |
if ($rrule['BYDAY'][0] > 0) { |
230 |
// to find Xth WKDAY in month, we find last WKDAY in month before
|
231 |
// we do that by finding first WKDAY in this month and going back one week
|
232 |
// then we add X weeks (below)
|
233 |
$offsetchangetimestamp = strtotime($daynames[$rrule['BYDAY']['DAY']],$offsetchangetimestamp); |
234 |
$offsetchangetimestamp = strtotime("-1 week",$offsetchangetimestamp); |
235 |
} else {
|
236 |
// to find Xth WKDAY before the end of the month, we find the first WKDAY in the following month
|
237 |
// we do that by going forward one month and going to WKDAY there
|
238 |
// then we subtract X weeks (below)
|
239 |
$offsetchangetimestamp = strtotime("+1 month",$offsetchangetimestamp); |
240 |
$offsetchangetimestamp = strtotime($daynames[$rrule['BYDAY']['DAY']],$offsetchangetimestamp); |
241 |
} |
242 |
// now move forward or back the appropriate number of weeks, into the month we want
|
243 |
$offsetchangetimestamp = strtotime($rrule['BYDAY'][0] . " week",$offsetchangetimestamp); |
244 |
$datearray = getdate($offsetchangetimestamp); |
245 |
} |
246 |
// convert the date parts back into a timestamp, setting the time parts according to the
|
247 |
// original time data which we stored
|
248 |
$offsetchangetimestamp = mktime( |
249 |
$changetime['hours'], |
250 |
$changetime['minutes'], |
251 |
$changetime['seconds'] + $diff, |
252 |
$datearray['mon'], |
253 |
$datearray['mday'], |
254 |
$datearray['year'] |
255 |
); |
256 |
// add this change to the array of changes
|
257 |
$tzdates[] = array( |
258 |
'timestamp' => $offsetchangetimestamp, |
259 |
'tzbefore' => $tzbefore, |
260 |
'tzafter' => $tzafter |
261 |
); |
262 |
// update counters (timestamp and count)
|
263 |
$offsetchangetimestamp = strtotime("+" . (( isset( $rrule['INTERVAL'] ) && ( $rrule['INTERVAL'] != 0 )) ? $rrule['INTERVAL'] : 1 ) . " year",$offsetchangetimestamp); |
264 |
$count += 1 ; |
265 |
} |
266 |
} |
267 |
} |
268 |
// generate dates according to RDATE lines
|
269 |
while ($rdates = $vtzc->getProperty('rdate')) { |
270 |
if ( is_array($rdates) ) { |
271 |
|
272 |
foreach ( $rdates as $rdate ) { |
273 |
// convert the explicit change date to a timestamp
|
274 |
$offsetchangetimestamp = mktime( |
275 |
$rdate['hour'], |
276 |
$rdate['min'], |
277 |
$rdate['sec'] + $diff, |
278 |
$rdate['month'], |
279 |
$rdate['day'], |
280 |
$rdate['year'] |
281 |
) ; |
282 |
// add this change to the array of changes
|
283 |
$tzdates[] = array( |
284 |
'timestamp' => $offsetchangetimestamp, |
285 |
'tzbefore' => $tzbefore, |
286 |
'tzafter' => $tzafter |
287 |
); |
288 |
} |
289 |
} |
290 |
} |
291 |
return $tzdates; |
292 |
} |