1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; |
4
|
|
|
|
5
|
|
|
use DateTime; |
6
|
|
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception; |
7
|
|
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions; |
8
|
|
|
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; |
9
|
|
|
|
10
|
|
|
class Week |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* WEEKNUM. |
14
|
|
|
* |
15
|
|
|
* Returns the week of the year for a specified date. |
16
|
|
|
* The WEEKNUM function considers the week containing January 1 to be the first week of the year. |
17
|
|
|
* However, there is a European standard that defines the first week as the one with the majority |
18
|
|
|
* of days (four or more) falling in the new year. This means that for years in which there are |
19
|
|
|
* three days or less in the first week of January, the WEEKNUM function returns week numbers |
20
|
|
|
* that are incorrect according to the European standard. |
21
|
|
|
* |
22
|
|
|
* Excel Function: |
23
|
|
|
* WEEKNUM(dateValue[,style]) |
24
|
|
|
* |
25
|
|
|
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), |
26
|
|
|
* PHP DateTime object, or a standard date string |
27
|
|
|
* @param int $method Week begins on Sunday or Monday |
28
|
|
|
* 1 or omitted Week begins on Sunday. |
29
|
|
|
* 2 Week begins on Monday. |
30
|
|
|
* 11 Week begins on Monday. |
31
|
|
|
* 12 Week begins on Tuesday. |
32
|
|
|
* 13 Week begins on Wednesday. |
33
|
|
|
* 14 Week begins on Thursday. |
34
|
|
|
* 15 Week begins on Friday. |
35
|
|
|
* 16 Week begins on Saturday. |
36
|
|
|
* 17 Week begins on Sunday. |
37
|
|
|
* 21 ISO (Jan. 4 is week 1, begins on Monday). |
38
|
|
|
* |
39
|
|
|
* @return int|string Week Number |
40
|
|
|
*/ |
41
|
163 |
|
public static function number($dateValue, $method = Constants::STARTWEEK_SUNDAY) |
42
|
|
|
{ |
43
|
163 |
|
$origDateValueNull = empty($dateValue); |
44
|
|
|
|
45
|
|
|
try { |
46
|
163 |
|
$method = self::validateMethod($method); |
47
|
147 |
|
if ($dateValue === null) { // boolean not allowed |
48
|
10 |
|
$dateValue = (SharedDateHelper::getExcelCalendar() === SharedDateHelper::CALENDAR_MAC_1904 || $method === Constants::DOW_SUNDAY) ? 0 : 1; |
49
|
|
|
} |
50
|
147 |
|
$dateValue = self::validateDateValue($dateValue); |
51
|
128 |
|
if (!$dateValue && self::buggyWeekNum1900($method)) { |
52
|
|
|
// This seems to be an additional Excel bug. |
53
|
128 |
|
return 0; |
54
|
|
|
} |
55
|
35 |
|
} catch (Exception $e) { |
56
|
35 |
|
return $e->getMessage(); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
// Execute function |
60
|
124 |
|
$PHPDateObject = SharedDateHelper::excelToDateTimeObject($dateValue); |
61
|
124 |
|
if ($method == Constants::STARTWEEK_MONDAY_ISO) { |
62
|
36 |
|
Helpers::silly1900($PHPDateObject); |
63
|
|
|
|
64
|
36 |
|
return (int) $PHPDateObject->format('W'); |
65
|
|
|
} |
66
|
88 |
|
if (self::buggyWeekNum1904($method, $origDateValueNull, $PHPDateObject)) { |
67
|
3 |
|
return 0; |
68
|
|
|
} |
69
|
85 |
|
Helpers::silly1900($PHPDateObject, '+ 5 years'); // 1905 calendar matches |
70
|
85 |
|
$dayOfYear = (int) $PHPDateObject->format('z'); |
71
|
85 |
|
$PHPDateObject->modify('-' . $dayOfYear . ' days'); |
72
|
85 |
|
$firstDayOfFirstWeek = (int) $PHPDateObject->format('w'); |
73
|
85 |
|
$daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7; |
74
|
85 |
|
$daysInFirstWeek += 7 * !$daysInFirstWeek; |
75
|
85 |
|
$endFirstWeek = $daysInFirstWeek - 1; |
76
|
85 |
|
$weekOfYear = floor(($dayOfYear - $endFirstWeek + 13) / 7); |
77
|
|
|
|
78
|
85 |
|
return (int) $weekOfYear; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* ISOWEEKNUM. |
83
|
|
|
* |
84
|
|
|
* Returns the ISO 8601 week number of the year for a specified date. |
85
|
|
|
* |
86
|
|
|
* Excel Function: |
87
|
|
|
* ISOWEEKNUM(dateValue) |
88
|
|
|
* |
89
|
|
|
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), |
90
|
|
|
* PHP DateTime object, or a standard date string |
91
|
|
|
* |
92
|
|
|
* @return int|string Week Number |
93
|
|
|
*/ |
94
|
59 |
|
public static function isoWeekNumber($dateValue) |
95
|
|
|
{ |
96
|
59 |
|
if (self::apparentBug($dateValue)) { |
97
|
3 |
|
return 52; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
try { |
101
|
56 |
|
$dateValue = Helpers::getDateValue($dateValue); |
102
|
7 |
|
} catch (Exception $e) { |
103
|
7 |
|
return $e->getMessage(); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
// Execute function |
107
|
49 |
|
$PHPDateObject = SharedDateHelper::excelToDateTimeObject($dateValue); |
108
|
49 |
|
Helpers::silly1900($PHPDateObject); |
109
|
|
|
|
110
|
49 |
|
return (int) $PHPDateObject->format('W'); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* WEEKDAY. |
115
|
|
|
* |
116
|
|
|
* Returns the day of the week for a specified date. The day is given as an integer |
117
|
|
|
* ranging from 0 to 7 (dependent on the requested style). |
118
|
|
|
* |
119
|
|
|
* Excel Function: |
120
|
|
|
* WEEKDAY(dateValue[,style]) |
121
|
|
|
* |
122
|
|
|
* @param null|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer), |
123
|
|
|
* PHP DateTime object, or a standard date string |
124
|
|
|
* @param mixed $style A number that determines the type of return value |
125
|
|
|
* 1 or omitted Numbers 1 (Sunday) through 7 (Saturday). |
126
|
|
|
* 2 Numbers 1 (Monday) through 7 (Sunday). |
127
|
|
|
* 3 Numbers 0 (Monday) through 6 (Sunday). |
128
|
|
|
* |
129
|
|
|
* @return int|string Day of the week value |
130
|
|
|
*/ |
131
|
95 |
|
public static function day($dateValue, $style = 1) |
132
|
|
|
{ |
133
|
|
|
try { |
134
|
95 |
|
$dateValue = Helpers::getDateValue($dateValue); |
135
|
93 |
|
$style = self::validateStyle($style); |
136
|
7 |
|
} catch (Exception $e) { |
137
|
7 |
|
return $e->getMessage(); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
// Execute function |
141
|
88 |
|
$PHPDateObject = SharedDateHelper::excelToDateTimeObject($dateValue); |
142
|
88 |
|
Helpers::silly1900($PHPDateObject); |
143
|
88 |
|
$DoW = (int) $PHPDateObject->format('w'); |
144
|
|
|
|
145
|
|
|
switch ($style) { |
146
|
88 |
|
case 1: |
147
|
17 |
|
++$DoW; |
148
|
|
|
|
149
|
17 |
|
break; |
150
|
71 |
|
case 2: |
151
|
37 |
|
$DoW = self::dow0Becomes7($DoW); |
152
|
|
|
|
153
|
37 |
|
break; |
154
|
34 |
|
case 3: |
155
|
34 |
|
$DoW = self::dow0Becomes7($DoW) - 1; |
156
|
|
|
|
157
|
34 |
|
break; |
158
|
|
|
} |
159
|
|
|
|
160
|
88 |
|
return $DoW; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @param mixed $style expect int |
165
|
|
|
*/ |
166
|
93 |
|
private static function validateStyle($style): int |
167
|
|
|
{ |
168
|
93 |
|
$style = Functions::flattenSingleValue($style); |
169
|
|
|
|
170
|
93 |
|
if (!is_numeric($style)) { |
171
|
1 |
|
throw new Exception(Functions::VALUE()); |
172
|
|
|
} |
173
|
92 |
|
$style = (int) $style; |
174
|
92 |
|
if (($style < 1) || ($style > 3)) { |
175
|
4 |
|
throw new Exception(Functions::NAN()); |
176
|
|
|
} |
177
|
|
|
|
178
|
88 |
|
return $style; |
179
|
|
|
} |
180
|
|
|
|
181
|
71 |
|
private static function dow0Becomes7(int $DoW): int |
182
|
|
|
{ |
183
|
71 |
|
return ($DoW === 0) ? 7 : $DoW; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), |
188
|
|
|
* PHP DateTime object, or a standard date string |
189
|
|
|
*/ |
190
|
59 |
|
private static function apparentBug($dateValue): bool |
191
|
|
|
{ |
192
|
59 |
|
if (SharedDateHelper::getExcelCalendar() !== SharedDateHelper::CALENDAR_MAC_1904) { |
193
|
31 |
|
if (is_bool($dateValue)) { |
194
|
2 |
|
return true; |
195
|
|
|
} |
196
|
29 |
|
if (is_numeric($dateValue) && !((int) $dateValue)) { |
197
|
1 |
|
return true; |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
|
201
|
56 |
|
return false; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Validate dateValue parameter. |
206
|
|
|
* |
207
|
|
|
* @param mixed $dateValue |
208
|
|
|
*/ |
209
|
147 |
|
private static function validateDateValue($dateValue): float |
210
|
|
|
{ |
211
|
147 |
|
if (is_bool($dateValue)) { |
212
|
4 |
|
throw new Exception(Functions::VALUE()); |
213
|
|
|
} |
214
|
|
|
|
215
|
143 |
|
return Helpers::getDateValue($dateValue); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Validate method parameter. |
220
|
|
|
* |
221
|
|
|
* @param mixed $method |
222
|
|
|
*/ |
223
|
163 |
|
private static function validateMethod($method): int |
224
|
|
|
{ |
225
|
163 |
|
if ($method === null) { |
226
|
2 |
|
$method = Constants::STARTWEEK_SUNDAY; |
227
|
|
|
} |
228
|
163 |
|
$method = Functions::flattenSingleValue($method); |
229
|
163 |
|
if (!is_numeric($method)) { |
230
|
2 |
|
throw new Exception(Functions::VALUE()); |
231
|
|
|
} |
232
|
|
|
|
233
|
161 |
|
$method = (int) $method; |
234
|
161 |
|
if (!array_key_exists($method, Constants::METHODARR)) { |
235
|
14 |
|
throw new Exception(Functions::NAN()); |
236
|
|
|
} |
237
|
147 |
|
$method = Constants::METHODARR[$method]; |
238
|
|
|
|
239
|
147 |
|
return $method; |
240
|
|
|
} |
241
|
|
|
|
242
|
36 |
|
private static function buggyWeekNum1900(int $method): bool |
243
|
|
|
{ |
244
|
36 |
|
return $method === Constants::DOW_SUNDAY && SharedDateHelper::getExcelCalendar() === SharedDateHelper::CALENDAR_WINDOWS_1900; |
245
|
|
|
} |
246
|
|
|
|
247
|
88 |
|
private static function buggyWeekNum1904(int $method, bool $origNull, DateTime $dateObject): bool |
248
|
|
|
{ |
249
|
|
|
// This appears to be another Excel bug. |
250
|
|
|
|
251
|
88 |
|
return $method === Constants::DOW_SUNDAY && SharedDateHelper::getExcelCalendar() === SharedDateHelper::CALENDAR_MAC_1904 && |
252
|
88 |
|
!$origNull && $dateObject->format('Y-m-d') === '1904-01-01'; |
253
|
|
|
} |
254
|
|
|
} |
255
|
|
|
|