root / drupal7 / sites / all / libraries / iCalcreator-2.22.1 / lib / iCal.tz.inc.php @ 73ab1d0a
1 | 0aee3c58 | Assos Assos | <?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 | } |