Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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