Completed
Push — master ( c6c53b...6ca4bd )
by mw
06:55
created

SRFTimezones::__construct()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5.5021

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 6
cts 11
cp 0.5455
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 4
nop 0
crap 5.5021
1
<?php
2
3
/**
4
 * Create the iCalendar's vTimezone component
5
 *
6
 * @author HgO
7
 *
8
 * @ingroup SemanticResultFormats
9
 */
10
class SRFTimezones {
11
	private $localTimezones;
12
	
13
	private $transitions;
14
	
15
	private $dateFrom;
16
	private $dateTo;
17
	
18
	private $offsets;
19
20 2
	public function __construct() {
21 2
		global $srfgTimezones;
22 2
		global $wgLocalTimezone;
23
		
24 2
		if ( empty( $srfgTimezones ) )
25 2
			$this->localTimezones = [];
26
		elseif ( is_array( $srfgTimezones ) )
27
			$this->localTimezones = $srfgTimezones;
28
		elseif ( isset( $wgLocalTimezone ) )
29
			$this->localTimezones = [ $wgLocalTimezone ];
30
		else
31
			$this->localTimezones = [ date_default_timezone_get() ];
32 2
	}
33
	
34
	/**
35
	 * @param array $localTimezones A list of local timezones.
36
	 */
37
	public function setLocalTimezones( $localTimezones ) {
38
		$this->localTimezones = $localTimezones;
39
	}
40
	
41
	/**
42
	 * Set a new range for the generated transitions.
43
	 * 
44
	 * @param $from Timestamp from which transitions are generated.
45
	 * @param $to Timestamp until which transitions are generated.
46
	 */
47
	public function setRange( $from, $to ) {
48
		$this->dateFrom = $from;
49
		$this->dateTo = $to;
50
	}
51
	
52
	/**
53
	 * Increase the range of the generated transitions. 
54
	 *
55
	 * @param int $from Timestamp from which transitions are generated.
56
	 * @param int $to Timestamp until which transitions are generated.
57
	 */
58 2
	public function updateRange( $from, $to ) {
59 2
		if ( $this->dateFrom === null || $from < $this->dateFrom )
60 2
			$this->dateFrom = $from;
61
		
62 2
		if ( $this->dateTo === null || $to > $this->dateTo )
63 2
			$this->dateTo = $to;
64 2
	}
65
	
66
	/**
67
	 * Calculate transitions for each timezone.
68
	 */
69 2
	public function calcTransitions() {
70 2
		$this->transitions = [];
71
	
72 2
		if ( $this->dateFrom === null || $this->dateTo === null )
73 1
			return false;
74
		
75 1
		foreach ( $this->localTimezones as $timezone ) {
76
			try {
77
				$dateTimezone = new DateTimeZone( $timezone );
78
			} catch( Exception $e ) {
79
				continue;
80
			}
81
			
82
			$transitions = $dateTimezone->getTransitions();
83
			
84
			$min = 0;
85
			$max = 1;
86
			foreach ( $transitions as $i => $transition ) {
87
				if ( $transition['ts'] < $this->dateFrom ) {
88
					$min = $i;
89
					continue;
90
				}
91
92
				if ( $transition['ts'] > $this->dateTo ) {
93
					$max = $i;
94
					break;
95
				}
96
			}
97
			
98
			$this->offsets[$timezone] = $transitions[max( $min-1, 0 )]['offset'];
99
			$this->transitions[$timezone] = array_slice( $transitions, $min, $max - $min );
100
		}
101 1
	}
102
	
103
	/**
104
	 * Generate the transitions for a given range, for each timezones, in the iCalendar format.
105
	 */
106 2
	public function getIcalForTimezone() {
107 2
		if ( $this->transitions === null )
108
			return false;
109
		
110 2
		$result = '';
111
		
112 2
		foreach ( $this->transitions as $timezone => $transitions ) {
113
			// cf. http://www.kanzaki.com/docs/ical/vtimezone.html
114
			$result .= "BEGIN:VTIMEZONE\r\n";
115
			$result .= "TZID:$timezone\r\n";
116
		
117
			$tzfrom = $this->offsets[$timezone] / 3600;
118
			foreach ( $transitions as $transition ) {
119
				$dst = ( $transition['isdst'] ) ? "DAYLIGHT" : "STANDARD";
120
				$result .= "BEGIN:$dst\r\n";
121
				
122
				$start_date = date( 'Ymd\THis', $transition['ts'] );
123
				$result .= "DTSTART:$start_date\r\n";
124
				
125
				$offset = $transition['offset'] / 3600;
126
				
127
				$offset_from = $this->formatTimezoneOffset( $tzfrom );
128
				$result .= "TZOFFSETFROM:$offset_from\r\n";
129
130
				$offset_to = $this->formatTimezoneOffset( $offset );
131
				$result .= "TZOFFSETTO:$offset_to\r\n";
132
				
133
				if ( !empty( $transition['abbr'] ) )
134
					$result .= "TZNAME:{$transition['abbr']}\r\n";
135
				
136
				$result .= "END:$dst\r\n";
137
				
138
				$tzfrom = $offset;
139
			}
140
			
141
			$result .= "END:VTIMEZONE\r\n";
142
		}
143
		
144 2
		return $result;
145
	}
146
	
147
	/**
148
	 * Format an integer offset to '+hhii', where hh are the hours, and ii the minutes
149
	 *
150
	 * @param int $offset
151
	 */
152
	private function formatTimezoneOffset( $offset ) {
153
		return sprintf('%s%02d%02d', $offset >= 0 ? '+' : '', floor($offset), ($offset - floor($offset)) * 60);
154
	}
155
}
156