Projet

Général

Profil

Paste
Télécharger (14,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / libraries / iCalcreator-2.22.1 / lib / iCal.tz.inc.php @ b5aa1857

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
}