Calendar::computeMillisInDay()   B
last analyzed

Complexity

Conditions 5
Paths 12

Size

Total Lines 38
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 12
nop 0
dl 0
loc 38
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
// +---------------------------------------------------------------------------+
4
// | This file is part of the Agavi package.                                   |
5
// | Copyright (c) 2005-2011 the Agavi Project.                                |
6
// |                                                                           |
7
// | For the full copyright and license information, please view the LICENSE   |
8
// | file that was distributed with this source code. You can also view the    |
9
// | LICENSE file online at http://www.agavi.org/LICENSE.txt                   |
10
// |   vi: set noexpandtab:                                                    |
11
// |   Local Variables:                                                        |
12
// |   indent-tabs-mode: t                                                     |
13
// |   End:                                                                    |
14
// +---------------------------------------------------------------------------+
15
16
namespace Agavi\Date;
17
18
use Agavi\Translation\Locale;
19
use Agavi\Translation\TranslationManager;
20
use Agavi\Util\Toolkit;
21
22
/**
23
 * Ported from ICU:
24
 *  icu/trunk/source/i18n/calendar.cpp        r22016
25
 *  icu/trunk/source/i18n/unicode/calendar.h  r22265
26
 *
27
 * @package    agavi
28
 * @subpackage date
29
 *
30
 * @author     Dominik del Bondio <[email protected]>
31
 * @author     The ICU Project
32
 * @copyright  Authors
33
 * @copyright  The Agavi Project
34
 *
35
 * @since      0.11.0
36
 *
37
 * @version    $Id$
38
 */
39
abstract class Calendar
40
{
41
    const GREGORIAN = 'gregorian';
42
43
    /**
44
     * @var        TranslationManager The translation manager instance.
45
     * @since      0.11.0
46
     */
47
    protected $translationManager;
48
49
    /**
50
     * Returns the translation manager.
51
     *
52
     * @return     TranslationManager The translation manager.
53
     *
54
     * @author     Dominik del Bondio <[email protected]>
55
     * @since      0.11.0
56
     */
57
    public function getTranslationManager()
58
    {
59
        return $this->translationManager;
60
    }
61
62
    /**
63
     * Initialize the variables to default values.
64
     *
65
     * @author     Dominik del Bondio <[email protected]>
66
     * @author     The ICU Project
67
     * @since      0.11.0
68
     */
69
    protected function initVariables()
70
    {
71
        $this->fIsTimeSet = false;
72
        $this->fAreFieldsInSync = false;
73
        $this->fAreAllFieldsSet = false;
74
        $this->fAreFieldsVirtuallySet = false;
75
        $this->fNextStamp = self::kMinimumUserStamp;
76
        $this->fTime = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $fTime was declared of type double, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
77
        $this->fLenient = true;
78
        $this->fZone = null;
79
    }
80
81
    /**
82
     * Called by the overload handler in the constructor.
83
     *
84
     * @param      TimeZone $zone   The timezone to use.
85
     * @param      Locale   $locale The locale to use.
86
     *
87
     * @author     Dominik del Bondio <[email protected]>
88
     * @author     The ICU Project
89
     * @since      0.11.0
90
     */
91
    protected function constructorOO(TimeZone $zone, Locale $locale)
92
    {
93
        $this->translationManager = $zone->getTranslationManager();
94
        $this->clear();
95
        $this->fZone = clone $zone;
96
        $this->setWeekCountData($locale, null);
97
    }
98
99
    /**
100
     * Marker for end of resolve set (row or group).
101
     */
102
    const RESOLVE_STOP  = -1;
103
104
    /**
105
     * Value to be bitwised "ORed" against resolve table field values for
106
     * remapping.  Example: (UCAL_DATE | kResolveRemap) in 1st column will cause
107
     * 'UCAL_DATE' to be returned, but will not examine the value of UCAL_DATE.
108
     */
109
    const RESOLVE_REMAP = 32;
110
111
    /**
112
     * The minimum supported Julian day.  This value is equivalent to
113
     * MIN_MILLIS.
114
     */
115
    const MIN_JULIAN                 = -19009842; //  -0x7F000000;  this was recalculated based on MIN_MILLIS
116
117
    /**
118
     * The minimum supported epoch milliseconds.  This value is equivalent
119
     * to MIN_JULIAN.
120
     */
121
    const MIN_MILLIS                 = -1853317152000000.0; // ((MIN_JULIAN - kEpochStartAsJulianDay) * kOneDay)
122
123
    /**
124
     * The maximum supported Julian day.  This value is equivalent to
125
     * MAX_MILLIS.
126
     */
127
    const MAX_JULIAN                 = 23939830.0; // (+0x7F000000)
128
129
    /**
130
     * The maximum supported epoch milliseconds.  This value is equivalent
131
     * to MAX_JULIAN.
132
     */
133
    const MAX_MILLIS                 = 1857534508800000.0; // ((MAX_JULIAN - kEpochStartAsJulianDay) * kOneDay)
134
135
    const LIMIT_MINIMUM             = 0;
136
    const LIMIT_GREATEST_MINIMUM    = 1;
137
    const LIMIT_LEAST_MAXIMUM       = 2;
138
    const LIMIT_MAXIMUM             = 3;
139
    const LIMIT_COUNT               = 4;
140
141
    protected static $kCalendarLimits = array(
142
        //               Minimum        Greatest min            Least max         Greatest max
143
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // ERA
144
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // YEAR
145
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // MONTH
146
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // WEEK_OF_YEAR
147
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // WEEK_OF_MONTH
148
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // DAY_OF_MONTH
149
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // DAY_OF_YEAR
150
        array(                 1,                  1,                   7,                   7 ), // DAY_OF_WEEK
151
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // DAY_OF_WEEK_IN_MONTH
152
        array(                 0,                  0,                   1,                   1 ), // AM_PM
153
        array(                 0,                  0,                  11,                  11 ), // HOUR
154
        array(                 0,                  0,                  23,                  23 ), // HOUR_OF_DAY
155
        array(                 0,                  0,                  59,                  59 ), // MINUTE
156
        array(                 0,                  0,                  59,                  59 ), // SECOND
157
        array(                 0,                  0,                 999,                 999 ), // MILLISECOND
158
        //    -12*self::kOneHour, -12*self::kOneHour,   12*self::kOneHour,   15*self::kOneHour
0 ignored issues
show
Unused Code Comprehensibility introduced by
52% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
159
        array(         -43200000,          -43200000,            43200000,            54000000 ), // ZONE_OFFSET
160
        array(                 0,                  0,DateDefinitions::MILLIS_PER_HOUR , DateDefinitions::MILLIS_PER_HOUR ), // DST_OFFSET
161
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // YEAR_WOY
162
        array(                 1,                  1,                   7,                   7 ), // DOW_LOCAL
163
        array(         /*N/A*/-1,          /*N/A*/-1,           /*N/A*/-1,           /*N/A*/-1 ), // EXTENDED_YEAR
164
        array(  self::MIN_JULIAN,   self::MIN_JULIAN,    self::MAX_JULIAN,    self::MAX_JULIAN ), // JULIAN_DAY
165
        //                     0,                  0, 24*self::kOneHour-1, 24*self::kOneHour-1
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
166
        array(                 0,                  0,           86399999,             86399999 ), // MILLISECONDS_IN_DAY
167
    );
168
169
    /**
170
     * Returns the current UTC (GMT) time measured in milliseconds since 0:00:00
171
     * on 1/1/70 (derived from the system time).
172
     *
173
     * @return     float The current UTC time in milliseconds.
174
     *
175
     * @author     Dominik del Bondio <[email protected]>
176
     * @author     The ICU Project
177
     * @since      0.11.0
178
     */
179
    public static function getNow()
180
    {
181
        return time() * DateDefinitions::MILLIS_PER_SECOND;
182
    }
183
184
    /**
185
     * Gets this Calendar's time as milliseconds. May involve recalculation of
186
     * time due to previous calls to set time field values. The time specified is
187
     * non-local UTC (GMT) time.
188
     *
189
     * @return     float The current time in UTC (GMT) time, or zero if the
190
     *                   operation failed.
191
     *
192
     * @author     Dominik del Bondio <[email protected]>
193
     * @author     The ICU Project
194
     * @since      0.11.0
195
     */
196
    public function getTime()
197
    {
198
        return $this->getTimeInMillis();
199
    }
200
201
    /**
202
     * Sets this Calendar's current time with the given UDate. The time specified
203
     * should be in non-local UTC (GMT) time.
204
     *
205
     * @param      float The given UDate in UTC (GMT) time.
206
     *
207
     * @author     Dominik del Bondio <[email protected]>
208
     * @author     The ICU Project
209
     * @since      0.11.0
210
     */
211
    public function setTime($date)
212
    {
213
        $this->setTimeInMillis($date);
214
    }
215
216
    /**
217
     * Returns the php native DateTime object which represents the time of this
218
     * object. Also supports dates which are not in the range of a unix timestamp.
219
     * It will also set the DateTime object to be in the same time zone as this
220
     * Calendar object.
221
     * Please note that this method will only work on PHP 5.1.x when you have
222
     * explicitly enabled the new DateTime support. This restriction does not
223
     * apply to 5.2 and upwards.
224
     * When the Calendar object is in the AD era, the result of the conversion
225
     * is undefined.
226
     *
227
     * @return     \DateTime The native DateTime.
228
     *
229
     * @author     Dominik del Bondio <[email protected]>
230
     * @since      0.11.0
231
     */
232
    public function getNativeDateTime()
233
    {
234
        $dateTimeString = sprintf(
235
            '%d-%d-%d %d:%d:%d',
236
            $this->get(DateDefinitions::YEAR), $this->get(DateDefinitions::MONTH) + 1, $this->get(DateDefinitions::DATE),
237
            $this->get(DateDefinitions::HOUR_OF_DAY), $this->get(DateDefinitions::MINUTE), $this->get(DateDefinitions::SECOND)
238
        );
239
        
240
        $tz = $this->getTimeZone();
241
        // check if this is a custom timezone (they have GMT+0000 as id and could potentially contain seconds as well, so we allow up to 6 digits)
242
        if (preg_match('#GMT[+-]\d{4,6}#', $tz->getId())) {
243
            return new \DateTime($dateTimeString . $tz->formatOffset(false, '', ''));
244
        } else {
245
            return new \DateTime($dateTimeString, new \DateTimeZone($tz->getId()));
246
        }
247
    }
248
249
    /**
250
     * Gets this Calendar's time as unix timestamp. May involve recalculation of
251
     * time due to previous calls to set time field values. The time specified is
252
     * non-local UTC (GMT) time.
253
     *
254
     * @return     int The current time in UTC (GMT) time as unix timestamp.
255
     *
256
     * @throws     <b>OverflowException</b> when the date can't be represented by
257
     *                                      an unix timestamp.
258
     *
259
     * @author     Dominik del Bondio <[email protected]>
260
     * @since      0.11.0
261
     */
262
    public function getUnixTimestamp()
263
    {
264
        $unixTime = floor($this->getTimeInMillis() / DateDefinitions::MILLIS_PER_SECOND);
265
        $unixTimeInt = (int) $unixTime;
266
        // lets check if the int can't represent the time anymore
267
        if ($unixTime != $unixTimeInt) {
268
            throw new \OverflowException('cannot convert the date ' . $this->get(DateDefinitions::YEAR) . '/' . $this->get(DateDefinitions::MONTH) . '/' . $this->get(DateDefinitions::DATE) . ' into a unix timestamp');
269
        }
270
        return $unixTimeInt;
271
    }
272
273
    /**
274
     * Sets this Calendar's current time with the given unix timestamp. The time
275
     * specified  should be in non-local UTC (GMT) time.
276
     *
277
     * @param      int $timestamp The given date in UTC (GMT) time.
278
     *
279
     * @author     Dominik del Bondio <[email protected]>
280
     * @since      0.11.0
281
     */
282
    public function setUnixTimestamp($timestamp)
283
    {
284
        $this->setTimeInMillis($timestamp * DateDefinitions::MILLIS_PER_SECOND);
285
    }
286
287
    /**
288
     * @see        Calendar::getAll()
289
     *
290
     * @author     Dominik del Bondio <[email protected]>
291
     * @since      1.0.0
292
     */
293
    public function toArray()
294
    {
295
        return $this->getAll();
296
    }
297
298
    /**
299
     * Sets all given time field values.
300
     *
301
     * @param      array $data An array using the DateDefinitions::XXX as key
302
     *                         and the respective value as value.
303
     *
304
     * @author     Dominik del Bondio <[email protected]>
305
     * @since      1.0.0
306
     */
307
    public function fromArray(array $data)
308
    {
309
        foreach ($data as $key => $value) {
310
            $this->set1($key, $value);
311
        }
312
    }
313
    
314
    /**
315
     * Returns the locale option string containing the timezone option set
316
     * to the timezone of this calendar.
317
     *
318
     * @param      string $prefix The prefix which will be applied to the timezone option
319
     *                            string. Use ';' here if you intend to use several
320
     *                            locale options and append the result of this method
321
     *                            to your locale string.
322
     *
323
     * @return     string
324
     *
325
     * @author     Dominik del Bondio <[email protected]>
326
     * @since      1.0.0
327
     */
328
    public function getTimeZoneLocaleOptionString($prefix = '@')
329
    {
330
        return Locale::getTimeZoneOptionString($this, $prefix);
331
    }
332
333
    public function __is_equal(Calendar $that)
334
    {
335
        return $this->isEquivalentTo($that) && $this->getTimeInMillis() == $that->getTimeInMillis();
336
    }
337
338
    public function __is_not_equal(Calendar $that)
339
    {
340
        return !$this->isEquivalentTo($that) || $this->getTimeInMillis() != $that->getTimeInMillis();
341
    }
342
343
    /**
344
     * Returns TRUE if the given Calendar object is equivalent to this
345
     * one.  An equivalent Calendar will behave exactly as this one
346
     * does, but it may be set to a different time.  By contrast, for
347
     * the operator==() method to return TRUE, the other Calendar must
348
     * be set to the same time.
349
     *
350
     * @param      Calendar the Calendar to be compared with this Calendar
351
     *
352
     * @return     bool
353
     *
354
     * @author     Dominik del Bondio <[email protected]>
355
     * @author     The ICU Project
356
     * @since      0.11.0
357
     */
358
    public function isEquivalentTo(Calendar $other)
359
    {
360
        return  get_class($this)                   == get_class($other) &&
361
                        $this->isLenient()                 == $other->isLenient() &&
362
                        $this->getFirstDayOfWeek()         == $other->getFirstDayOfWeek() &&
363
                        $this->getMinimalDaysInFirstWeek() == $other->getMinimalDaysInFirstWeek() &&
364
                        $this->getTimeZone()->__is_equal($other->getTimeZone());
365
    }
366
367
    /**
368
     * Compares the Calendar time, whereas Calendar::operator== compares the
369
     * equality of Calendar objects.
370
     *
371
     * @param      Calendar $when The Calendar to be compared with this Calendar.
372
     *                            The object may be modified physically
373
     *
374
     * @return     bool True if the current time of this Calendar is equal to the
375
     *                  time of Calendar when; false otherwise.
376
     *
377
     * @author     Dominik del Bondio <[email protected]>
378
     * @author     The ICU Project
379
     * @since      0.11.0
380
     */
381
    public function equals(Calendar $when)
382
    {
383
        return ($this->__is_equal($when) || $this->getTime() == $when->getTime());
384
    }
385
386
    /**
387
     * Returns true if this Calendar's current time is before "when"'s current
388
     * time.
389
     *
390
     * @param      Calendar $when The Calendar to be compared with this Calendar.
391
     *                            The object may be modified physically.
392
     *
393
     * @return     bool True if the current time of this Calendar is before the
394
     *                  time of Calendar when; false otherwise.
395
     *
396
     * @author     Dominik del Bondio <[email protected]>
397
     * @author     The ICU Project
398
     * @since      0.11.0
399
     */
400
    public function before(Calendar $when)
401
    {
402
        return ($this->__is_not_equal($when) && $this->getTimeInMillis() < $when->getTimeInMillis());
403
    }
404
405
    /**
406
     * Returns true if this Calendar's current time is after "when"'s current
407
     * time.
408
     *
409
     * @param      Calendar $when The Calendar to be compared with this Calendar.
410
     *                            The object may be modified physically.
411
     *
412
     * @return     bool True if the current time of this Calendar is after the
413
     *                  time of Calendar when; false otherwise.
414
     *
415
     * @author     Dominik del Bondio <[email protected]>
416
     * @author     The ICU Project
417
     * @since      0.11.0
418
     */
419
    public function after(Calendar $when)
420
    {
421
        return ($this->__is_not_equal($when) && $this->getTimeInMillis() > $when->getTimeInMillis());
422
    }
423
424
    /**
425
     * UDate Arithmetic function. Adds the specified (signed) amount of time to
426
     * the given time field, based on the calendar's rules. For example, to
427
     * subtract 5 days from the current time of the calendar, call
428
     * add(DateDefinitions::DATE, -5). When adding on the month or
429
     * DateDefinitions::DATE field, other fields like date might conflict
430
     * and need to be changed. For instance, adding 1 month on the date 01/31/96
431
     * will result in 02/29/96.
432
     *
433
     * @param      int $field  Specifies which date field to modify.
434
     * @param      int $amount The amount of time to be added to the field, in the natural
435
     *                         unit for that field (e.g., days for the day fields, hours
436
     *                         for the hour field.)
437
     *
438
     * @author     Dominik del Bondio <[email protected]>
439
     * @author     The ICU Project
440
     * @since      0.11.0
441
     */
442
    public function add($field, $amount)
443
    {
444
        if ($amount == 0) {
445
            return;   // Do nothing!
446
        }
447
448
        // We handle most fields in the same way.  The algorithm is to add
449
        // a computed amount of millis to the current millis.  The only
450
        // wrinkle is with DST -- for some fields, like the DAY_OF_MONTH,
451
        // we don't want the HOUR to shift due to changes in DST.  If the
452
        // result of the add operation is to move from DST to Standard, or
453
        // vice versa, we need to adjust by an hour forward or back,
454
        // respectively.  For such fields we set keepHourInvariant to TRUE.
455
456
        // We only adjust the DST for fields larger than an hour.  For
457
        // fields smaller than an hour, we cannot adjust for DST without
458
        // causing problems.  for instance, if you add one hour to April 5,
459
        // 1998, 1:00 AM, in PST, the time becomes "2:00 AM PDT" (an
460
        // illegal value), but then the adjustment sees the change and
461
        // compensates by subtracting an hour.  As a result the time
462
        // doesn't advance at all.
463
464
        // For some fields larger than a day, such as a UCAL_MONTH, we pin the
465
        // UCAL_DAY_OF_MONTH.  This allows <March 31>.add(UCAL_MONTH, 1) to be
466
        // <April 30>, rather than <April 31> => <May 1>.
467
468
        $delta = (float) $amount; // delta in ms
469
        $keepHourInvariant = true;
470
471
        switch ($field) {
472 View Code Duplication
            case DateDefinitions::ERA:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
473
                $this->set($field, $this->get($field) + $amount);
474
                $this->pinField(DateDefinitions::ERA);
475
                return;
476
477
            case DateDefinitions::YEAR:
478
            case DateDefinitions::EXTENDED_YEAR:
479
            case DateDefinitions::YEAR_WOY:
480 View Code Duplication
            case DateDefinitions::MONTH:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
481
                $this->set($field, $this->get($field) + $amount);
482
                $this->pinField(DateDefinitions::DAY_OF_MONTH);
483
                return;
484
485
            case DateDefinitions::WEEK_OF_YEAR:
486
            case DateDefinitions::WEEK_OF_MONTH:
487
            case DateDefinitions::DAY_OF_WEEK_IN_MONTH:
488
                $delta *= DateDefinitions::MILLIS_PER_WEEK;
489
                break;
490
491
            case DateDefinitions::AM_PM:
492
                $delta *= 12 * DateDefinitions::MILLIS_PER_HOUR;
493
                break;
494
495
            case DateDefinitions::DAY_OF_MONTH:
496
            case DateDefinitions::DAY_OF_YEAR:
497
            case DateDefinitions::DAY_OF_WEEK:
498
            case DateDefinitions::DOW_LOCAL:
499
            case DateDefinitions::JULIAN_DAY:
500
                $delta *= DateDefinitions::MILLIS_PER_DAY;
501
                break;
502
503
            case DateDefinitions::HOUR_OF_DAY:
504
            case DateDefinitions::HOUR:
505
                $delta *= DateDefinitions::MILLIS_PER_HOUR;
506
                $keepHourInvariant = false;
507
                break;
508
509
            case DateDefinitions::MINUTE:
510
                $delta *= DateDefinitions::MILLIS_PER_MINUTE;
511
                $keepHourInvariant = false;
512
                break;
513
514
            case DateDefinitions::SECOND:
515
                $delta *= DateDefinitions::MILLIS_PER_SECOND;
516
                $keepHourInvariant = false;
517
                break;
518
519
            case DateDefinitions::MILLISECOND:
520
            case DateDefinitions::MILLISECONDS_IN_DAY:
521
                $keepHourInvariant = false;
522
                break;
523
524
            default:
525
                throw new \InvalidArgumentException('Calendar::add(): field ' . $field . ' is not supported');
526
        }
527
528
        // In order to keep the hour invariant (for fields where this is
529
        // appropriate), record the DST_OFFSET before and after the add()
530
        // operation.  If it has changed, then adjust the millis to
531
        // compensate.
532
        $dst = 0;
533
        $hour = 0;
534
        if ($keepHourInvariant) {
535
            $dst = $this->get(DateDefinitions::DST_OFFSET);
536
            $hour = $this->internalGet(DateDefinitions::HOUR_OF_DAY);
537
        }
538
539
        $this->setTimeInMillis($this->getTimeInMillis() + $delta);
540
541
        if ($keepHourInvariant) {
542
            $dst -= $this->get(DateDefinitions::DST_OFFSET);
543
            if ($dst != 0) {
544
                // We have done an hour-invariant adjustment but the
545
                // DST offset has altered.  We adjust millis to keep
546
                // the hour constant.  In cases such as midnight after
547
                // a DST change which occurs at midnight, there is the
548
                // danger of adjusting into a different day.  To avoid
549
                // this we make the adjustment only if it actually
550
                // maintains the hour.
551
552
                /* double */
553
                $t = $this->internalGetTime();
554
                $this->setTimeInMillis($t + $dst);
555
                if ($this->get(DateDefinitions::HOUR_OF_DAY) != $hour) {
556
                    $this->setTimeInMillis($t);
557
                }
558
            }
559
        }
560
    }
561
562
    /**
563
     * Time Field Rolling function. Rolls by the given amount on the given
564
     * time field. For example, to roll the current date up by one day, call
565
     * roll(DateDefinitions::DATE, +1). When rolling on the month or
566
     * DateDefinitions::MONTH field, other fields like date might
567
     * conflict and, need to be changed. For instance, rolling the month up on the
568
     * date 01/31/96 will result in 02/29/96.  Rolling by a positive value always
569
     * means rolling forward in time; e.g., rolling the year by +1 on "100 BC"
570
     * will result in "99 BC", for Gregorian calendar. When rolling on the
571
     * hour-in-day or DateDefinitions::HOUR_OF_DAY field, it will
572
     * roll the hour value in the range between 0 and 23, which is zero-based.
573
     * <P>
574
     * The only difference between roll() and add() is that roll() does not change
575
     * the value of more significant fields when it reaches the minimum or maximum
576
     * of its range, whereas add() does.
577
     *
578
     * @param      int $field  The time field.
579
     * @param      int $amount Indicates amount to roll.
580
     *
581
     * @author     Dominik del Bondio <[email protected]>
582
     * @author     The ICU Project
583
     * @since      0.11.0
584
     */
585
    public function roll($field, $amount)
586
    {
587
        // this is overloaded in c++ with roll($field, $up)
588
        if (is_bool($amount)) {
589
            $amount = $amount ? +1 : -1;
590
        }
591
592
        if ($amount == 0) {
593
            return; // Nothing to do
594
        }
595
596
        $this->complete();
597
598
        switch ($field) {
599
            case DateDefinitions::DAY_OF_MONTH:
600
            case DateDefinitions::AM_PM:
601
            case DateDefinitions::MINUTE:
602
            case DateDefinitions::SECOND:
603
            case DateDefinitions::MILLISECOND:
604
            case DateDefinitions::MILLISECONDS_IN_DAY:
605
            case DateDefinitions::ERA:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
606
                // These are the standard roll instructions.  These work for all
607
                // simple cases, that is, cases in which the limits are fixed, such
608
                // as the hour, the day of the month, and the era.
609
                {
610
                    $min = $this->getActualMinimum($field);
611
                    $max = $this->getActualMaximum($field);
612
                    $gap = $max - $min + 1;
613
614
                    $value = $this->internalGet($field) + $amount;
615
                    $value = ($value - $min) % $gap;
616
                if ($value < 0) {
617
                    $value += $gap;
618
                }
619
                    $value += $min;
620
621
                    $this->set($field, $value);
622
                return;
623
            }
624
625
            case DateDefinitions::HOUR:
626
            case DateDefinitions::HOUR_OF_DAY:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
627
                // Rolling the hour is difficult on the ONSET and CEASE days of
628
                // daylight savings.  For example, if the change occurs at
629
                // 2 AM, we have the following progression:
630
                // ONSET: 12 Std -> 1 Std -> 3 Dst -> 4 Dst
631
                // CEASE: 12 Dst -> 1 Dst -> 1 Std -> 2 Std
632
                // To get around this problem we don't use fields; we manipulate
633
                // the time in millis directly.
634
                {
635
                    // Assume min == 0 in calculations below
636
                    /* double */ $start = $this->getTimeInMillis();
637
                    $oldHour = $this->internalGet($field);
638
                    $max = $this->getMaximum($field);
639
                    $newHour = ($oldHour + $amount) % ($max + 1);
640
                if ($newHour < 0) {
641
                    $newHour += $max + 1;
642
                }
643
                    $this->setTimeInMillis($start + DateDefinitions::MILLIS_PER_HOUR * ($newHour - $oldHour));
644
                return;
645
            }
646
647
            case DateDefinitions::MONTH:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
648
                // Rolling the month involves both pinning the final value
649
                // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
650
                // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
651
                // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
652
                {
653
                        $max = $this->getActualMaximum(DateDefinitions::MONTH);
654
                        $mon = ($this->internalGet(DateDefinitions::MONTH) + $amount) % ($max + 1);
655
656
                if ($mon < 0) {
657
                    $mon += ($max + 1);
658
                }
659
                        $this->set(DateDefinitions::MONTH, $mon);
660
661
                        // Keep the day of month in range.  We don't want to spill over
662
                        // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
663
                        // mar3.
664
                        $this->pinField(DateDefinitions::DAY_OF_MONTH);
665
                return;
666
            }
667
668
            case DateDefinitions::YEAR:
669
            case DateDefinitions::YEAR_WOY:
670 View Code Duplication
            case DateDefinitions::EXTENDED_YEAR:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
671
                // Rolling the year can involve pinning the DAY_OF_MONTH.
672
                $this->set($field, $this->internalGet($field) + $amount);
673
                $this->pinField(DateDefinitions::MONTH);
674
                $this->pinField(DateDefinitions::DAY_OF_MONTH);
675
                return;
676
677 View Code Duplication
            case DateDefinitions::WEEK_OF_MONTH:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
678
                {
679
                        // This is tricky, because during the roll we may have to shift
680
                        // to a different day of the week.  For example:
681
682
                        //    s  m  t  w  r  f  s
683
                        //          1  2  3  4  5
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
684
                        //    6  7  8  9 10 11 12
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
685
686
                        // When rolling from the 6th or 7th back one week, we go to the
687
                        // 1st (assuming that the first partial week counts).  The same
688
                        // thing happens at the end of the month.
689
690
                        // The other tricky thing is that we have to figure out whether
691
                        // the first partial week actually counts or not, based on the
692
                        // minimal first days in the week.  And we have to use the
693
                        // correct first day of the week to delineate the week
694
                        // boundaries.
695
696
                        // Here's our algorithm.  First, we find the real boundaries of
697
                        // the month.  Then we discard the first partial week if it
698
                        // doesn't count in this locale.  Then we fill in the ends with
699
                        // phantom days, so that the first partial week and the last
700
                        // partial week are full weeks.  We then have a nice square
701
                        // block of weeks.  We do the usual rolling within this block,
702
                        // as is done elsewhere in this method.  If we wind up on one of
703
                        // the phantom days that we added, we recognize this and pin to
704
                        // the first or the last day of the month.  Easy, eh?
705
706
                        // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
707
                        // in this locale.  We have dow in 0..6.
708
                        $dow = $this->internalGet(DateDefinitions::DAY_OF_WEEK) - $this->getFirstDayOfWeek();
709
                if ($dow < 0) {
710
                    $dow += 7;
711
                }
712
713
                        // Find the day of the week (normalized for locale) for the first
714
                        // of the month.
715
                        $fdm = ($dow - $this->internalGet(DateDefinitions::DAY_OF_MONTH) + 1) % 7;
716
                if ($fdm < 0) {
717
                    $fdm += 7;
718
                }
719
720
                        // Get the first day of the first full week of the month,
721
                        // including phantom days, if any.  Figure out if the first week
722
                        // counts or not; if it counts, then fill in phantom days.  If
723
                        // not, advance to the first real full week (skip the partial week).
724
                if ((7 - $fdm) < $this->getMinimalDaysInFirstWeek()) {
725
                    $start = 8 - $fdm; // Skip the first partial week
726
                } else {
727
                    $start = 1 - $fdm; // This may be zero or negative
728
                }
729
730
                        // Get the day of the week (normalized for locale) for the last
731
                        // day of the month.
732
                        $monthLen = $this->getActualMaximum(DateDefinitions::DAY_OF_MONTH);
733
                        $ldm = ($monthLen - $this->internalGet(DateDefinitions::DAY_OF_MONTH) + $dow) % 7;
734
                        // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.
735
736
                        // Get the limit day for the blocked-off rectangular month; that
737
                        // is, the day which is one past the last day of the month,
738
                        // after the month has already been filled in with phantom days
739
                        // to fill out the last week.  This day has a normalized DOW of 0.
740
                        $limit = $monthLen + 7 - $ldm;
741
742
                        // Now roll between start and (limit - 1).
743
                        $gap = $limit - $start;
744
                        $day_of_month = ($this->internalGet(DateDefinitions::DAY_OF_MONTH) + $amount * 7 - $start) % $gap;
745
                if ($day_of_month < 0) {
746
                    $day_of_month += $gap;
747
                }
748
                        $day_of_month += $start;
749
750
                        // Finally, pin to the real start and end of the month.
751
                if ($day_of_month < 1) {
752
                    $day_of_month = 1;
753
                }
754
                if ($day_of_month > $monthLen) {
755
                    $day_of_month = $monthLen;
756
                }
757
758
                        // Set the DAY_OF_MONTH.  We rely on the fact that this field
759
                        // takes precedence over everything else (since all other fields
760
                        // are also set at this point).  If this fact changes (if the
761
                        // disambiguation algorithm changes) then we will have to unset
762
                        // the appropriate fields here so that DAY_OF_MONTH is attended
763
                        // to.
764
                        $this->set(DateDefinitions::DAY_OF_MONTH, $day_of_month);
765
                return;
766
            }
767 View Code Duplication
            case DateDefinitions::WEEK_OF_YEAR:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
768
                {
769
                    // This follows the outline of WEEK_OF_MONTH, except it applies
770
                    // to the whole year.  Please see the comment for WEEK_OF_MONTH
771
                    // for general notes.
772
773
                    // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
774
                    // in this locale.  We have dow in 0..6.
775
                    $dow = $this->internalGet(DateDefinitions::DAY_OF_WEEK) - $this->getFirstDayOfWeek();
776
                if ($dow < 0) {
777
                    $dow += 7;
778
                }
779
780
                    // Find the day of the week (normalized for locale) for the first
781
                    // of the year.
782
                    $fdy = ($dow - $this->internalGet(DateDefinitions::DAY_OF_YEAR) + 1) % 7;
783
                if ($fdy < 0) {
784
                    $fdy += 7;
785
                }
786
787
                    // Get the first day of the first full week of the year,
788
                    // including phantom days, if any.  Figure out if the first week
789
                    // counts or not; if it counts, then fill in phantom days.  If
790
                    // not, advance to the first real full week (skip the partial week).
791
                if ((7 - $fdy) < $this->getMinimalDaysInFirstWeek()) {
792
                    $start = 8 - $fdy; // Skip the first partial week
793
                } else {
794
                    $start = 1 - $fdy; // This may be zero or negative
795
                }
796
797
                    // Get the day of the week (normalized for locale) for the last
798
                    // day of the year.
799
                    $yearLen = $this->getActualMaximum(DateDefinitions::DAY_OF_YEAR);
800
                    $ldy = ($yearLen - $this->internalGet(DateDefinitions::DAY_OF_YEAR) + $dow) % 7;
801
                    // We know yearLen >= DAY_OF_YEAR so we skip the += 7 step here.
802
803
                    // Get the limit day for the blocked-off rectangular year; that
804
                    // is, the day which is one past the last day of the year,
805
                    // after the year has already been filled in with phantom days
806
                    // to fill out the last week.  This day has a normalized DOW of 0.
807
                    $limit = $yearLen + 7 - $ldy;
808
809
                    // Now roll between start and (limit - 1).
810
                    $gap = $limit - $start;
811
                    $day_of_year = ($this->internalGet(DateDefinitions::DAY_OF_YEAR) + $amount * 7 - $start) % $gap;
812
                if ($day_of_year < 0) {
813
                    $day_of_year += $gap;
814
                }
815
                    $day_of_year += $start;
816
817
                    // Finally, pin to the real start and end of the month.
818
                if ($day_of_year < 1) {
819
                    $day_of_year = 1;
820
                }
821
                if ($day_of_year > $yearLen) {
822
                    $day_of_year = $yearLen;
823
                }
824
825
                    // Make sure that the year and day of year are attended to by
826
                    // clearing other fields which would normally take precedence.
827
                    // If the disambiguation algorithm is changed, this section will
828
                    // have to be updated as well.
829
                    $this->set(DateDefinitions::DAY_OF_YEAR, $day_of_year);
830
                    $this->clear(DateDefinitions::MONTH);
831
                return;
832
            }
833
            case DateDefinitions::DAY_OF_YEAR:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
834
                {
835
                    // Roll the day of year using millis.  Compute the millis for
836
                    // the start of the year, and get the length of the year.
837
                    $delta = (float) ($amount * DateDefinitions::MILLIS_PER_DAY); // Scale up from days to millis
838
                    $min2 = (float) ($this->internalGet(DateDefinitions::DAY_OF_YEAR) - 1);
839
                    $min2 *= DateDefinitions::MILLIS_PER_DAY;
840
                    $min2 = $this->internalGetTime() - $min2;
841
842
                    $yearLength = (float) $this->getActualMaximum(DateDefinitions::DAY_OF_YEAR);
843
                    $oneYear = $yearLength;
844
                    $oneYear *= DateDefinitions::MILLIS_PER_DAY;
845
                    $newtime = fmod(($this->internalGetTime() + $delta - $min2), $oneYear);
846
                if ($newtime < 0) {
847
                    $newtime += $oneYear;
848
                }
849
                    $this->setTimeInMillis($newtime + $min2);
850
                return;
851
            }
852
            case DateDefinitions::DAY_OF_WEEK:
853
            case DateDefinitions::DOW_LOCAL:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
854
                {
855
                    // Roll the day of week using millis.  Compute the millis for
856
                    // the start of the week, using the first day of week setting.
857
                    // Restrict the millis to [start, start+7days).
858
                    $delta = (float) ($amount * DateDefinitions::MILLIS_PER_DAY); // Scale up from days to millis
859
                    // Compute the number of days before the current day in this
860
                    // week.  This will be a value 0..6.
861
                    $leadDays = $this->internalGet($field);
862
                    $leadDays -= ($field == DateDefinitions::DAY_OF_WEEK) ? $this->getFirstDayOfWeek() : 1;
863
                if ($leadDays < 0) {
864
                    $leadDays += 7;
865
                }
866
                    $min2 = (float) ($this->internalGetTime() - $leadDays * DateDefinitions::MILLIS_PER_DAY);
867
                    $newtime = fmod(($this->internalGetTime() + $delta - $min2), DateDefinitions::MILLIS_PER_WEEK);
868
                if ($newtime < 0) {
869
                    $newtime += DateDefinitions::MILLIS_PER_WEEK;
870
                }
871
                    $this->setTimeInMillis($newtime + $min2);
872
                return;
873
            }
874
            case DateDefinitions::DAY_OF_WEEK_IN_MONTH:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
875
                {
876
                    // Roll the day of week in the month using millis.  Determine
877
                    // the first day of the week in the month, and then the last,
878
                    // and then roll within that range.
879
                    $delta = (float) ($amount * DateDefinitions::MILLIS_PER_WEEK); // Scale up from weeks to millis
880
                    // Find the number of same days of the week before this one
881
                    // in this month.
882
                    $preWeeks = (int) (($this->internalGet(DateDefinitions::DAY_OF_MONTH) - 1) / 7);
883
                    // Find the number of same days of the week after this one
884
                    // in this month.
885
                    $postWeeks = (int) (($this->getActualMaximum(DateDefinitions::DAY_OF_MONTH) - $this->internalGet(DateDefinitions::DAY_OF_MONTH)) / 7);
886
                    // From these compute the min and gap millis for rolling.
887
                    $min2 = (float) ($this->internalGetTime() - $preWeeks * DateDefinitions::MILLIS_PER_WEEK);
888
                    $gap2 = (float) (DateDefinitions::MILLIS_PER_WEEK * ($preWeeks + $postWeeks + 1)); // Must add 1!
889
                    // Roll within this range
890
                    $newtime = fmod(($this->internalGetTime() + $delta - $min2), $gap2);
891
                if ($newtime < 0) {
892
                    $newtime += $gap2;
893
                }
894
                    $this->setTimeInMillis($newtime + $min2);
895
                return;
896
            }
897
            case DateDefinitions::JULIAN_DAY:
898
                $this->set($field, $this->internalGet($field) + $amount);
899
                return;
900
            default:
901
                // Other fields cannot be rolled by this method
902
                throw new \InvalidArgumentException('Calendar::roll(): field ' . $field . ' cannot be rolled with this method');
903
        }
904
    }
905
906
    /**
907
     * Return the difference between the given time and the time this
908
     * calendar object is set to.  If this calendar is set
909
     * <em>before</em> the given time, the returned value will be
910
     * positive.  If this calendar is set <em>after</em> the given
911
     * time, the returned value will be negative.  The
912
     * <code>field</code> parameter specifies the units of the return
913
     * value.  For example, if <code>fieldDifference($when,
914
     * DateDefinitions::MONTH)</code> returns 3, then this calendar is set to
915
     * 3 months before <code>when</code>, and possibly some addition
916
     * time less than one month.
917
     *
918
     * <p>As a side effect of this call, this calendar is advanced
919
     * toward <code>$when</code> by the given amount.  That is, calling
920
     * this method has the side effect of calling <code>add($field,
921
     * $n)</code>, where <code>n</code> is the return value.
922
     *
923
     * <p>Usage: To use this method, call it first with the largest
924
     * field of interest, then with progressively smaller fields.  For
925
     * example:
926
     *
927
     * <pre>
928
     * $y = $cal->fieldDifference($when, DateDefinitions::YEAR);
929
     * $m = $cal->fieldDifference($when, DateDefinitions::MONTH);
930
     * $d = $cal->fieldDifference($when, DateDefinitions::DATE);</pre>
931
     *
932
     * computes the difference between <code>$cal</code> and
933
     * <code>$when</code> in years, months, and days.
934
     *
935
     * <p>Note: <code>fieldDifference()</code> is
936
     * <em>asymmetrical</em>.  That is, in the following code:
937
     *
938
     * <pre>
939
     * $cal->setTime($date1);
940
     * $m1 = $cal->fieldDifference($date2, DateDefinitions::MONTH);
941
     * $d1 = $cal->fieldDifference($date2, DateDefinitions::DATE);
942
     * $cal->setTime($date2);
943
     * $m2 = $cal->fieldDifference($date1, DateDefinitions::MONTH);
944
     * $d2 = $cal->fieldDifference($date1, DateDefinitions::DATE);</pre>
945
     *
946
     * one might expect that <code>$m1 == -$m2 && $d1 == -$d2</code>.
947
     * However, this is not generally the case, because of
948
     * irregularities in the underlying calendar system (e.g., the
949
     * Gregorian calendar has a varying number of days per month).
950
     *
951
     * @param      float|Calendar $targetMs When the date to compare this
952
     *                                      calendar's time to
953
     * @param      int            $field    The field in which to compute the result
954
     *
955
     * @return     int       The difference, either positive or negative, between
956
     *                       this calendar's time and <code>when</code>, in terms
957
     *                       of <code>field</code>.
958
     *
959
     * @author     Dominik del Bondio <[email protected]>
960
     * @author     The ICU Project
961
     * @since      0.11.0
962
     */
963
    public function fieldDifference($targetMs /* $when */, $field)
964
    {
965
        $min = 0;
966
        $startMs = (float) $this->getTimeInMillis();
967
        if ($targetMs instanceof Calendar) {
968
            $targetMs = (float) $targetMs->getTimeInMillis();
969
        }
970
        // Always add from the start millis.  This accommodates
971
        // operations like adding years from February 29, 2000 up to
972
        // February 29, 2004.  If 1, 1, 1, 1 is added to the year
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
973
        // field, the DOM gets pinned to 28 and stays there, giving an
974
        // incorrect DOM difference of 1.  We have to add 1, reset, 2,
975
        // reset, 3, reset, 4.
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
976
        if ($startMs < $targetMs) {
977
            $max = 1;
978
            // Find a value that is too large
979 View Code Duplication
            while (true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
980
                $this->setTimeInMillis($startMs);
981
                $this->add($field, $max);
982
                $ms = (float) $this->getTimeInMillis();
983
                if ($ms == $targetMs) {
984
                    return $max;
985
                } elseif ($ms > $targetMs) {
986
                    break;
987
                } else {
988
                    $max <<= 1;
989
                    if ($max < 0) {
990
                        // TODO: check if we can change this to float to support a larger range
991
                        // Field difference too large to fit into int32_t
992
                        throw new \InvalidArgumentException('The difference is to large to fit into an integer');
993
                    }
994
                }
995
            }
996
            // Do a binary search
997 View Code Duplication
            while (($max - $min) > 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
998
                $t = (int) (($min + $max) / 2);
999
                $this->setTimeInMillis($startMs);
1000
                $this->add($field, $t);
1001
                $ms = (float) $this->getTimeInMillis();
1002
                if ($ms == $targetMs) {
1003
                    return $t;
1004
                } elseif ($ms > $targetMs) {
1005
                    $max = $t;
1006
                } else {
1007
                    $min = $t;
1008
                }
1009
            }
1010
        } elseif ($startMs > $targetMs) {
1011
            $max = -1;
1012
            // Find a value that is too small
1013 View Code Duplication
            while (true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1014
                $this->setTimeInMillis($startMs);
1015
                $this->add($field, $max);
1016
                $ms = (float) $this->getTimeInMillis();
1017
                if ($ms == $targetMs) {
1018
                    return $max;
1019
                } elseif ($ms < $targetMs) {
1020
                    break;
1021
                } else {
1022
                    $max <<= 1;
1023
                    if ($max == 0) {
1024
                        // TODO: see above
1025
                        // Field difference too large to fit into int32_t
1026
                        throw new \InvalidArgumentException('The difference is to large to fit into an integer');
1027
                    }
1028
                }
1029
            }
1030
            // Do a binary search
1031 View Code Duplication
            while (($min - $max) > 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1032
                $t = (int) (($min + $max) / 2);
1033
                $this->setTimeInMillis($startMs);
1034
                $this->add($field, $t);
1035
                $ms = (float) $this->getTimeInMillis();
1036
                if ($ms == $targetMs) {
1037
                    return $t;
1038
                } elseif ($ms < $targetMs) {
1039
                    $max = $t;
1040
                } else {
1041
                    $min = $t;
1042
                }
1043
            }
1044
        }
1045
        // Set calendar to end point
1046
        $this->setTimeInMillis($startMs);
1047
        $this->add($field, $min);
1048
1049
        return $min;
1050
    }
1051
1052
    /**
1053
     * Sets the calendar's time zone to be the same as the one passed in. The
1054
     * TimeZone passed in is _not_ cloned.
1055
     *
1056
     * @param      TimeZone $zone The given time zone. If null is passed nothing
1057
     *                            is done.
1058
     *
1059
     * @author     Dominik del Bondio <[email protected]>
1060
     * @author     The ICU Project
1061
     * @since      0.11.0
1062
     */
1063
    public function setTimeZone(TimeZone $zone = null)
1064
    {
1065
        // Do nothing if passed-in zone is NULL
1066
        if (!$zone) {
1067
            return;
1068
        }
1069
1070
        // fZone should always be non-null
1071
        $this->fZone = $zone;
1072
1073
        // if the zone changes, we need to recompute the time fields
1074
        $this->fAreFieldsInSync = false;
1075
    }
1076
1077
    /**
1078
     * Returns a reference to the time zone owned by this calendar.
1079
     *
1080
     * @return     TimeZone The time zone object associated with this
1081
     *                           calendar.
1082
     *
1083
     * @author     Dominik del Bondio <[email protected]>
1084
     * @author     The ICU Project
1085
     * @since      0.11.0
1086
     */
1087
    public function getTimeZone()
1088
    {
1089
        return $this->fZone;
1090
    }
1091
1092
    /**
1093
     * Queries if the current date for this Calendar is in Daylight Savings Time.
1094
     *
1095
     * @return     bool True if the current date for this Calendar is in
1096
     *                  Daylight Savings Time, false, otherwise.
1097
     *
1098
     * @author     Dominik del Bondio <[email protected]>
1099
     * @author     The ICU Project
1100
     * @since      0.11.0
1101
     */
1102
    abstract public function inDaylightTime();
1103
1104
    /**
1105
     * Specifies whether or not date/time interpretation is to be lenient. With
1106
     * lenient interpretation, a date such as "February 942, 1996" will be treated
1107
     * as being equivalent to the 941st day after February 1, 1996. With strict
1108
     * interpretation, such dates will cause an error when computing time from the
1109
     * time field values representing the dates.
1110
     *
1111
     * @param      bool $lenient True specifies date/time interpretation to be lenient.
1112
     *
1113
     * @author     Dominik del Bondio <[email protected]>
1114
     * @author     The ICU Project
1115
     * @since      0.11.0
1116
     */
1117
    public function setLenient($lenient)
1118
    {
1119
        $this->fLenient = $lenient;
1120
    }
1121
1122
    /**
1123
     * Tells whether date/time interpretation is to be lenient.
1124
     *
1125
     * @return     bool True tells that date/time interpretation is to be lenient.
1126
     *
1127
     * @author     Dominik del Bondio <[email protected]>
1128
     * @author     The ICU Project
1129
     * @since      0.11.0
1130
     */
1131
    public function isLenient()
1132
    {
1133
        return $this->fLenient;
1134
    }
1135
1136
    /**
1137
     * Sets what the first day of the week is; e.g., Sunday in US, Monday in
1138
     * France.
1139
     *
1140
     * @param      int $value The given first day of the week.
1141
     *
1142
     * @author     Dominik del Bondio <[email protected]>
1143
     * @author     The ICU Project
1144
     * @since      0.11.0
1145
     */
1146
    public function setFirstDayOfWeek($value)
1147
    {
1148
        $this->fFirstDayOfWeek = $value;
1149
    }
1150
1151
    /**
1152
     * Gets what the first day of the week is; e.g., Sunday in US, Monday in
1153
     * France.
1154
     *
1155
     * @return     int The first day of the week.
1156
     *
1157
     * @author     Dominik del Bondio <[email protected]>
1158
     * @author     The ICU Project
1159
     * @since      0.11.0
1160
     */
1161
    public function getFirstDayOfWeek()
1162
    {
1163
        return $this->fFirstDayOfWeek;
1164
    }
1165
1166
    /**
1167
     * Sets what the minimal days required in the first week of the year are; For
1168
     * example, if the first week is defined as one that contains the first day of
1169
     * the first month of a year, call the method with value 1. If it must be a
1170
     * full week, use value 7.
1171
     *
1172
     * @param      int $value The given minimal days required in the first week of the
1173
     *                 year.
1174
     *
1175
     * @author     Dominik del Bondio <[email protected]>
1176
     * @author     The ICU Project
1177
     * @since      0.11.0
1178
     */
1179
    public function setMinimalDaysInFirstWeek($value)
1180
    {
1181
        $this->fMinimalDaysInFirstWeek = $value;
1182
    }
1183
1184
    /**
1185
     * Gets what the minimal days required in the first week of the year are;
1186
     * e.g., if the first week is defined as one that contains the first day of
1187
     * the first month of a year, getMinimalDaysInFirstWeek returns 1. If the
1188
     * minimal days required must be a full week, getMinimalDaysInFirstWeek
1189
     * returns 7.
1190
     *
1191
     * @return     int The minimal days required in the first week of the year.
1192
     *
1193
     * @author     Dominik del Bondio <[email protected]>
1194
     * @author     The ICU Project
1195
     * @since      0.11.0
1196
     */
1197
    public function getMinimalDaysInFirstWeek()
1198
    {
1199
        return $this->fMinimalDaysInFirstWeek;
1200
    }
1201
1202
    /**
1203
     * Gets the minimum value for the given time field. e.g., for Gregorian
1204
     * DAY_OF_MONTH, 1.
1205
     *
1206
     * @param      int    $field The given time field.
1207
     *
1208
     * @return     int    The minimum value for the given time field.
1209
     *
1210
     * @author     Dominik del Bondio <[email protected]>
1211
     * @author     The ICU Project
1212
     * @since      0.11.0
1213
     */
1214
    public function getMinimum($field)
1215
    {
1216
        return $this->getLimit($field, self::LIMIT_MINIMUM);
1217
    }
1218
1219
    /**
1220
     * Gets the maximum value for the given time field. e.g., for Gregorian
1221
     * DAY_OF_MONTH, 31.
1222
     *
1223
     * @param      int    $field The given time field.
1224
     *
1225
     * @return     int    The maximum value for the given time field.
1226
     *
1227
     * @author     Dominik del Bondio <[email protected]>
1228
     * @author     The ICU Project
1229
     * @since      0.11.0
1230
     */
1231
    public function getMaximum($field)
1232
    {
1233
        return $this->getLimit($field, self::LIMIT_MAXIMUM);
1234
    }
1235
1236
    /**
1237
     * Gets the highest minimum value for the given field if varies. Otherwise
1238
     * same as getMinimum(). For Gregorian, no difference.
1239
     *
1240
     * @param      int    $field The given time field.
1241
     *
1242
     * @return     int    The highest minimum value for the given time field.
1243
     *
1244
     * @author     Dominik del Bondio <[email protected]>
1245
     * @author     The ICU Project
1246
     * @since      0.11.0
1247
     */
1248
    public function getGreatestMinimum($field)
1249
    {
1250
        return $this->getLimit($field, self::LIMIT_GREATEST_MINIMUM);
1251
    }
1252
1253
    /**
1254
     * Gets the lowest maximum value for the given field if varies. Otherwise same
1255
     * as getMaximum(). e.g., for Gregorian DAY_OF_MONTH, 28.
1256
     *
1257
     * @param      int    $field The given time field.
1258
     *
1259
     * @return     int    The lowest maximum value for the given time field.
1260
     *
1261
     * @author     Dominik del Bondio <[email protected]>
1262
     * @author     The ICU Project
1263
     * @since      0.11.0
1264
     */
1265
    public function getLeastMaximum($field)
1266
    {
1267
        return $this->getLimit($field, self::LIMIT_LEAST_MAXIMUM);
1268
    }
1269
1270
    /**
1271
     * Return the minimum value that this field could have, given the current
1272
     * date. For the Gregorian calendar, this is the same as getMinimum() and
1273
     * getGreatestMinimum().
1274
     *
1275
     * The version of this function on Calendar uses an iterative algorithm to
1276
     * determine the actual minimum value for the field.  There is almost always a
1277
     * more efficient way to accomplish this (in most cases, you can simply return
1278
     * getMinimum()).  GregorianCalendar overrides this function with a more
1279
     * efficient implementation.
1280
     *
1281
     * @param      int    $field the field to determine the minimum of
1282
     *
1283
     * @return     int    the minimum of the given field for the current date of
1284
     *                    this Calendar
1285
     *
1286
     * @author     Dominik del Bondio <[email protected]>
1287
     * @author     The ICU Project
1288
     * @since      0.11.0
1289
     */
1290
    public function getActualMinimum($field)
1291
    {
1292
        $fieldValue = $this->getGreatestMinimum($field);
1293
        $endValue = $this->getMinimum($field);
1294
1295
        // if we know that the minimum value is always the same, just return it
1296
        if ($fieldValue == $endValue) {
1297
            return $fieldValue;
1298
        }
1299
1300
        // clone the calendar so we don't mess with the real one, and set it to
1301
        // accept anything for the field values
1302
        $work = clone $this;
1303
        $work->setLenient(true);
1304
1305
        // now try each value from getLeastMaximum() to getMaximum() one by one until
1306
        // we get a value that normalizes to another value.	 The last value that
1307
        // normalizes to itself is the actual minimum for the current date
1308
        $result = $fieldValue;
1309
1310 View Code Duplication
        do {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1311
            $work->set($field, $fieldValue);
1312
            if ($work->get($field) != $fieldValue) {
1313
                break;
1314
            } else {
1315
                $result = $fieldValue;
1316
                $fieldValue--;
1317
            }
1318
        } while ($fieldValue >= $endValue);
1319
1320
        return $result;
1321
    }
1322
1323
    /**
1324
     * Return the maximum value that this field could have, given the current
1325
     * date. For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field,
1326
     * the actual maximum would be 28; for "Feb 3, 1996" it s 29.  Similarly for a
1327
     * Hebrew calendar,for some years the actual maximum for MONTH is 12, and for
1328
     * others 13.
1329
     *
1330
     * The version of this function on Calendar uses an iterative algorithm to
1331
     * determine the actual maximum value for the field.  There is almost always a
1332
     * more efficient way to accomplish this (in most cases, you can simply return
1333
     * getMaximum()). AgaviGregorianCalendar overrides this function with a more
1334
     * efficient implementation.
1335
     *
1336
     * @param      int    $field the field to determine the maximum of
1337
     *
1338
     * @return     int    the maximum of the given field for the current date of
1339
     *                    this Calendar
1340
     *
1341
     * @author     Dominik del Bondio <[email protected]>
1342
     * @author     The ICU Project
1343
     * @since      0.11.0
1344
     */
1345
    public function getActualMaximum($field)
1346
    {
1347
        switch ($field) {
1348 View Code Duplication
            case DateDefinitions::DATE:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1349
                $cal = clone $this;
1350
                $cal->prepareGetActual($field, false);
1351
                $result = $this->handleGetMonthLength($cal->get(DateDefinitions::EXTENDED_YEAR), $cal->get(DateDefinitions::MONTH));
1352
                break;
1353
1354 View Code Duplication
            case DateDefinitions::DAY_OF_YEAR:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1355
                $cal = clone $this;
1356
                $cal->prepareGetActual($field, false);
1357
                $result = $this->handleGetYearLength($cal->get(DateDefinitions::EXTENDED_YEAR));
1358
                break;
1359
1360
            case DateDefinitions::DAY_OF_WEEK:
1361
            case DateDefinitions::AM_PM:
1362
            case DateDefinitions::HOUR:
1363
            case DateDefinitions::HOUR_OF_DAY:
1364
            case DateDefinitions::MINUTE:
1365
            case DateDefinitions::SECOND:
1366
            case DateDefinitions::MILLISECOND:
1367
            case DateDefinitions::ZONE_OFFSET:
1368
            case DateDefinitions::DST_OFFSET:
1369
            case DateDefinitions::DOW_LOCAL:
1370
            case DateDefinitions::JULIAN_DAY:
1371
            case DateDefinitions::MILLISECONDS_IN_DAY:
1372
                // These fields all have fixed minima/maxima
1373
                $result = $this->getMaximum($field);
1374
                break;
1375
1376
            default:
1377
                // For all other fields, do it the hard way....
1378
                $result = $this->getActualHelper($field, $this->getLeastMaximum($field), $this->getMaximum($field));
1379
                break;
1380
        }
1381
        return $result;
1382
    }
1383
1384
    /**
1385
     * Gets all time field values. Recalculate the current time field
1386
     * values if the time value has been changed by a call to setTime(). Return
1387
     * zero for unset fields if any fields have been explicitly set by a call to
1388
     * set(). To force a recomputation of all fields regardless of the previous
1389
     * state, call complete().
1390
     *
1391
     * @return     array All fields of this instance.
1392
     *
1393
     * @author     Dominik del Bondio <[email protected]>
1394
     * @author     The ICU Project
1395
     * @since      0.11.0
1396
     */
1397
    public function getAll()
1398
    {
1399
        // field values are only computed when actually requested; for more on when computation
1400
        // of various things happens, see the "data flow in Calendar" description at the top
1401
        // of this file
1402
        $this->complete();
1403
        return $this->fFields;
1404
    }
1405
1406
    /**
1407
     * Gets the value for a given time field. Recalculate the current time field
1408
     * values if the time value has been changed by a call to setTime(). Return
1409
     * zero for unset fields if any fields have been explicitly set by a call to
1410
     * set(). To force a recomputation of all fields regardless of the previous
1411
     * state, call complete().
1412
     *
1413
     * @param      int    $field The given time field.
1414
     *
1415
     * @return     int    The value for the given time field, or zero if the field
1416
     *                    is unset, and set() has been called for any other field.
1417
     *
1418
     * @author     Dominik del Bondio <[email protected]>
1419
     * @author     The ICU Project
1420
     * @since      0.11.0
1421
     */
1422
    public function get($field)
1423
    {
1424
        // field values are only computed when actually requested; for more on when computation
1425
        // of various things happens, see the "data flow in Calendar" description at the top
1426
        // of this file
1427
        $this->complete();
1428
        return $this->fFields[$field];
1429
    }
1430
1431
    /**
1432
     * Determines if the given time field has a value set. This can affect in the
1433
     * resolving of time in Calendar. Unset fields have a value of zero, by
1434
     * definition.
1435
     *
1436
     * @param      int    $field The given time field.
1437
     *
1438
     * @return     bool   True if the given time field has a value set; false
1439
     *                    otherwise.
1440
     *
1441
     * @author     Dominik del Bondio <[email protected]>
1442
     * @author     The ICU Project
1443
     * @since      0.11.0
1444
     */
1445
    public function _isSet($field) // isset is a keyword in php
1446
    {
1447
        return $this->fAreFieldsVirtuallySet || ($this->fStamp[$field] != self::kUnset);
1448
    }
1449
1450
    /**
1451
     * Overloaded
1452
     *
1453
     * @see        Calendar::set1()
1454
     * @see        Calendar::set2()
1455
     * @see        Calendar::set3()
1456
     * @see        Calendar::set4()
1457
     *
1458
     * @author     Dominik del Bondio <[email protected]>
1459
     * @author     The ICU Project
1460
     * @since      0.11.0
1461
     */
1462
    public function set()
1463
    {
1464
        $arguments = func_get_args();
1465
1466
        $fName = Toolkit::overloadHelper(array(
1467
            array('name' => 'set1',
1468
                        'parameters' => array('int', 'int')),
1469
            array('name' => 'set2',
1470
                        'parameters' => array('int', 'int', 'int')),
1471
            array('name' => 'set3',
1472
                        'parameters' => array('int', 'int', 'int', 'int', 'int')),
1473
            array('name' => 'set4',
1474
                        'parameters' => array('int', 'int', 'int', 'int', 'int', 'int')),
1475
            ),
1476
            $arguments
1477
        );
1478
        call_user_func_array(array($this, $fName), $arguments);
1479
    }
1480
1481
    /**
1482
     * Sets the given time field with the given value.
1483
     *
1484
     * @param      int    $field The given time field.
1485
     * @param      int    $value The value to be set for the given time field.
1486
     *
1487
     * @author     Dominik del Bondio <[email protected]>
1488
     * @author     The ICU Project
1489
     * @since      0.11.0
1490
     */
1491 View Code Duplication
    public function set1($field, $value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1492
    {
1493
        if ($this->fAreFieldsVirtuallySet) {
1494
            $this->computeFields();
1495
        }
1496
1497
        $this->fFields[$field]    = $value;
1498
        $this->fStamp[$field]     = $this->fNextStamp++;
1499
        $this->fIsSet[$field]     = true; // Remove later
0 ignored issues
show
Deprecated Code introduced by
The property Agavi\Date\Calendar::$fIsSet has been deprecated with message: ICU 2.8 use (fStamp[n]!=kUnset)

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1500
        $this->fIsTimeSet = $this->fAreFieldsInSync = $this->fAreFieldsVirtuallySet = false;
1501
    }
1502
1503
    /**
1504
     * Sets the values for the fields YEAR, MONTH, and DATE. Other field values
1505
     * are retained; call clear() first if this is not desired.
1506
     *
1507
     * @param      int $year  The value used to set the YEAR time field.
1508
     * @param      int $month The value used to set the MONTH time field. Month value is
1509
     *                        0-based. e.g., 0 for January.
1510
     * @param      int $date  The value used to set the DATE time field.
1511
     *
1512
     * @author     Dominik del Bondio <[email protected]>
1513
     * @author     The ICU Project
1514
     * @since      0.11.0
1515
     */
1516
    public function set2($year, $month, $date)
1517
    {
1518
        $this->set1(DateDefinitions::YEAR, $year);
1519
        $this->set1(DateDefinitions::MONTH, $month);
1520
        $this->set1(DateDefinitions::DATE, $date);
1521
    }
1522
1523
    /**
1524
     * Sets the values for the fields YEAR, MONTH, DATE, HOUR_OF_DAY, and MINUTE.
1525
     * Other field values are retained; call
1526
     * ) first if this is not desired.
1527
     *
1528
     * @param      int $year   The value used to set the YEAR time field.
1529
     * @param      int $month  The value used to set the MONTH time field. Month value is
1530
     *                         0-based. E.g., 0 for January.
1531
     * @param      int $date   The value used to set the DATE time field.
1532
     * @param      int $hour   The value used to set the HOUR_OF_DAY time field.
1533
     * @param      int $minute The value used to set the MINUTE time field.
1534
     *
1535
     * @author     Dominik del Bondio <[email protected]>
1536
     * @author     The ICU Project
1537
     * @since      0.11.0
1538
     */
1539 View Code Duplication
    public function set3($year, $month, $date, $hour, $minute)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1540
    {
1541
        $this->set1(DateDefinitions::YEAR, $year);
1542
        $this->set1(DateDefinitions::MONTH, $month);
1543
        $this->set1(DateDefinitions::DATE, $date);
1544
        $this->set1(DateDefinitions::HOUR_OF_DAY, $hour);
1545
        $this->set1(DateDefinitions::MINUTE, $minute);
1546
    }
1547
1548
    /**
1549
     * Sets the values for the fields YEAR, MONTH, DATE, HOUR_OF_DAY, MINUTE, and
1550
     * SECOND. Other field values are retained; call clear() first if this is not
1551
     * desired.
1552
     *
1553
     * @param      int $year   The value used to set the YEAR time field.
1554
     * @param      int $month  The value used to set the MONTH time field. Month value is
1555
     *                         0-based. E.g., 0 for January.
1556
     * @param      int $date   The value used to set the DATE time field.
1557
     * @param      int $hour   The value used to set the HOUR_OF_DAY time field.
1558
     * @param      int $minute The value used to set the MINUTE time field.
1559
     * @param      int $second The value used to set the SECOND time field.
1560
     *
1561
     * @author     Dominik del Bondio <[email protected]>
1562
     * @author     The ICU Project
1563
     * @since      0.11.0
1564
     */
1565 View Code Duplication
    public function set4($year, $month, $date, $hour, $minute, $second)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1566
    {
1567
        $this->set1(DateDefinitions::YEAR, $year);
1568
        $this->set1(DateDefinitions::MONTH, $month);
1569
        $this->set1(DateDefinitions::DATE, $date);
1570
        $this->set1(DateDefinitions::HOUR_OF_DAY, $hour);
1571
        $this->set1(DateDefinitions::MINUTE, $minute);
1572
        $this->set1(DateDefinitions::SECOND, $second);
1573
    }
1574
1575
    /**
1576
     * Overloaded
1577
     *
1578
     * @see        Calendar::clear1()
1579
     * @see        Calendar::clear2()
1580
     *
1581
     * @author     Dominik del Bondio <[email protected]>
1582
     * @author     The ICU Project
1583
     * @since      0.11.0
1584
     */
1585
    public function clear()
1586
    {
1587
        $arguments = func_get_args();
1588
1589
        $fName = Toolkit::overloadHelper(array(
1590
            array('name' => 'clear1',
1591
                        'parameters' => array()),
1592
            array('name' => 'clear2',
1593
                        'parameters' => array('int')),
1594
            ),
1595
            $arguments
1596
        );
1597
        call_user_func_array(array($this, $fName), $arguments);
1598
    }
1599
1600
    /**
1601
     * Clears the values of all the time fields, making them both unset and
1602
     * assigning them a value of zero. The field values will be determined during
1603
     * the next resolving of time into time fields.
1604
     *
1605
     * @author     Dominik del Bondio <[email protected]>
1606
     * @author     The ICU Project
1607
     * @since      0.11.0
1608
     */
1609
    public function clear1()
1610
    {
1611
        for ($i = 0; $i < DateDefinitions::FIELD_COUNT; ++$i) {
1612
            $this->fFields[$i]     = 0; // Must do this; other code depends on it
1613
            $this->fStamp[$i]      = self::kUnset;
1614
            $this->fIsSet[$i]      = false; // Remove later
0 ignored issues
show
Deprecated Code introduced by
The property Agavi\Date\Calendar::$fIsSet has been deprecated with message: ICU 2.8 use (fStamp[n]!=kUnset)

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1615
        }
1616
        $this->fIsTimeSet = $this->fAreFieldsInSync = $this->fAreAllFieldsSet = $this->fAreFieldsVirtuallySet = false;
1617
        // fTime is not 'cleared' - may be used if no fields are set.
1618
    }
1619
1620
    /**
1621
     * Clears the value in the given time field, both making it unset and
1622
     * assigning it a value of zero. This field value will be determined during
1623
     * the next resolving of time into time fields.
1624
     *
1625
     * @param      string $field The time field to be cleared.
1626
     *
1627
     * @author     Dominik del Bondio <[email protected]>
1628
     * @author     The ICU Project
1629
     * @since      0.11.0
1630
     */
1631 View Code Duplication
    public function clear2($field)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1632
    {
1633
        if ($this->fAreFieldsVirtuallySet) {
1634
            $this->computeFields();
1635
        }
1636
        $this->fFields[$field]        = 0;
1637
        $this->fStamp[$field]         = self::kUnset;
1638
        $this->fIsSet[$field]         = false; // Remove later
0 ignored issues
show
Deprecated Code introduced by
The property Agavi\Date\Calendar::$fIsSet has been deprecated with message: ICU 2.8 use (fStamp[n]!=kUnset)

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1639
        $this->fIsTimeSet = $this->fAreFieldsInSync = $this->fAreAllFieldsSet = $this->fAreFieldsVirtuallySet = false;
1640
    }
1641
1642
    /**
1643
     * Converts Calendar's time field values to GMT as milliseconds.
1644
     *
1645
     * @author     Dominik del Bondio <[email protected]>
1646
     * @author     The ICU Project
1647
     * @since      0.11.0
1648
     */
1649
    protected function computeTime()
1650
    {
1651
        if (!$this->isLenient()) {
1652
            $this->validateFields();
1653
        }
1654
1655
        // Compute the Julian day
1656
        $julianDay = $this->computeJulianDay();
1657
1658
        $millis = CalendarGrego::julianDayToMillis($julianDay);
1659
1660
        $millisInDay = 0;
0 ignored issues
show
Unused Code introduced by
$millisInDay is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1661
1662
        // We only use MILLISECONDS_IN_DAY if it has been set by the user.
1663
        // This makes it possible for the caller to set the calendar to a
1664
        // time and call clear(MONTH) to reset the MONTH to January.  This
1665
        // is legacy behavior.  Without this, clear(MONTH) has no effect,
1666
        // since the internally set JULIAN_DAY is used.
1667
        if ($this->fStamp[DateDefinitions::MILLISECONDS_IN_DAY] >= (self::kMinimumUserStamp) &&
1668
                $this->newestStamp(DateDefinitions::AM_PM, DateDefinitions::MILLISECOND, self::kUnset) <= $this->fStamp[DateDefinitions::MILLISECONDS_IN_DAY]) {
1669
            $millisInDay = $this->internalGet(DateDefinitions::MILLISECONDS_IN_DAY);
1670
        } else {
1671
            $millisInDay = $this->computeMillisInDay();
1672
        }
1673
1674
        // Compute the time zone offset and DST offset.  There are two potential
1675
        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
1676
        // for discussion purposes here.
1677
        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
1678
        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
1679
        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
1680
        //    We assume standard time.
1681
        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
1682
        //    can be in standard or DST.  Both are valid representations (the rep
1683
        //    jumps from 1:59:59 DST to 1:00:00 Std).
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1684
        //    Again, we assume standard time.
1685
        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
1686
        // or DST_OFFSET fields; then we use those fields.
1687
        if ($this->fStamp[DateDefinitions::ZONE_OFFSET] >= (self::kMinimumUserStamp) ||
1688
                $this->fStamp[DateDefinitions::DST_OFFSET] >= (self::kMinimumUserStamp)) {
1689
            $millisInDay -= $this->internalGet(DateDefinitions::ZONE_OFFSET) + $this->internalGet(DateDefinitions::DST_OFFSET);
1690
        } else {
1691
            $millisInDay -= $this->computeZoneOffset($millis, $millisInDay);
1692
        }
1693
1694
        $this->internalSetTime($millis + $millisInDay);
1695
    }
1696
1697
    /**
1698
     * Converts GMT as milliseconds to time field values. This allows you to sync
1699
     * up the time field values with a new time that is set for the calendar.
1700
     * This method does NOT recompute the time first; to recompute the time, then
1701
     * the fields, use the method complete().
1702
     *
1703
     * @author     Dominik del Bondio <[email protected]>
1704
     * @author     The ICU Project
1705
     * @since      0.11.0
1706
     */
1707
    protected function computeFields()
1708
    {
1709
        // Compute local wall millis
1710
        $localMillis = $this->internalGetTime();
1711
1712
        $rawOffset = $dstOffset = 0;
1713
        $this->getTimeZone()->getOffsetRef($localMillis, false, $rawOffset, $dstOffset);
1714
        $localMillis += $rawOffset;
1715
1716
        // Mark fields as set.  Do this before calling handleComputeFields().
1717
        $mask =   //fInternalSetMask;
1718
            (1 << DateDefinitions::ERA) |
1719
            (1 << DateDefinitions::YEAR) |
1720
            (1 << DateDefinitions::MONTH) |
1721
            (1 << DateDefinitions::DAY_OF_MONTH) | // = UCAL_DATE
1722
            (1 << DateDefinitions::DAY_OF_YEAR) |
1723
            (1 << DateDefinitions::EXTENDED_YEAR);
1724
1725
        for ($i = 0; $i < DateDefinitions::FIELD_COUNT; ++$i) {
1726
            if (($mask & 1) == 0) {
1727
                $this->fStamp[$i] = self::kInternallySet;
1728
                $this->fIsSet[$i] = true; // Remove later
0 ignored issues
show
Deprecated Code introduced by
The property Agavi\Date\Calendar::$fIsSet has been deprecated with message: ICU 2.8 use (fStamp[n]!=kUnset)

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1729
            } else {
1730
                $this->fStamp[$i] = self::kUnset;
1731
                $this->fIsSet[$i] = false; // Remove later
0 ignored issues
show
Deprecated Code introduced by
The property Agavi\Date\Calendar::$fIsSet has been deprecated with message: ICU 2.8 use (fStamp[n]!=kUnset)

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1732
            }
1733
            $mask >>= 1;
1734
        }
1735
1736
        // We used to check for and correct extreme millis values (near
1737
        // Long.MIN_VALUE or Long.MAX_VALUE) here.  Such values would cause
1738
        // overflows from positive to negative (or vice versa) and had to
1739
        // be manually tweaked.  We no longer need to do this because we
1740
        // have limited the range of supported dates to those that have a
1741
        // Julian day that fits into an int.  This allows us to implement a
1742
        // JULIAN_DAY field and also removes some inelegant code. - Liu
1743
        // 11/6/00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1744
1745
        $days = floor($localMillis / DateDefinitions::MILLIS_PER_DAY);
1746
1747
        $this->internalSet(DateDefinitions::JULIAN_DAY, $days + DateDefinitions::EPOCH_START_AS_JULIAN_DAY);
1748
1749
        // In some cases we will have to call this method again below to
1750
        // adjust for DST pushing us into the next Julian day.
1751
        $this->computeGregorianAndDOWFields($this->fFields[DateDefinitions::JULIAN_DAY]);
1752
1753
        $millisInDay =  (int) ($localMillis - ($days * DateDefinitions::MILLIS_PER_DAY));
1754
        if ($millisInDay < 0) {
1755
            $millisInDay += (int) DateDefinitions::MILLIS_PER_DAY;
1756
        }
1757
1758
        // Adjust our millisInDay for DST.  dstOffset will be zero if DST
1759
        // is not in effect at this time of year, or if our zone does not
1760
        // use DST.
1761
        $millisInDay += $dstOffset;
1762
1763
        // If DST has pushed us into the next day, we must call
1764
        // computeGregorianAndDOWFields() again.  This happens in DST between
1765
        // 12:00 am and 1:00 am every day.  The first call to
1766
        // computeGregorianAndDOWFields() will give the wrong day, since the
1767
        // Standard time is in the previous day.
1768
        if ($millisInDay >= (int) DateDefinitions::MILLIS_PER_DAY) {
1769
            $millisInDay -= (int) DateDefinitions::MILLIS_PER_DAY; // ASSUME dstOffset < 24:00
1770
1771
            // We don't worry about overflow of JULIAN_DAY because the
1772
            // allowable range of JULIAN_DAY has slop at the ends (that is,
1773
            // the max is less that 0x7FFFFFFF and the min is greater than
1774
            // -0x80000000).
1775
            $this->computeGregorianAndDOWFields(++$this->fFields[DateDefinitions::JULIAN_DAY]);
1776
        }
1777
1778
        // Call framework method to have subclass compute its fields.
1779
        // These must include, at a minimum, MONTH, DAY_OF_MONTH,
1780
        // EXTENDED_YEAR, YEAR, DAY_OF_YEAR.  This method will call internalSet(),
1781
        // which will update stamp[].
1782
        $this->handleComputeFields($this->fFields[DateDefinitions::JULIAN_DAY]);
1783
1784
        // Compute week-related fields, based on the subclass-computed
1785
        // fields computed by handleComputeFields().
1786
        $this->computeWeekFields();
1787
1788
        // Compute time-related fields.  These are independent of the date and
1789
        // of the subclass algorithm.  They depend only on the local zone
1790
        // wall milliseconds in day.
1791
        $this->fFields[DateDefinitions::MILLISECONDS_IN_DAY] = $millisInDay;
1792
        $this->fFields[DateDefinitions::MILLISECOND] = $millisInDay % 1000;
1793
        $millisInDay /= 1000;
1794
        $this->fFields[DateDefinitions::SECOND] = $millisInDay % 60;
1795
        $millisInDay /= 60;
1796
        $this->fFields[DateDefinitions::MINUTE] = $millisInDay % 60;
1797
        $millisInDay /= 60;
1798
        $this->fFields[DateDefinitions::HOUR_OF_DAY] = (int) $millisInDay;
1799
        $this->fFields[DateDefinitions::AM_PM] = (int) ($millisInDay / 12); // Assume AM == 0
1800
        $this->fFields[DateDefinitions::HOUR] = $millisInDay % 12;
1801
        $this->fFields[DateDefinitions::ZONE_OFFSET] = $rawOffset;
1802
        $this->fFields[DateDefinitions::DST_OFFSET] = $dstOffset;
1803
    }
1804
1805
    /**
1806
     * Gets this Calendar's current time as a long.
1807
     *
1808
     * @return     double the current time as UTC milliseconds from the epoch.
1809
     *
1810
     * @author     Dominik del Bondio <[email protected]>
1811
     * @author     The ICU Project
1812
     * @since      0.11.0
1813
     */
1814
    protected function getTimeInMillis()
1815
    {
1816
        if (!$this->fIsTimeSet) {
1817
            $this->updateTime();
1818
        }
1819
1820
        return $this->fTime;
1821
    }
1822
1823
    /**
1824
     * Sets this Calendar's current time from the given long value.
1825
     *
1826
     * @param      double $millis the new time in UTC milliseconds from the epoch.
1827
     *
1828
     * @author     Dominik del Bondio <[email protected]>
1829
     * @author     The ICU Project
1830
     * @since      0.11.0
1831
     */
1832
    protected function setTimeInMillis($millis)
1833
    {
1834
        $millis = (float) $millis;
1835
        
1836
        if ($millis > self::MAX_MILLIS) {
1837
            $millis = self::MAX_MILLIS;
1838
        } elseif ($millis < self::MIN_MILLIS) {
1839
            $millis = self::MIN_MILLIS;
1840
        }
1841
1842
        $this->fTime = $millis;
0 ignored issues
show
Documentation Bug introduced by
It seems like $millis can also be of type integer. However, the property $fTime is declared as type double. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1843
        $this->fAreFieldsInSync = $this->fAreAllFieldsSet = false;
1844
        $this->fIsTimeSet = $this->fAreFieldsVirtuallySet = true;
1845
    }
1846
1847
    /**
1848
     * Recomputes the current time from currently set fields, and then fills in
1849
     * any unset fields in the time field list.
1850
     *
1851
     * @author     Dominik del Bondio <[email protected]>
1852
     * @author     The ICU Project
1853
     * @since      0.11.0
1854
     */
1855
    protected function complete()
1856
    {
1857
        if (!$this->fIsTimeSet) {
1858
            $this->updateTime();
1859
        }
1860
1861
        if (!$this->fAreFieldsInSync) {
1862
            $this->computeFields(); // fills in unset fields
1863
1864
            $this->fAreFieldsInSync        = true;
1865
            $this->fAreAllFieldsSet     = true;
1866
        }
1867
    }
1868
1869
    /**
1870
     * Gets the value for a given time field. Subclasses can use this function to
1871
     * get field values without forcing recomputation of time. If the field's
1872
     * stamp is UNSET, the defaultValue is used.
1873
     *
1874
     * @param      int    $field        The given time field.
1875
     * @param      int    $defaultValue a default value used if the field is unset.
1876
     * @return     int    The value for the given time field.
1877
     *
1878
     * @author     Dominik del Bondio <[email protected]>
1879
     * @author     The ICU Project
1880
     * @since      0.11.0
1881
     */
1882
    protected function internalGet($field, $defaultValue = null)
1883
    {
1884
        return $this->fStamp[$field] > self::kUnset ? $this->fFields[$field] : $defaultValue;
1885
    }
1886
1887
    /**
1888
     * Sets the value for a given time field.  This is a fast internal method for
1889
     * subclasses.  It does not affect the fAreFieldsInSync, isTimeSet, or
1890
     * areAllFieldsSet flags.
1891
     *
1892
     * @param      int    $field The given time field.
1893
     * @param      int    $value The value for the given time field.
1894
     *
1895
     * @author     Dominik del Bondio <[email protected]>
1896
     * @author     The ICU Project
1897
     * @since      0.11.0
1898
     */
1899
    protected function internalSet($field, $value)
1900
    {
1901
        $this->fFields[$field]  = $value;
1902
        $this->fStamp[$field]   = self::kInternallySet;
1903
        $this->fIsSet[$field]   = true; // Remove later
0 ignored issues
show
Deprecated Code introduced by
The property Agavi\Date\Calendar::$fIsSet has been deprecated with message: ICU 2.8 use (fStamp[n]!=kUnset)

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1904
    }
1905
1906
    /**
1907
     * Prepare this calendar for computing the actual minimum or maximum.
1908
     * This method modifies this calendar's fields; it is called on a
1909
     * temporary calendar.
1910
     *
1911
     * @param      int   $field     The given time field
1912
     * @param      bool  $isMinimum
1913
     *
1914
     * @author     Dominik del Bondio <[email protected]>
1915
     * @author     The ICU Project
1916
     * @since      0.11.0
1917
     */
1918
    protected function prepareGetActual($field, $isMinimum)
1919
    {
1920
        $this->set(DateDefinitions::MILLISECONDS_IN_DAY, 0);
1921
1922
        switch ($field) {
1923
            case DateDefinitions::YEAR:
1924
            case DateDefinitions::YEAR_WOY:
1925
            case DateDefinitions::EXTENDED_YEAR:
1926
                $this->set(DateDefinitions::DAY_OF_YEAR, $this->getGreatestMinimum(DateDefinitions::DAY_OF_YEAR));
1927
                break;
1928
1929
            case DateDefinitions::MONTH:
1930
                $this->set(DateDefinitions::DATE, $this->getGreatestMinimum(DateDefinitions::DATE));
1931
                break;
1932
1933
            case DateDefinitions::DAY_OF_WEEK_IN_MONTH:
1934
                // For dowim, the maximum occurs for the DOW of the first of the
1935
                // month.
1936
                $this->set(DateDefinitions::DATE, 1);
1937
                $this->set(DateDefinitions::DAY_OF_WEEK, $this->get(DateDefinitions::DAY_OF_WEEK)); // Make this user set
1938
                break;
1939
1940
            case DateDefinitions::WEEK_OF_MONTH:
1941
            case DateDefinitions::WEEK_OF_YEAR:
1942
                // If we're counting weeks, set the day of the week to either the
1943
                // first or last localized DOW.  We know the last week of a month
1944
                // or year will contain the first day of the week, and that the
1945
                // first week will contain the last DOW.
1946
                $dow = $this->fFirstDayOfWeek;
1947
                if ($isMinimum) {
1948
                    $dow = ($dow + 6) % 7; // set to last DOW
1949
                    if ($dow < DateDefinitions::SUNDAY) {
1950
                        $dow += 7;
1951
                    }
1952
                }
1953
1954
                $this->set(DateDefinitions::DAY_OF_WEEK, $dow);
1955
                break;
1956
            default:
1957
                ;
1958
        }
1959
1960
        // Do this last to give it the newest time stamp
1961
        $this->set($field, $this->getGreatestMinimum($field));
1962
    }
1963
1964
    /**
1965
     * Subclass API for defining limits of different types.
1966
     * Subclasses must implement this method to return limits for the
1967
     * following fields:
1968
     *
1969
     * <pre>DateDefinitions::ERA
1970
     * DateDefinitions::YEAR
1971
     * DateDefinitions::MONTH
1972
     * DateDefinitions::WEEK_OF_YEAR
1973
     * DateDefinitions::WEEK_OF_MONTH
1974
     * DateDefinitions::DATE
1975
     * DateDefinitions::DAY_OF_YEAR
1976
     * DateDefinitions::DAY_OF_WEEK_IN_MONTH
1977
     * DateDefinitions::YEAR_WOY
1978
     * DateDefinitions::EXTENDED_YEAR</pre>
1979
     *
1980
     * @param      int $field     one of the above field numbers
1981
     * @param      int $limitType one of <code>self::LIMIT_MINIMUM</code>,
1982
     *                            <code>self::LIMIT_GREATEST_MINIMUM</code>,
1983
     *                            <code>self::LIMIT_LEAST_MAXIMUM</code>,
1984
     *                            or <code>self::LIMIT_MAXIMUM</code>
1985
     *
1986
     * @return     int
1987
     *
1988
     * @author     Dominik del Bondio <[email protected]>
1989
     * @author     The ICU Project
1990
     * @since      0.11.0
1991
     */
1992
    abstract protected function handleGetLimit($field, $limitType);
1993
1994
    /**
1995
     * Return a limit for a field.
1996
     *
1997
     * @param      int $field     the field
1998
     * @param      int $limitType the type specifier for the limit
1999
     *
2000
     * @return     int
2001
     *
2002
     * @author     Dominik del Bondio <[email protected]>
2003
     * @author     The ICU Project
2004
     * @since      0.11.0
2005
     */
2006
    protected function getLimit($field, $limitType)
2007
    {
2008
        switch ($field) {
2009
            case DateDefinitions::DAY_OF_WEEK:
2010
            case DateDefinitions::AM_PM:
2011
            case DateDefinitions::HOUR:
2012
            case DateDefinitions::HOUR_OF_DAY:
2013
            case DateDefinitions::MINUTE:
2014
            case DateDefinitions::SECOND:
2015
            case DateDefinitions::MILLISECOND:
2016
            case DateDefinitions::ZONE_OFFSET:
2017
            case DateDefinitions::DST_OFFSET:
2018
            case DateDefinitions::DOW_LOCAL:
2019
            case DateDefinitions::JULIAN_DAY:
2020
            case DateDefinitions::MILLISECONDS_IN_DAY:
2021
                return self::$kCalendarLimits[$field][$limitType];
2022
            default:
2023
                return $this->handleGetLimit($field, $limitType);
2024
        }
2025
    }
2026
2027
    /**
2028
     * Return the Julian day number of day before the first day of the
2029
     * given month in the given extended year.  Subclasses should override
2030
     * this method to implement their calendar system.
2031
     *
2032
     * @param      int  $eyear the extended year
2033
     * @param      int  $month the zero-based month, or 0 if useMonth is false
2034
     * @param      bool $useMonth if false, compute the day before the first day of
2035
     *                  the given year, otherwise, compute the day before the
2036
     *                  first day of the given month
2037
     *
2038
     * @return     int  the Julian day number of the day before the first
2039
     *                  day of the given month and year
2040
     *
2041
     * @author     Dominik del Bondio <[email protected]>
2042
     * @author     The ICU Project
2043
     * @since      0.11.0
2044
     */
2045
    abstract protected function handleComputeMonthStart($eyear, $month, $useMonth);
2046
2047
    /**
2048
     * Return the number of days in the given month of the given extended
2049
     * year of this calendar system.  Subclasses should override this
2050
     * method if they can provide a more correct or more efficient
2051
     * implementation than the default implementation in Calendar.
2052
     *
2053
     * @author     Dominik del Bondio <[email protected]>
2054
     * @author     The ICU Project
2055
     * @since      0.11.0
2056
     */
2057
    protected function handleGetMonthLength($extendedYear, $month)
2058
    {
2059
        return $this->handleComputeMonthStart($extendedYear, $month + 1, true) -
2060
                        $this->handleComputeMonthStart($extendedYear, $month, true);
2061
    }
2062
2063
    /**
2064
     * Return the number of days in the given extended year of this
2065
     * calendar system.  Subclasses should override this method if they can
2066
     * provide a more correct or more efficient implementation than the
2067
     * default implementation in Calendar.
2068
     *
2069
     * @author     Dominik del Bondio <[email protected]>
2070
     * @author     The ICU Project
2071
     * @since      0.11.0
2072
     */
2073
    protected function handleGetYearLength($eyear)
2074
    {
2075
        return $this->handleComputeMonthStart($eyear + 1, 0, false) -
2076
                        $this->handleComputeMonthStart($eyear, 0, false);
2077
    }
2078
2079
    /**
2080
     * Return the extended year defined by the current fields.  This will
2081
     * use the EXTENDED_YEAR field or the YEAR and supra-year fields
2082
     * (such as ERA) specific to the calendar system, depending on which set
2083
     * of fields is newer.
2084
     *
2085
     * @return     int the extended year
2086
     *
2087
     * @author     Dominik del Bondio <[email protected]>
2088
     * @author     The ICU Project
2089
     * @since      0.11.0
2090
     */
2091
    abstract protected function handleGetExtendedYear();
2092
2093
    /**
2094
     * Subclasses may override this.  This method calls
2095
     * handleGetMonthLength() to obtain the calendar-specific month
2096
     * length.
2097
     *
2098
     * @param      string $bestField which field to use to calculate the date
2099
     *
2100
     * @return     int    julian day specified by calendar fields.
2101
     *
2102
     * @author     Dominik del Bondio <[email protected]>
2103
     * @author     The ICU Project
2104
     * @since      0.11.0
2105
     */
2106
    protected function handleComputeJulianDay($bestField)
2107
    {
2108
        $useMonth = ($bestField == DateDefinitions::DAY_OF_MONTH ||
2109
                                    $bestField == DateDefinitions::WEEK_OF_MONTH ||
2110
                                    $bestField == DateDefinitions::DAY_OF_WEEK_IN_MONTH);
2111
        $year = 0;
0 ignored issues
show
Unused Code introduced by
$year is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2112
2113
        if ($bestField == DateDefinitions::WEEK_OF_YEAR) {
2114
            $year = $this->internalGet(DateDefinitions::YEAR_WOY, $this->handleGetExtendedYear());
2115
            $this->internalSet(DateDefinitions::EXTENDED_YEAR, $year);
2116
        } else {
2117
            $year = $this->handleGetExtendedYear();
2118
            $this->internalSet(DateDefinitions::EXTENDED_YEAR, $year);
2119
        }
2120
2121
        // Get the Julian day of the day BEFORE the start of this year.
2122
        // If useMonth is true, get the day before the start of the month.
2123
2124
        // give calendar subclass a chance to have a default 'first' month
2125
        $month = 0;
0 ignored issues
show
Unused Code introduced by
$month is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2126
2127
        if ($this->_isSet(DateDefinitions::MONTH)) {
2128
            $month = $this->internalGet(DateDefinitions::MONTH);
2129
        } else {
2130
            $month = $this->getDefaultMonthInYear();
2131
        }
2132
2133
        $julianDay = $this->handleComputeMonthStart($year, $useMonth ? $month : 0, $useMonth);
2134
2135
        if ($bestField == DateDefinitions::DAY_OF_MONTH) {
2136
            // give calendar subclass a chance to have a default 'first' dom
2137
            $dayOfMonth = 0;
0 ignored issues
show
Unused Code introduced by
$dayOfMonth is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2138
            if ($this->_isSet(DateDefinitions::DAY_OF_MONTH)) {
2139
                $dayOfMonth = $this->internalGet(DateDefinitions::DAY_OF_MONTH, 1);
2140
            } else {
2141
                $dayOfMonth = $this->getDefaultDayInMonth($month);
2142
            }
2143
2144
            return $julianDay + $dayOfMonth;
2145
        }
2146
2147
        if ($bestField == DateDefinitions::DAY_OF_YEAR) {
2148
            return $julianDay + $this->internalGet(DateDefinitions::DAY_OF_YEAR);
2149
        }
2150
2151
        $firstDayOfWeek = $this->getFirstDayOfWeek(); // Localized fdw
2152
2153
        // At this point julianDay is the 0-based day BEFORE the first day of
2154
        // January 1, year 1 of the given calendar.  If julianDay == 0, it
2155
        // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
2156
        // or Gregorian). (or it is before the month we are in, if useMonth is True)
2157
2158
        // At this point we need to process the WEEK_OF_MONTH or
2159
        // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH.
2160
        // First, perform initial shared computations.  These locate the
2161
        // first week of the period.
2162
2163
        // Get the 0-based localized DOW of day one of the month or year.
2164
        // Valid range 0..6.
2165
        $first = $this->julianDayToDayOfWeek($julianDay + 1) - $firstDayOfWeek;
2166
        if ($first < 0) {
2167
            $first += 7;
2168
        }
2169
2170
        $dowLocal = $this->getLocalDOW();
2171
2172
        // Find the first target DOW (dowLocal) in the month or year.
2173
        // Actually, it may be just before the first of the month or year.
2174
        // It will be an integer from -5..7.
2175
        $date = 1 - $first + $dowLocal;
2176
2177
        if ($bestField == DateDefinitions::DAY_OF_WEEK_IN_MONTH) {
2178
            // Adjust the target DOW to be in the month or year.
2179
            if ($date < 1) {
2180
                $date += 7;
2181
            }
2182
2183
            // The only trickiness occurs if the day-of-week-in-month is
2184
            // negative.
2185
            $dim = $this->internalGet(DateDefinitions::DAY_OF_WEEK_IN_MONTH, 1);
2186
            if ($dim >= 0) {
2187
                $date += 7 * ($dim - 1);
2188
            } else {
2189
                // Move date to the last of this day-of-week in this month,
2190
                // then back up as needed.  If dim==-1, we don't back up at
2191
                // all.  If dim==-2, we back up once, etc.  Don't back up
2192
                // past the first of the given day-of-week in this month.
2193
                // Note that we handle -2, -3, etc. correctly, even though
2194
                // values < -1 are technically disallowed.
2195
                $m = $this->internalGet(DateDefinitions::MONTH, DateDefinitions::JANUARY);
2196
                $monthLength = $this->handleGetMonthLength($year, $m);
2197
                $date += ((int)(($monthLength - $date) / 7) + $dim + 1) * 7;
2198
            }
2199
        } else {
2200
            if ($bestField == DateDefinitions::WEEK_OF_YEAR) {  // ------------------------------------- WOY -------------
2201
                if (!$this->_isSet(DateDefinitions::YEAR_WOY) ||  // YWOY not set at all or
2202
                    (
2203
                        ($this->resolveFields(self::$kYearPrecedence) != DateDefinitions::YEAR_WOY) // YWOY doesn't have precedence
2204
                        && ($this->fStamp[DateDefinitions::YEAR_WOY] != self::kInternallySet) // (excluding where all fields are internally set - then YWOY is used)
2205
                    )
2206
                ) {
2207
                    // need to be sure to stay in 'real' year.
2208
                    $woy = $this->internalGet($bestField);
2209
2210
                    $nextJulianDay = $this->handleComputeMonthStart($year + 1, 0, false); // jd of day before jan 1
2211
                    $nextFirst = $this->julianDayToDayOfWeek($nextJulianDay + 1) - $firstDayOfWeek;
2212
2213
                    if ($nextFirst < 0) { // 0..6 ldow of Jan 1
2214
                        $nextFirst += 7;
2215
                    }
2216
2217
                    if ($woy == 1) {  // FIRST WEEK ---------------------------------
2218
2219
                        // nextFirst is now the localized DOW of Jan 1  of y-woy+1
2220 View Code Duplication
                        if (($nextFirst > 0) &&   // Jan 1 starts on FDOW
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2221
                            (7 - $nextFirst) >= $this->getMinimalDaysInFirstWeek() // or enough days in the week
2222
                        ) {
2223
                            // Jan 1 of (yearWoy+1) is in yearWoy+1 - recalculate JD to next year
2224
                            $julianDay = $nextJulianDay;
2225
2226
                            // recalculate 'first' [0-based local dow of jan 1]
2227
                            $first = $this->julianDayToDayOfWeek($julianDay + 1) - $firstDayOfWeek;
2228
                            if ($first < 0) {
2229
                                $first += 7;
2230
                            }
2231
                            // recalculate date.
2232
                            $date = 1 - $first + $dowLocal;
2233
                        }
2234
                    } elseif ($woy >= $this->getLeastMaximum($bestField)) {
2235
                        // could be in the last week- find out if this JD would overstep
2236
                        $testDate = $date;
2237
                        if ((7 - $first) < $this->getMinimalDaysInFirstWeek()) {
2238
                            $testDate += 7;
2239
                        }
2240
2241
                        // Now adjust for the week number.
2242
                        $testDate += 7 * ($woy - 1);
2243
2244 View Code Duplication
                        if ($julianDay + $testDate > $nextJulianDay) { // is it past Dec 31?  (nextJulianDay is day BEFORE year+1's  Jan 1)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2245
                            // Fire up the calculating engines.. retry YWOY = (year-1)
2246
                            $julianDay = $this->handleComputeMonthStart($year - 1, 0, false); // jd before Jan 1 of previous year
2247
                            $first = $this->julianDayToDayOfWeek($julianDay + 1) - $firstDayOfWeek; // 0 based local dow   of first week
2248
2249
                            if ($first < 0) { // 0..6
2250
                                $first += 7;
2251
                            }
2252
                            $date = 1 - $first + $dowLocal;
2253
                        } /* correction needed */
2254
                    } /* leastmaximum */
2255
                } /* resolvefields(year) != year_woy */
2256
            } /* bestfield != week_of_year */
2257
2258
            // assert(bestField == WEEK_OF_MONTH || bestField == WEEK_OF_YEAR)
2259
            // Adjust for minimal days in first week
2260
            if ((7 - $first) < $this->getMinimalDaysInFirstWeek()) {
2261
                $date += 7;
2262
            }
2263
2264
            // Now adjust for the week number.
2265
            $date += 7 * ($this->internalGet($bestField) - 1);
2266
        }
2267
2268
        return $julianDay + $date;
2269
    }
2270
2271
    /**
2272
     * Subclasses must override this to convert from week fields
2273
     * (YEAR_WOY and WEEK_OF_YEAR) to an extended year in the case
2274
     * where YEAR, EXTENDED_YEAR are not set.
2275
     * The Calendar implementation assumes yearWoy is in extended gregorian form
2276
     *
2277
     * @internal
2278
     *
2279
     * @param      int $yearWoy
2280
     * @param      int $woy
2281
     *
2282
     * @return     int the extended year, UCAL_EXTENDED_YEAR
2283
     *
2284
     * @author     Dominik del Bondio <[email protected]>
2285
     * @author     The ICU Project
2286
     * @since      0.11.0
2287
     */
2288
    protected function handleGetExtendedYearFromWeekFields($yearWoy, $woy)
2289
    {
2290
        // We have UCAL_YEAR_WOY and UCAL_WEEK_OF_YEAR - from those, determine
2291
        // what year we fall in, so that other code can set it properly.
2292
        // (code borrowed from computeWeekFields and handleComputeJulianDay)
2293
        //return yearWoy;
2294
2295
        // First, we need a reliable DOW.
2296
        $bestField = $this->resolveFields(self::$kDatePrecedence); // !! Note: if subclasses have a different table, they should override handleGetExtendedYearFromWeekFields
2297
2298
        // Now, a local DOW
2299
        $dowLocal = $this->getLocalDOW(); // 0..6
2300
        $firstDayOfWeek = $this->getFirstDayOfWeek(); // Localized fdw
2301
        $jan1Start = $this->handleComputeMonthStart($yearWoy, 0, false);
2302
        $nextJan1Start = $this->handleComputeMonthStart($yearWoy + 1, 0, false); // next year's Jan1 start
2303
2304
        // At this point julianDay is the 0-based day BEFORE the first day of
2305
        // January 1, year 1 of the given calendar.  If julianDay == 0, it
2306
        // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
2307
        // or Gregorian). (or it is before the month we are in, if useMonth is True)
2308
2309
        // At this point we need to process the WEEK_OF_MONTH or
2310
        // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH.
2311
        // First, perform initial shared computations.  These locate the
2312
        // first week of the period.
2313
2314
        // Get the 0-based localized DOW of day one of the month or year.
2315
        // Valid range 0..6.
2316
        $first = $this->julianDayToDayOfWeek($jan1Start + 1) - $firstDayOfWeek;
2317
        if ($first < 0) {
2318
            $first += 7;
2319
        }
2320
        $nextFirst = $this->julianDayToDayOfWeek($nextJan1Start + 1) - $firstDayOfWeek;
2321
        if ($nextFirst < 0) {
2322
            $nextFirst += 7;
2323
        }
2324
2325
        $minDays = $this->getMinimalDaysInFirstWeek();
2326
        $jan1InPrevYear = false;  // January 1st in the year of WOY is the 1st week?  (i.e. first week is < minimal )
2327
        //UBool nextJan1InPrevYear = false; // January 1st of Year of WOY + 1 is in the first week?
2328
2329
        if ((7 - $first) < $minDays) {
2330
            $jan1InPrevYear = true;
2331
        }
2332
2333
        //   if((7 - nextFirst) < minDays) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2334
        //     nextJan1InPrevYear = true;
2335
        //   }
2336
2337
        switch ($bestField) {
2338
            case DateDefinitions::WEEK_OF_YEAR:
2339
                if ($woy == 1) {
2340
                    if ($jan1InPrevYear == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2341
                        // the first week of January is in the previous year
2342
                        // therefore WOY1 is always solidly within yearWoy
2343
                        return $yearWoy;
2344
                    } else {
2345
                        // First WOY is split between two years
2346
                        if ($dowLocal < $first) { // we are prior to Jan 1
2347
                            return $yearWoy - 1; // previous year
2348
                        } else {
2349
                            return $yearWoy; // in this year
2350
                        }
2351
                    }
2352
                } elseif ($woy >= $this->getLeastMaximum($bestField)) {
2353
                    // we _might_ be in the last week..
2354
                    $jd =  // Calculate JD of our target day:
2355
                                $jan1Start +  // JD of Jan 1
2356
                                (7 - $first) + //  days in the first week (Jan 1.. )
2357
                                ($woy - 1) * 7 + // add the weeks of the year
2358
                                $dowLocal;   // the local dow (0..6) of last week
2359
                    if ($jan1InPrevYear == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2360
                        $jd -= 7; // woy already includes Jan 1's week.
2361
                    }
2362
2363
                    if (($jd + 1) >= $nextJan1Start) {
2364
                        // we are in week 52 or 53 etc. - actual year is yearWoy+1
2365
                        return $yearWoy + 1;
2366
                    } else {
2367
                        // still in yearWoy;
2368
                        return $yearWoy;
2369
                    }
2370
                } else {
2371
                    // we're not possibly in the last week -must be ywoy
2372
                    return $yearWoy;
2373
                }
2374
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2375
2376
            case DateDefinitions::DATE:
2377
                if (($this->internalGet(DateDefinitions::MONTH)==0) &&
2378
                        ($woy >= $this->getLeastMaximum(DateDefinitions::WEEK_OF_YEAR))) {
2379
                    return $yearWoy + 1; // month 0, late woy = in the next year
2380
                } elseif ($woy == 1) {
2381
                    //if(nextJan1InPrevYear) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2382
                    if ($this->internalGet(DateDefinitions::MONTH)==0) {
2383
                        return $yearWoy;
2384
                    } else {
2385
                        return $yearWoy - 1;
2386
                    }
2387
                    //}
2388
                }
2389
2390
                //(internalGet(UCAL_DATE) <= (7-first)) /* && in minDow  */ ) {
2391
                //within 1st week and in this month..
2392
                //return yearWoy+1;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2393
                return $yearWoy;
2394
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2395
2396
            default: // assume the year is appropriate
2397
                return $yearWoy;
2398
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2399
        }
2400
    }
2401
2402
    /**
2403
     * Compute the Julian day from fields.  Will determine whether to use
2404
     * the JULIAN_DAY field directly, or other fields.
2405
     *
2406
     * @return     int the julian day
2407
     *
2408
     * @author     Dominik del Bondio <[email protected]>
2409
     * @author     The ICU Project
2410
     * @since      0.11.0
2411
     */
2412
    protected function computeJulianDay()
2413
    {
2414
        // We want to see if any of the date fields is newer than the
2415
        // JULIAN_DAY.  If not, then we use JULIAN_DAY.  If so, then we do
2416
        // the normal resolution.  We only use JULIAN_DAY if it has been
2417
        // set by the user.  This makes it possible for the caller to set
2418
        // the calendar to a time and call clear(MONTH) to reset the MONTH
2419
        // to January.  This is legacy behavior.  Without this,
2420
        // clear(MONTH) has no effect, since the internally set JULIAN_DAY
2421
        // is used.
2422
        if ($this->fStamp[DateDefinitions::JULIAN_DAY] >= (int)self::kMinimumUserStamp) {
2423
            $bestStamp = $this->newestStamp(DateDefinitions::ERA, DateDefinitions::DAY_OF_WEEK_IN_MONTH, self::kUnset);
2424
            $bestStamp = $this->newestStamp(DateDefinitions::YEAR_WOY, DateDefinitions::EXTENDED_YEAR, $bestStamp);
2425
            if ($bestStamp <= $this->fStamp[DateDefinitions::JULIAN_DAY]) {
2426
                return $this->internalGet(DateDefinitions::JULIAN_DAY);
2427
            }
2428
        }
2429
2430
        $bestField = $this->resolveFields($this->getFieldResolutionTable());
2431
        if ($bestField == DateDefinitions::FIELD_COUNT) {
2432
            $bestField = DateDefinitions::DAY_OF_MONTH;
2433
        }
2434
2435
        return $this->handleComputeJulianDay($bestField);
2436
    }
2437
2438
    /**
2439
     * Compute the milliseconds in the day from the fields.  This is a
2440
     * value from 0 to 23:59:59.999 inclusive, unless fields are out of
2441
     * range, in which case it can be an arbitrary value.  This value
2442
     * reflects local zone wall time.
2443
     *
2444
     * @return     int The milliseconds in the day
2445
     *
2446
     * @author     Dominik del Bondio <[email protected]>
2447
     * @author     The ICU Project
2448
     * @since      0.11.0
2449
     */
2450
    protected function computeMillisInDay()
2451
    {
2452
        // Do the time portion of the conversion.
2453
2454
        $millisInDay = 0;
2455
2456
        // Find the best set of fields specifying the time of day.  There
2457
        // are only two possibilities here; the HOUR_OF_DAY or the
2458
        // AM_PM and the HOUR.
2459
        $hourOfDayStamp = $this->fStamp[DateDefinitions::HOUR_OF_DAY];
2460
        $hourStamp = ($this->fStamp[DateDefinitions::HOUR] > $this->fStamp[DateDefinitions::AM_PM]) ? $this->fStamp[DateDefinitions::HOUR] : $this->fStamp[DateDefinitions::AM_PM];
2461
        $bestStamp = ($hourStamp > $hourOfDayStamp) ? $hourStamp : $hourOfDayStamp;
2462
2463
        // Hours
2464
        if ($bestStamp != self::kUnset) {
2465
            if ($bestStamp == $hourOfDayStamp) {
2466
                // Don't normalize here; let overflow bump into the next period.
2467
                // This is consistent with how we handle other fields.
2468
                $millisInDay += $this->internalGet(DateDefinitions::HOUR_OF_DAY);
2469
            } else {
2470
                // Don't normalize here; let overflow bump into the next period.
2471
                // This is consistent with how we handle other fields.
2472
                $millisInDay += $this->internalGet(DateDefinitions::HOUR);
2473
                $millisInDay += 12 * $this->internalGet(DateDefinitions::AM_PM); // Default works for unset AM_PM
2474
            }
2475
        }
2476
2477
        // We use the fact that unset == 0; we start with millisInDay
2478
        // == HOUR_OF_DAY.
2479
        $millisInDay *= 60;
2480
        $millisInDay += $this->internalGet(DateDefinitions::MINUTE); // now have minutes
2481
        $millisInDay *= 60;
2482
        $millisInDay += $this->internalGet(DateDefinitions::SECOND); // now have seconds
2483
        $millisInDay *= 1000;
2484
        $millisInDay += $this->internalGet(DateDefinitions::MILLISECOND); // now have millis
2485
2486
        return $millisInDay;
2487
    }
2488
2489
    /**
2490
     * This method can assume EXTENDED_YEAR has been set.
2491
     *
2492
     * @param      double $millis milliseconds of the date fields
2493
     * @param      int    $millisInDay milliseconds of the time fields; may be out or range.
2494
     *
2495
     * @return     int
2496
     *
2497
     * @author     Dominik del Bondio <[email protected]>
2498
     * @author     The ICU Project
2499
     * @since      0.11.0
2500
     */
2501
    protected function computeZoneOffset($millis, $millisInDay)
2502
    {
2503
        $rawOffset = $dstOffset = 0;
2504
        $this->getTimeZone()->getOffsetRef($millis + $millisInDay, true, $rawOffset, $dstOffset);
2505
        return $rawOffset + $dstOffset;
2506
        // Note: Because we pass in wall millisInDay, rather than
2507
        // standard millisInDay, we interpret "1:00 am" on the day
2508
        // of cessation of DST as "1:00 am Std" (assuming the time
2509
        // of cessation is 2:00 am).
2510
    }
2511
2512
    /**
2513
     * Determine the best stamp in a range.
2514
     *
2515
     * @param      int    $first first enum to look at
2516
     * @param      int    $last last enum to look at
2517
     * @param      int    $bestStampSoFar stamp prior to function call
2518
     *
2519
     * @return     int    the stamp value of the best stamp
2520
     *
2521
     * @author     Dominik del Bondio <[email protected]>
2522
     * @author     The ICU Project
2523
     * @since      0.11.0
2524
     */
2525
    protected function newestStamp($first, $last, $bestStampSoFar)
2526
    {
2527
        $bestStamp = $bestStampSoFar;
2528
        for ($i = (int) $first; $i <= (int) $last; ++$i) {
2529
            if ($this->fStamp[$i] > $bestStamp) {
2530
                $bestStamp = $this->fStamp[$i];
2531
            }
2532
        }
2533
        return $bestStamp;
2534
    }
2535
2536
    /**
2537
     * @var        array Precedence table for Dates
2538
     * @see #resolveFields
2539
     * @internal
2540
     *
2541
     * @author     Dominik del Bondio <[email protected]>
2542
     * @author     The ICU Project
2543
     * @since      0.11.0
2544
     */
2545
    static $kDatePrecedence = array(
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $kDatePrecedence.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
2546
        array(
2547
            array(DateDefinitions::DAY_OF_MONTH, self::RESOLVE_STOP),
2548
            array(DateDefinitions::WEEK_OF_YEAR, DateDefinitions::DAY_OF_WEEK, self::RESOLVE_STOP),
2549
            array(DateDefinitions::WEEK_OF_MONTH, DateDefinitions::DAY_OF_WEEK, self::RESOLVE_STOP),
2550
            array(DateDefinitions::DAY_OF_WEEK_IN_MONTH, DateDefinitions::DAY_OF_WEEK, self::RESOLVE_STOP),
2551
            array(DateDefinitions::WEEK_OF_YEAR, DateDefinitions::DOW_LOCAL, self::RESOLVE_STOP),
2552
            array(DateDefinitions::WEEK_OF_MONTH, DateDefinitions::DOW_LOCAL, self::RESOLVE_STOP),
2553
            array(DateDefinitions::DAY_OF_WEEK_IN_MONTH, DateDefinitions::DOW_LOCAL, self::RESOLVE_STOP),
2554
            array(DateDefinitions::DAY_OF_YEAR, self::RESOLVE_STOP),
2555
            //    kResolveRemap | UCAL_DAY_OF_MONTH
2556
            array(37, DateDefinitions::YEAR, self::RESOLVE_STOP),  // if YEAR is set over YEAR_WOY use DAY_OF_MONTH
2557
            //    kResolveRemap | UCAL_WEEK_OF_YEAR
2558
            array(35, DateDefinitions::YEAR_WOY, self::RESOLVE_STOP),  // if YEAR_WOY is set,  calc based on WEEK_OF_YEAR
2559
            array(self::RESOLVE_STOP),
2560
        ),
2561
        array(
2562
            array(DateDefinitions::WEEK_OF_YEAR, self::RESOLVE_STOP),
2563
            array(DateDefinitions::WEEK_OF_MONTH, self::RESOLVE_STOP),
2564
            array(DateDefinitions::DAY_OF_WEEK_IN_MONTH, self::RESOLVE_STOP),
2565
            //    kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH
2566
            array(40, DateDefinitions::DAY_OF_WEEK, self::RESOLVE_STOP),
2567
            //    self::kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2568
            array(40, DateDefinitions::DOW_LOCAL, self::RESOLVE_STOP),
2569
            array(self::RESOLVE_STOP),
2570
        ),
2571
        array(
2572
            array(self::RESOLVE_STOP),
2573
        ),
2574
    );
2575
2576
    /**
2577
     * @var        array Precedence table for Year
2578
     * @see #resolveFields
2579
     * @internal
2580
     *
2581
     * @author     Dominik del Bondio <[email protected]>
2582
     * @author     The ICU Project
2583
     * @since      0.11.0
2584
     */
2585
    protected static $kYearPrecedence = array(
2586
        array(
2587
            array(DateDefinitions::YEAR, self::RESOLVE_STOP),
2588
            array(DateDefinitions::EXTENDED_YEAR, self::RESOLVE_STOP),
2589
            array(DateDefinitions::YEAR_WOY, DateDefinitions::WEEK_OF_YEAR, self::RESOLVE_STOP),  // YEAR_WOY is useless without WEEK_OF_YEAR
2590
            array(self::RESOLVE_STOP),
2591
        ),
2592
        array(
2593
            array(self::RESOLVE_STOP),
2594
        ),
2595
    );
2596
2597
    /**
2598
     * @var        array Precedence table for Day of Week
2599
     * @see #resolveFields
2600
     * @internal
2601
     *
2602
     * @author     Dominik del Bondio <[email protected]>
2603
     * @author     The ICU Project
2604
     * @since      0.11.0
2605
     */
2606
    protected static $kDOWPrecedence = array(
2607
        array(
2608
            array(DateDefinitions::DAY_OF_WEEK, self::RESOLVE_STOP, self::RESOLVE_STOP),
2609
            array(DateDefinitions::DOW_LOCAL, self::RESOLVE_STOP, self::RESOLVE_STOP),
2610
            array(self::RESOLVE_STOP),
2611
        ),
2612
        array(
2613
            array(self::RESOLVE_STOP),
2614
        ),
2615
    );
2616
2617
    /**
2618
     * Given a precedence table, return the newest field combination in
2619
     * the table, or UCAL_FIELD_COUNT if none is found.
2620
     *
2621
     * <p>The precedence table is a 3-dimensional array of integers.  It
2622
     * may be thought of as an array of groups.  Each group is an array of
2623
     * lines.  Each line is an array of field numbers.  Within a line, if
2624
     * all fields are set, then the time stamp of the line is taken to be
2625
     * the stamp of the most recently set field.  If any field of a line is
2626
     * unset, then the line fails to match.  Within a group, the line with
2627
     * the newest time stamp is selected.  The first field of the line is
2628
     * returned to indicate which line matched.
2629
     *
2630
     * <p>In some cases, it may be desirable to map a line to field that
2631
     * whose stamp is NOT examined.  For example, if the best field is
2632
     * DAY_OF_WEEK then the DAY_OF_WEEK_IN_MONTH algorithm may be used.  In
2633
     * order to do this, insert the value <code>kResolveRemap | F</code> at
2634
     * the start of the line, where <code>F</code> is the desired return
2635
     * field value.  This field will NOT be examined; it only determines
2636
     * the return value if the other fields in the line are the newest.
2637
     *
2638
     * <p>If all lines of a group contain at least one unset field, then no
2639
     * line will match, and the group as a whole will fail to match.  In
2640
     * that case, the next group will be processed.  If all groups fail to
2641
     * match, then UCAL_FIELD_COUNT is returned.
2642
     * @internal
2643
     *
2644
     * @param      array $precedenceTable the precedence table
2645
     *
2646
     * @return     int   the best field
2647
     *
2648
     * @author     Dominik del Bondio <[email protected]>
2649
     * @author     The ICU Project
2650
     * @since      0.11.0
2651
     */
2652
    protected function resolveFields($precedenceTable)
2653
    {
2654
        $bestField = DateDefinitions::FIELD_COUNT;
2655
        for ($g = 0; $precedenceTable[$g][0][0] != -1 && ($bestField == DateDefinitions::FIELD_COUNT); ++$g) {
2656
            $bestStamp = self::kUnset;
2657
            for ($l = 0; $precedenceTable[$g][$l][0] != -1; ++$l) {
2658
                $lineStamp = self::kUnset;
2659
                // Skip over first entry if it is negative
2660
                for ($i = (($precedenceTable[$g][$l][0] >= self::RESOLVE_REMAP) ? 1 : 0); $precedenceTable[$g][$l][$i] != -1; ++$i) {
2661
                    $s = $this->fStamp[$precedenceTable[$g][$l][$i]];
2662
2663
                    // If any field is unset then don't use this line
2664
                    if ($s == self::kUnset) {
2665
//					goto linesInGroup;
2666
                        continue 2;
2667
                    } elseif ($s > $lineStamp) {
2668
                        $lineStamp = $s;
2669
                    }
2670
                }
2671
                // Record new maximum stamp & field no.
2672
                if ($lineStamp > $bestStamp) {
2673
                    $bestStamp = $lineStamp;
2674
                    $bestField = $precedenceTable[$g][$l][0]; // First field refers to entire line
2675
                }
2676
//linesInGroup:
2677
            }
2678
        }
2679
        return ($bestField >= self::RESOLVE_REMAP) ? ($bestField & (self::RESOLVE_REMAP - 1)) : $bestField ;
2680
    }
2681
2682
    /**
2683
     * @return     array
2684
     *
2685
     * @author     Dominik del Bondio <[email protected]>
2686
     * @author     The ICU Project
2687
     * @since      0.11.0
2688
     */
2689
    protected function getFieldResolutionTable()
2690
    {
2691
        return self::$kDatePrecedence;
2692
    }
2693
2694
    /**
2695
     * Return the field that is newer, either defaultField, or alternateField.
2696
     * If neither is newer or neither is set, return defaultField.
2697
     * @internal
2698
     *
2699
     * @param      int
2700
     * @param      int
2701
     *
2702
     * @return     int
2703
     *
2704
     * @author     Dominik del Bondio <[email protected]>
2705
     * @author     The ICU Project
2706
     * @since      0.11.0
2707
     */
2708
    protected function newerField($defaultField, $alternateField)
2709
    {
2710
        if ($this->fStamp[$alternateField] > $this->fStamp[$defaultField]) {
2711
            return $alternateField;
2712
        }
2713
        return $defaultField;
2714
    }
2715
2716
    /**
2717
     * Helper function for calculating limits by trial and error
2718
     *
2719
     * @param      int    $field The field being investigated
2720
     * @param      int    $startValue starting (least max) value of field
2721
     * @param      int    $endValue ending (greatest max) value of field
2722
     *
2723
     * @return     int
2724
     *
2725
     * @author     Dominik del Bondio <[email protected]>
2726
     * @author     The ICU Project
2727
     * @since      0.11.0
2728
     */
2729
    protected function getActualHelper($field, $startValue, $endValue)
2730
    {
2731
        if ($startValue == $endValue) {
2732
            // if we know that the maximum value is always the same, just return it
2733
            return $startValue;
2734
        }
2735
2736
        $delta = ($endValue > $startValue) ? 1 : -1;
2737
2738
        // clone the calendar so we don't mess with the real one, and set it to
2739
        // accept anything for the field values
2740
        $work = clone $this;
2741
        $work->setLenient(true);
2742
        $work->prepareGetActual($field, $delta < 0);
2743
2744
        // now try each value from the start to the end one by one until
2745
        // we get a value that normalizes to another value.  The last value that
2746
        // normalizes to itself is the actual maximum for the current date
2747
        $result = $startValue;
2748 View Code Duplication
        do {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2749
            $work->set($field, $startValue);
2750
            if ($work->get($field) != $startValue) {
2751
                break;
2752
            } else {
2753
                $result = $startValue;
2754
                $startValue += $delta;
2755
            }
2756
        } while ($result != $endValue);
2757
2758
        return $result;
2759
    }
2760
2761
    /**
2762
     * @var        bool The flag which indicates if the current time is set in the
2763
     *                  calendar.
2764
     */
2765
    protected $fIsTimeSet = false;
2766
2767
    /**
2768
     * @var        bool True if the fields are in sync with the currently set time
2769
     *                  of this Calendar. If false, then the next attempt to get
2770
     *                  the value of a field will force a recomputation of all
2771
     *                  fields from the current value of the time field.
2772
     */
2773
    protected $fAreFieldsInSync = false;
2774
2775
    /**
2776
     * @var        bool True if all of the fields have been set.  This is
2777
     *                  initially false, and set to true by computeFields().
2778
     */
2779
    protected $fAreAllFieldsSet = false;
2780
2781
    /**
2782
     * @var        bool True if all fields have been virtually set, but have not
2783
     *                  yet been computed.  This occurs only in setTimeInMillis().
2784
     *                  A calendar set to this state will compute all fields from
2785
     *                  the time if it becomes necessary, but otherwise will delay
2786
     *                  such computation.
2787
     */
2788
    protected $fAreFieldsVirtuallySet = false;
2789
2790
    /**
2791
     * Get the current time without recomputing.
2792
     *
2793
     * @return     float the current time without recomputing.
2794
     *
2795
     * @author     Dominik del Bondio <[email protected]>
2796
     * @author     The ICU Project
2797
     * @since      0.11.0
2798
     */
2799
    protected function internalGetTime()
2800
    {
2801
        return $this->fTime;
2802
    }
2803
2804
    /**
2805
     * Set the current time without affecting flags or fields.
2806
     *
2807
     * @param      float $time The time to be set
2808
     *
2809
     * @author     Dominik del Bondio <[email protected]>
2810
     * @author     The ICU Project
2811
     * @since      0.11.0
2812
     */
2813
    protected function internalSetTime($time)
2814
    {
2815
        $this->fTime = $time;
2816
    }
2817
2818
    /**
2819
     * @var        array The time fields containing values into which the millis
2820
     *                   is computed.
2821
     */
2822
    protected $fFields;
2823
2824
    /**
2825
     * @var        array The flags which tell if a specified time field for the
2826
     *                   calendar is set.
2827
     *
2828
     * @author     Dominik del Bondio <[email protected]>
2829
     * @author     The ICU Project
2830
     * @since      0.11.0
2831
     *
2832
     * @deprecated ICU 2.8 use (fStamp[n]!=kUnset)
2833
     */
2834
    protected $fIsSet;
2835
2836
    /** Special values of stamp[]
2837
     *
2838
     * @author     Dominik del Bondio <[email protected]>
2839
     * @author     The ICU Project
2840
     * @since      0.11.0
2841
     */
2842
    const kUnset                 = 0;
2843
    const kInternallySet         = 1;
2844
    const kMinimumUserStamp      = 2;
2845
2846
    /**
2847
     * @var        array Pseudo-time-stamps which specify when each field was set.
2848
     *                   There are two special values, UNSET and INTERNALLY_SET.
2849
     *                   Values from MINIMUM_USER_SET to Integer.MAX_VALUE are
2850
     *                   legal user set values.
2851
     */
2852
    protected $fStamp;
2853
2854
    /**
2855
     * Subclasses may override this method to compute several fields
2856
     * specific to each calendar system.  These are:
2857
     *
2858
     * <ul><li>DateDefinitions::ERA
2859
     * <li>DateDefinitions::YEAR
2860
     * <li>DateDefinitions::MONTH
2861
     * <li>DateDefinitions::DAY_OF_MONTH
2862
     * <li>DateDefinitions::DAY_OF_YEAR
2863
     * <li>DateDefinitions::EXTENDED_YEAR</ul>
2864
     *
2865
     * Subclasses can refer to the DAY_OF_WEEK and DOW_LOCAL fields, which
2866
     * will be set when this method is called.  Subclasses can also call
2867
     * the getGregorianXxx() methods to obtain Gregorian calendar
2868
     * equivalents for the given Julian day.
2869
     *
2870
     * <p>In addition, subclasses should compute any subclass-specific
2871
     * fields, that is, fields from BASE_FIELD_COUNT to
2872
     * getFieldCount() - 1.
2873
     *
2874
     * <p>The default implementation in <code>Calendar</code> implements
2875
     * a pure proleptic Gregorian calendar.
2876
     * @internal
2877
     *
2878
     * @param      int $julianDay The julian day
2879
     *
2880
     * @author     Dominik del Bondio <[email protected]>
2881
     * @author     The ICU Project
2882
     * @since      0.11.0
2883
     */
2884
    protected function handleComputeFields($julianDay)
2885
    {
2886
        $this->internalSet(DateDefinitions::MONTH, $this->getGregorianMonth());
2887
        $this->internalSet(DateDefinitions::DAY_OF_MONTH, $this->getGregorianDayOfMonth());
2888
        $this->internalSet(DateDefinitions::DAY_OF_YEAR, $this->getGregorianDayOfYear());
2889
        $eyear = $this->getGregorianYear();
2890
        $this->internalSet(DateDefinitions::EXTENDED_YEAR, $eyear);
2891
        $era = GregorianCalendar::AD;
2892
        if ($eyear < 1) {
2893
            $era = GregorianCalendar::BC;
2894
            $eyear = 1 - $eyear;
2895
        }
2896
        $this->internalSet(DateDefinitions::ERA, $era);
2897
        $this->internalSet(DateDefinitions::YEAR, $eyear);
2898
    }
2899
2900
    /**
2901
     * Return the extended year on the Gregorian calendar as computed by
2902
     * <code>computeGregorianFields()</code>.
2903
     * @see        Calendar::computeGregorianFields
2904
     * @internal
2905
     *
2906
     * @return     int The gregorian year
2907
     *
2908
     * @author     Dominik del Bondio <[email protected]>
2909
     * @author     The ICU Project
2910
     * @since      0.11.0
2911
     */
2912
    protected function getGregorianYear()
2913
    {
2914
        return $this->fGregorianYear;
2915
    }
2916
2917
    /**
2918
     * Return the month (0-based) on the Gregorian calendar as computed by
2919
     * <code>computeGregorianFields()</code>.
2920
     * @see        Calendar::computeGregorianFields
2921
     * @internal
2922
     *
2923
     * @return     int The gregorian month
2924
     *
2925
     * @author     Dominik del Bondio <[email protected]>
2926
     * @author     The ICU Project
2927
     * @since      0.11.0
2928
     */
2929
    protected function getGregorianMonth()
2930
    {
2931
        return $this->fGregorianMonth;
2932
    }
2933
2934
    /**
2935
     * Return the day of year (1-based) on the Gregorian calendar as
2936
     * computed by <code>computeGregorianFields()</code>.
2937
     * @see        Calendar::computeGregorianFields
2938
     * @internal
2939
     *
2940
     * @return     int The gregorian day of year
2941
     *
2942
     * @author     Dominik del Bondio <[email protected]>
2943
     * @author     The ICU Project
2944
     * @since      0.11.0
2945
     */
2946
    protected function getGregorianDayOfYear()
2947
    {
2948
        return $this->fGregorianDayOfYear;
2949
    }
2950
2951
    /**
2952
     * Return the day of month (1-based) on the Gregorian calendar as
2953
     * computed by <code>computeGregorianFields()</code>.
2954
     * @see        Calendar::computeGregorianFields
2955
     * @internal
2956
     *
2957
     * @return     int The gregorian day of month
2958
     *
2959
     * @author     Dominik del Bondio <[email protected]>
2960
     * @author     The ICU Project
2961
     * @since      0.11.0
2962
     */
2963
    protected function getGregorianDayOfMonth()
2964
    {
2965
        return $this->fGregorianDayOfMonth;
2966
    }
2967
2968
    /**
2969
     * Called by computeJulianDay.  Returns the default month (0-based) for the
2970
     * year, taking year and era into account.  Defaults to 0 for Gregorian, which
2971
     * doesn't care.
2972
     *
2973
     * @return     int The default month for the year.
2974
     *
2975
     * @author     Dominik del Bondio <[email protected]>
2976
     * @author     The ICU Project
2977
     * @since      0.11.0
2978
     */
2979
    protected function getDefaultMonthInYear()
2980
    {
2981
        return 0;
2982
    }
2983
2984
    /**
2985
     * Called by computeJulianDay.  Returns the default day (1-based) for the
2986
     * month, taking currently-set year and era into account.  Defaults to 1 for
2987
     * Gregorian.
2988
     *
2989
     * @param      int $month The months
2990
     *
2991
     * @return     int The default day for the month
2992
     *
2993
     * @author     Dominik del Bondio <[email protected]>
2994
     * @author     The ICU Project
2995
     * @since      0.11.0
2996
     */
2997
    protected function getDefaultDayInMonth($month)
0 ignored issues
show
Unused Code introduced by
The parameter $month is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2998
    {
2999
        return 1;
3000
    }
3001
3002
    //-------------------------------------------------------------------------
3003
    // Protected utility methods for use by subclasses.  These are very handy
3004
    // for implementing add, roll, and computeFields.
3005
    //-------------------------------------------------------------------------
3006
3007
    /**
3008
     * Adjust the specified field so that it is within
3009
     * the allowable range for the date to which this calendar is set.
3010
     * For example, in a Gregorian calendar pinning the
3011
     * DateDefinitions::DAY_OF_MONTH field for a calendar set to April 31
3012
     * would cause it to be set to April 30.
3013
     * <p>
3014
     * <b>Subclassing:</b>
3015
     * <br>
3016
     * This utility method is intended for use by subclasses that need to
3017
     * implement their own overrides of {@link #roll roll} and {@link #add add}.
3018
     * <p>
3019
     * <b>Note:</b>
3020
     * <code>pinField</code> is implemented in terms of
3021
     * {@link #getActualMinimum getActualMinimum}
3022
     * and {@link #getActualMaximum getActualMaximum}.  If either of those methods
3023
     * uses a slow, iterative algorithm for a particular field, it would be
3024
     * unwise to attempt to call <code>pinField</code> for that field.  If you
3025
     * really do need to do so, you should override this method to do
3026
     * something more efficient for that field.
3027
     * <p>
3028
     *
3029
     * @param      string $field The calendar field whose value should be pinned.
3030
     *
3031
     * @see        getActualMinimum
3032
     * @see        getActualMaximum
3033
     *
3034
     * @author     Dominik del Bondio <[email protected]>
3035
     * @author     The ICU Project
3036
     * @since      0.11.0
3037
     */
3038
    protected function pinField($field)
3039
    {
3040
        $max = $this->getActualMaximum($field);
3041
        $min = $this->getActualMinimum($field);
3042
3043
        if ($this->fFields[$field] > $max) {
3044
            $this->set($field, $max);
3045
        } elseif ($this->fFields[$field] < $min) {
3046
            $this->set($field, $min);
3047
        }
3048
    }
3049
3050
    /**
3051
     * Return the week number of a day, within a period. This may be the week
3052
     * number in a year or the week number in a month. Usually this will be a
3053
     * value >= 1, but if some initial days of the period are excluded from
3054
     * week 1, because getMinimalDaysInFirstWeek is > 1, then the week number will
3055
     * be zero for those initial days. This method requires the day number and day
3056
     * of week for some known date in the period in order to determine the day of
3057
     * week on the desired day.
3058
     * <p>
3059
     * <b>Subclassing:</b>
3060
     * <br>
3061
     * This method is intended for use by subclasses in implementing their
3062
     * {@link #computeTime computeTime} and/or {@link #computeFields computeFields} methods.
3063
     * It is often useful in {@link #getActualMinimum getActualMinimum} and
3064
     * {@link #getActualMaximum getActualMaximum} as well.
3065
     * <p>
3066
     * This variant is handy for computing the week number of some other
3067
     * day of a period (often the first or last day of the period) when its day
3068
     * of the week is not known but the day number and day of week for some other
3069
     * day in the period (e.g. the current date) <em>is</em> known.
3070
     * <p>
3071
     *
3072
     * @param      int $desiredDay The {@link #UCalendarDateFields DAY_OF_YEAR} or
3073
     *                 {@link #UCalendarDateFields DAY_OF_MONTH} whose week
3074
     *                 number is desired.
3075
     *                 Should be 1 for the first day of the period.
3076
     *
3077
     * @param      int $dayOfPeriod The {@link #UCalendarDateFields DAY_OF_YEAR}
3078
     *                 or {@link #UCalendarDateFields DAY_OF_MONTH} for a day in
3079
     *                 the period whose {@link #UCalendarDateFields DAY_OF_WEEK}
3080
     *                 is specified by the <code>knownDayOfWeek</code> parameter.
3081
     *                 Should be 1 for first day of period.
3082
     *
3083
     * @param      int $dayOfWeek The {@link #UCalendarDateFields DAY_OF_WEEK} for the day
3084
     *                 corresponding to the <code>knownDayOfPeriod</code>
3085
     *                 parameter.
3086
     *                 1-based with 1=Sunday.
3087
     *
3088
     * @return     int The week number (one-based), or zero if the day falls
3089
     *                 before the first week because
3090
     *                 {@link #getMinimalDaysInFirstWeek getMinimalDaysInFirstWeek}
3091
     *                 is more than one.
3092
     *
3093
     * @author     Dominik del Bondio <[email protected]>
3094
     * @author     The ICU Project
3095
     * @since      0.11.0
3096
     */
3097
    protected function weekNumber1($desiredDay, $dayOfPeriod, $dayOfWeek)
3098
    {
3099
        // Determine the day of the week of the first day of the period
3100
        // in question (either a year or a month).  Zero represents the
3101
        // first day of the week on this calendar.
3102
        $periodStartDayOfWeek = ($dayOfWeek - $this->getFirstDayOfWeek() - $dayOfPeriod + 1) % 7;
3103
        if ($periodStartDayOfWeek < 0) {
3104
            $periodStartDayOfWeek += 7;
3105
        }
3106
3107
        // Compute the week number.  Initially, ignore the first week, which
3108
        // may be fractional (or may not be).  We add periodStartDayOfWeek in
3109
        // order to fill out the first week, if it is fractional.
3110
        $weekNo = (int) (($desiredDay + $periodStartDayOfWeek - 1) / 7);
3111
3112
        // If the first week is long enough, then count it.  If
3113
        // the minimal days in the first week is one, or if the period start
3114
        // is zero, we always increment weekNo.
3115
        if ((7 - $periodStartDayOfWeek) >= $this->getMinimalDaysInFirstWeek()) {
3116
            ++$weekNo;
3117
        }
3118
3119
        return $weekNo;
3120
    }
3121
3122
    /**
3123
     * Return the week number of a day, within a period. This may be the week number in
3124
     * a year, or the week number in a month. Usually this will be a value >= 1, but if
3125
     * some initial days of the period are excluded from week 1, because
3126
     * {@link #getMinimalDaysInFirstWeek getMinimalDaysInFirstWeek} is > 1,
3127
     * then the week number will be zero for those
3128
     * initial days. This method requires the day of week for the given date in order to
3129
     * determine the result.
3130
     * <p>
3131
     * <b>Subclassing:</b>
3132
     * <br>
3133
     * This method is intended for use by subclasses in implementing their
3134
     * {@link #computeTime computeTime} and/or {@link #computeFields computeFields} methods.
3135
     * It is often useful in {@link #getActualMinimum getActualMinimum} and
3136
     * {@link #getActualMaximum getActualMaximum} as well.
3137
     * <p>
3138
     * @param      int $dayOfPeriod The {@link #UCalendarDateFields DAY_OF_YEAR} or
3139
     *                 {@link #UCalendarDateFields DAY_OF_MONTH} whose week
3140
     *                 number is desired. Should be 1 for the first day of the
3141
     *                 period.
3142
     *
3143
     * @param      int $dayOfWeek The {@link #UCalendarDateFields DAY_OF_WEEK} for the day
3144
     *                 corresponding to the <code>dayOfPeriod</code> parameter.
3145
     *                 1-based with 1=Sunday.
3146
     *
3147
     * @return     int The week number (one-based), or zero if the day falls
3148
     *                 before the first week because
3149
     *                 {@link #getMinimalDaysInFirstWeek getMinimalDaysInFirstWeek}
3150
     *                 is more than one.
3151
     * @internal
3152
     *
3153
     * @author     Dominik del Bondio <[email protected]>
3154
     * @author     The ICU Project
3155
     * @since      0.11.0
3156
     */
3157
    protected function weekNumber($dayOfPeriod, $dayOfWeek)
3158
    {
3159
        return $this->weekNumber1($dayOfPeriod, $dayOfPeriod, $dayOfWeek);
3160
    }
3161
3162
    /**
3163
     * returns the local DOW, valid range 0..6
3164
     * @internal
3165
     *
3166
     * @return     int
3167
     *
3168
     * @author     Dominik del Bondio <[email protected]>
3169
     * @author     The ICU Project
3170
     * @since      0.11.0
3171
     */
3172
    protected function getLocalDOW()
3173
    {
3174
        // Get zero-based localized DOW, valid range 0..6.  This is the DOW
3175
        // we are looking for.
3176
        $dowLocal = 0;
3177
        switch ($this->resolveFields(self::$kDOWPrecedence)) {
3178
            case DateDefinitions::DAY_OF_WEEK:
3179
                $dowLocal = $this->internalGet(DateDefinitions::DAY_OF_WEEK) - $this->fFirstDayOfWeek;
3180
                break;
3181
            case DateDefinitions::DOW_LOCAL:
3182
                $dowLocal = $this->internalGet(DateDefinitions::DOW_LOCAL) - 1;
3183
                break;
3184
            default:
3185
                break;
3186
        }
3187
        $dowLocal = $dowLocal % 7;
3188
        if ($dowLocal < 0) {
3189
            $dowLocal += 7;
3190
        }
3191
        return $dowLocal;
3192
    }
3193
3194
    /**
3195
     * @var        int The next available value for fStamp[]
3196
     */
3197
    private $fNextStamp = 1;// = MINIMUM_USER_STAMP;
3198
3199
    /**
3200
     * @var        float The current time set for the calendar.
3201
     */
3202
    private $fTime;
3203
3204
    /**
3205
     * @see   #setLenient
3206
     * @var        bool
3207
     */
3208
    private $fLenient;
3209
3210
    /**
3211
     * @var        TimeZone Time zone affects the time calculation done by
3212
     *                           Calendar. Calendar subclasses use the time zone
3213
     *                           data to produce the local time.
3214
     */
3215
    private $fZone;
3216
3217
    /**
3218
     * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent. They are
3219
     * used to figure out the week count for a specific date for a given locale. These
3220
     * must be set when a Calendar is constructed. For example, in US locale,
3221
     * firstDayOfWeek is SUNDAY; minimalDaysInFirstWeek is 1. They are used to figure
3222
     * out the week count for a specific date for a given locale. These must be set when
3223
     * a Calendar is constructed.
3224
     *
3225
     * @author     Dominik del Bondio <[email protected]>
3226
     * @author     The ICU Project
3227
     * @since      0.11.0
3228
     */
3229
    private $fFirstDayOfWeek;
3230
    private $fMinimalDaysInFirstWeek;
3231
3232
    /**
3233
     * Sets firstDayOfWeek and minimalDaysInFirstWeek. Called at Calendar construction
3234
     * time.
3235
     *
3236
     * @param      Locale $desiredLocale The given locale.
3237
     * @param      string $type The calendar type identifier, e.g: gregorian,
3238
     *                    buddhist, etc.
3239
     *
3240
     * @author     Dominik del Bondio <[email protected]>
3241
     * @author     The ICU Project
3242
     * @since      0.11.0
3243
     */
3244
    private function setWeekCountData(Locale $desiredLocale, $type)
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
3245
    {
3246
        // Read the week count data from the resource bundle.  This should
3247
        // have the form:
3248
        //
3249
        //   DateTimeElements:intvector {
3250
        //      1,    // first day of week
3251
        //      1     // min days in week
3252
        //   }
3253
        //   Both have a range of 1..7
3254
3255
        $this->fFirstDayOfWeek = DateDefinitions::SUNDAY;
3256
        $this->fMinimalDaysInFirstWeek = 1;
3257
3258
        $tm = $desiredLocale->getContext()->getTranslationManager();
3259
        $cdata = $tm->getTerritoryData($desiredLocale->getLocaleTerritory());
3260
        if (isset($cdata['week']['firstDay'])) {
3261
            $this->fFirstDayOfWeek = (int) $cdata['week']['firstDay'];
3262
        }
3263
        if (isset($cdata['week']['minDays'])) {
3264
            $this->fMinimalDaysInFirstWeek = (int) $cdata['week']['minDays'];
3265
        }
3266
    }
3267
3268
    /**
3269
     * Recompute the time and update the status fields isTimeSet
3270
     * and areFieldsSet.  Callers should check isTimeSet and only
3271
     * call this method if isTimeSet is false.
3272
     *
3273
     * @author     Dominik del Bondio <[email protected]>
3274
     * @author     The ICU Project
3275
     * @since      0.11.0
3276
     */
3277
    private function updateTime()
3278
    {
3279
        $this->computeTime();
3280
3281
        // If we are lenient, we need to recompute the fields to normalize
3282
        // the values.  Also, if we haven't set all the fields yet (i.e.,
3283
        // in a newly-created object), we need to fill in the fields. [LIU]
3284
        if ($this->isLenient() || ! $this->fAreAllFieldsSet) {
3285
            $this->fAreFieldsInSync = false;
3286
        }
3287
3288
        $this->fIsTimeSet = true;
3289
        $this->fAreFieldsVirtuallySet = false;
3290
    }
3291
3292
    /**
3293
     * @var        int The Gregorian year, as computed by computeGregorianFields()
3294
     *                 and returned by getGregorianYear().
3295
     * @see        Calendar::computeGregorianFields
3296
     */
3297
    private $fGregorianYear;
3298
3299
    /**
3300
     * @var        int The Gregorian month, as computed by
3301
     *                 computeGregorianFields() and returned by
3302
     *                 getGregorianMonth().
3303
     * @see        Calendar::computeGregorianFields
3304
     */
3305
    private $fGregorianMonth;
3306
3307
    /**
3308
     * @var        int The Gregorian day of the year, as computed by
3309
     *                 computeGregorianFields() and returned by
3310
     *                 getGregorianDayOfYear().
3311
     * @see        Calendar::computeGregorianFields
3312
     */
3313
    private $fGregorianDayOfYear;
3314
3315
    /**
3316
     * @var        int The Gregorian day of the month, as computed by
3317
     *                 computeGregorianFields() and returned by
3318
     *                 getGregorianDayOfMonth().
3319
     * @see        Calendar::computeGregorianFields
3320
     */
3321
    private $fGregorianDayOfMonth;
3322
3323
    /* calculations */
3324
3325
    /**
3326
     * Compute the Gregorian calendar year, month, and day of month from
3327
     * the given Julian day.  These values are not stored in fields, but in
3328
     * member variables gregorianXxx.  Also compute the DAY_OF_WEEK and
3329
     * DOW_LOCAL fields.
3330
     *
3331
     * @param      int $julianDay The julian day
3332
     *
3333
     * @author     Dominik del Bondio <[email protected]>
3334
     * @author     The ICU Project
3335
     * @since      0.11.0
3336
     */
3337
    private function computeGregorianAndDOWFields($julianDay)
3338
    {
3339
        $this->computeGregorianFields($julianDay);
3340
3341
        // Compute day of week: JD 0 = Monday
3342
        $dow = $this->julianDayToDayOfWeek($julianDay);
3343
        $this->internalSet(DateDefinitions::DAY_OF_WEEK, $dow);
3344
3345
        // Calculate 1-based localized day of week
3346
        $dowLocal = $dow - $this->getFirstDayOfWeek() + 1;
3347
        if ($dowLocal < 1) {
3348
            $dowLocal += 7;
3349
        }
3350
        $this->internalSet(DateDefinitions::DOW_LOCAL, $dowLocal);
3351
        $this->fFields[DateDefinitions::DOW_LOCAL] = $dowLocal;
3352
    }
3353
3354
    /**
3355
     * Compute the Gregorian calendar year, month, and day of month from the
3356
     * Julian day.  These values are not stored in fields, but in member
3357
     * variables gregorianXxx.  They are used for time zone computations and by
3358
     * subclasses that are Gregorian derivatives.  Subclasses may call this
3359
     * method to perform a Gregorian calendar millis->fields computation.
3360
     * To perform a Gregorian calendar fields->millis computation, call
3361
     * computeGregorianMonthStart().
3362
     * @see #computeGregorianMonthStart
3363
     *
3364
     * @param      int $julianDay The julian day
3365
     *
3366
     * @author     Dominik del Bondio <[email protected]>
3367
     * @author     The ICU Project
3368
     * @since      0.11.0
3369
     */
3370
    private function computeGregorianFields($julianDay)
3371
    {
3372
        $gregorianDayOfWeekUnused = 0;
3373
        CalendarGrego::dayToFields($julianDay - DateDefinitions::EPOCH_START_AS_JULIAN_DAY, $this->fGregorianYear, $this->fGregorianMonth, $this->fGregorianDayOfMonth, $gregorianDayOfWeekUnused, $this->fGregorianDayOfYear);
3374
    }
3375
3376
    /**
3377
     * Compute the fields WEEK_OF_YEAR, YEAR_WOY, WEEK_OF_MONTH,
3378
     * DAY_OF_WEEK_IN_MONTH, and DOW_LOCAL from EXTENDED_YEAR, YEAR,
3379
     * DAY_OF_WEEK, and DAY_OF_YEAR.  The latter fields are computed by the
3380
     * subclass based on the calendar system.
3381
     *
3382
     * <p>The YEAR_WOY field is computed simplistically.  It is equal to YEAR
3383
     * most of the time, but at the year boundary it may be adjusted to YEAR-1
3384
     * or YEAR+1 to reflect the overlap of a week into an adjacent year.  In
3385
     * this case, a simple increment or decrement is performed on YEAR, even
3386
     * though this may yield an invalid YEAR value.  For instance, if the YEAR
3387
     * is part of a calendar system with an N-year cycle field CYCLE, then
3388
     * incrementing the YEAR may involve incrementing CYCLE and setting YEAR
3389
     * back to 0 or 1.  This is not handled by this code, and in fact cannot be
3390
     * simply handled without having subclasses define an entire parallel set of
3391
     * fields for fields larger than or equal to a year.  This additional
3392
     * complexity is not warranted, since the intention of the YEAR_WOY field is
3393
     * to support ISO 8601 notation, so it will typically be used with a
3394
     * proleptic Gregorian calendar, which has no field larger than a year.
3395
     *
3396
     * @author     Dominik del Bondio <[email protected]>
3397
     * @author     The ICU Project
3398
     * @since      0.11.0
3399
     */
3400
    private function computeWeekFields()
3401
    {
3402
        $eyear = $this->fFields[DateDefinitions::EXTENDED_YEAR];
3403
        $year = $this->fFields[DateDefinitions::YEAR];
3404
        $dayOfWeek = $this->fFields[DateDefinitions::DAY_OF_WEEK];
3405
        $dayOfYear = $this->fFields[DateDefinitions::DAY_OF_YEAR];
3406
3407
        // WEEK_OF_YEAR start
3408
        // Compute the week of the year.  For the Gregorian calendar, valid week
3409
        // numbers run from 1 to 52 or 53, depending on the year, the first day
3410
        // of the week, and the minimal days in the first week.  For other
3411
        // calendars, the valid range may be different -- it depends on the year
3412
        // length.  Days at the start of the year may fall into the last week of
3413
        // the previous year; days at the end of the year may fall into the
3414
        // first week of the next year.  ASSUME that the year length is less than
3415
        // 7000 days.
3416
        $yearOfWeekOfYear = $year;
3417
        $relDow = ($dayOfWeek + 7 - $this->getFirstDayOfWeek()) % 7; // 0..6
3418
        $relDowJan1 = ($dayOfWeek - $dayOfYear + 7001 - $this->getFirstDayOfWeek()) % 7; // 0..6
3419
        $woy = (int) (($dayOfYear - 1 + $relDowJan1) / 7); // 0..53
3420
        if ((7 - $relDowJan1) >= $this->getMinimalDaysInFirstWeek()) {
3421
            ++$woy;
3422
        }
3423
3424
        // Adjust for weeks at the year end that overlap into the previous or
3425
        // next calendar year.
3426
        if ($woy == 0) {
3427
            // We are the last week of the previous year.
3428
            // Check to see if we are in the last week; if so, we need
3429
            // to handle the case in which we are the first week of the
3430
            // next year.
3431
3432
            $prevDoy = $dayOfYear + $this->handleGetYearLength($eyear - 1);
3433
            $woy = $this->weekNumber($prevDoy, $dayOfWeek);
3434
            $yearOfWeekOfYear--;
3435
        } else {
3436
            $lastDoy = $this->handleGetYearLength($eyear);
3437
            // Fast check: For it to be week 1 of the next year, the DOY
3438
            // must be on or after L-5, where L is yearLength(), then it
3439
            // cannot possibly be week 1 of the next year:
3440
            //          L-5                  L
3441
            // doy: 359 360 361 362 363 364 365 001
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3442
            // dow:      1   2   3   4   5   6   7
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3443
            if ($dayOfYear >= ($lastDoy - 5)) {
3444
                $lastRelDow = ($relDow + $lastDoy - $dayOfYear) % 7;
3445
                if ($lastRelDow < 0) {
3446
                    $lastRelDow += 7;
3447
                }
3448
                if (((6 - $lastRelDow) >= $this->getMinimalDaysInFirstWeek()) &&
3449
                        (($dayOfYear + 7 - $relDow) > $lastDoy)) {
3450
                    $woy = 1;
3451
                    $yearOfWeekOfYear++;
3452
                }
3453
            }
3454
        }
3455
        $this->fFields[DateDefinitions::WEEK_OF_YEAR] = $woy;
3456
        $this->fFields[DateDefinitions::YEAR_WOY] = $yearOfWeekOfYear;
3457
        // WEEK_OF_YEAR end
3458
3459
        $dayOfMonth = $this->fFields[DateDefinitions::DAY_OF_MONTH];
3460
        $this->fFields[DateDefinitions::WEEK_OF_MONTH] = $this->weekNumber($dayOfMonth, $dayOfWeek);
3461
        $this->fFields[DateDefinitions::DAY_OF_WEEK_IN_MONTH] = (int)(($dayOfMonth-1) / 7) + 1;
3462
    }
3463
3464
    /**
3465
     * Ensure that each field is within its valid range by calling {@link
3466
     * #validateField(int, int&)} on each field that has been set.  This method
3467
     * should only be called if this calendar is not lenient.
3468
     * @see #isLenient
3469
     * @see #validateField(int, int&)
3470
     * @internal
3471
     *
3472
     * @author     Dominik del Bondio <[email protected]>
3473
     * @author     The ICU Project
3474
     * @since      0.11.0
3475
     */
3476
    private function validateFields()
3477
    {
3478
        for ($field = 0; $field < DateDefinitions::FIELD_COUNT; ++$field) {
3479
            if ($this->_isSet($field)) {
3480
                $this->validateField($field);
3481
            }
3482
        }
3483
    }
3484
3485
    /**
3486
     * Validate a single field of this calendar.  Subclasses should
3487
     * override this method to validate any calendar-specific fields.
3488
     * Generic fields can be handled by
3489
     * <code>Calendar.validateField()</code>.
3490
     * @see #validateField(int, int, int, int&)
3491
     * @internal
3492
     *
3493
     * @param      int $field The field
3494
     *
3495
     * @author     Dominik del Bondio <[email protected]>
3496
     * @author     The ICU Project
3497
     * @since      0.11.0
3498
     */
3499
    private function validateField($field)
3500
    {
3501
        switch ($field) {
3502
            case DateDefinitions::DAY_OF_MONTH:
3503
                $y = $this->handleGetExtendedYear();
3504
                $this->validateField1($field, 1, $this->handleGetMonthLength($y, $this->internalGet(DateDefinitions::MONTH)));
3505
                break;
3506
            case DateDefinitions::DAY_OF_YEAR:
3507
                $y = $this->handleGetExtendedYear();
3508
                $this->validateField1($field, 1, $this->handleGetYearLength($y));
3509
                break;
3510
            case DateDefinitions::DAY_OF_WEEK_IN_MONTH:
3511
                if ($this->internalGet($field) == 0) {
3512
                    throw new \InvalidArgumentException('DAY_OF_WEEK_IN_MONTH cannot be zero');
3513
                }
3514
                $this->validateField1($field, $this->getMinimum($field), $this->getMaximum($field));
3515
                break;
3516
            default:
3517
                $this->validateField1($field, $this->getMinimum($field), $this->getMaximum($field));
3518
                break;
3519
        }
3520
    }
3521
3522
    /**
3523
     * Validate a single field of this calendar given its minimum and
3524
     * maximum allowed value.  If the field is out of range,
3525
     * <code>InvalidArgumentException</code> will be thrown.  Subclasses may
3526
     * use this method in their implementation of {@link
3527
     * #validateField(int, int&)}.
3528
     * @internal
3529
     *
3530
     * @throws     <b>InvalidArgumentException</b>
3531
     *
3532
     * @param      string
3533
     * @param      int
3534
     * @param      int
3535
     *
3536
     * @author     Dominik del Bondio <[email protected]>
3537
     * @author     The ICU Project
3538
     * @since      0.11.0
3539
     */
3540
    private function validateField1($field, $min, $max)
3541
    {
3542
        $value = $this->fFields[$field];
3543
        if ($value < $min || $value > $max) {
3544
            throw new \InvalidArgumentException('Illegal argument error. Field: ' . $field . '. Value ' . $value . ' is not within ' . $min . ' and ' . $max);
3545
        }
3546
    }
3547
3548
    /**
3549
     * Convert a quasi Julian date to the day of the week. The Julian date used here is
3550
     * not a true Julian date, since it is measured from midnight, not noon. Return
3551
     * value is one-based.
3552
     *
3553
     * @param      double $julian The given Julian date number.
3554
     *
3555
     * @return     int    Day number from 1..7 (SUN..SAT).
3556
     *
3557
     * @internal
3558
     *
3559
     * @author     Dominik del Bondio <[email protected]>
3560
     * @author     The ICU Project
3561
     * @since      0.11.0
3562
     */
3563
    protected function julianDayToDayOfWeek($julian)
3564
    {
3565
        // If julian is negative, then julian%7 will be negative, so we adjust
3566
        // accordingly.  We add 1 because Julian day 0 is Monday.
3567
3568
        $dayOfWeek = fmod($julian + 1, 7);
3569
3570
        $result = ($dayOfWeek + (($dayOfWeek < 0) ? (7 + DateDefinitions::SUNDAY) : DateDefinitions::SUNDAY));
3571
        return $result;
3572
    }
3573
3574
    /**
3575
     * @var        string
3576
     */
3577
    private $validLocale;
0 ignored issues
show
Unused Code introduced by
The property $validLocale is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
3578
3579
    /**
3580
     * @var        string
3581
     */
3582
    private $actualLocale;
0 ignored issues
show
Unused Code introduced by
The property $actualLocale is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
3583
3584
    /**
3585
     * @internal
3586
     * @return     bool if this calendar has a default century (i.e. 03 -> 2003)
3587
     *
3588
     * @author     Dominik del Bondio <[email protected]>
3589
     * @author     The ICU Project
3590
     * @since      0.11.0
3591
     */
3592
    abstract public function haveDefaultCentury();
3593
3594
    /**
3595
     * @internal
3596
     * @return     float the start of the default century, as a UDate
3597
     *
3598
     * @author     Dominik del Bondio <[email protected]>
3599
     * @author     The ICU Project
3600
     * @since      0.11.0
3601
     */
3602
    abstract public function defaultCenturyStart();
3603
3604
    /**
3605
     * @internal
3606
     * @return     int the beginning year of the default century, as a year
3607
     *
3608
     * @author     Dominik del Bondio <[email protected]>
3609
     * @author     The ICU Project
3610
     * @since      0.11.0
3611
     */
3612
    abstract public function defaultCenturyStartYear();
3613
3614
    /**
3615
     * Returns the type of the implementing calendar.
3616
     *
3617
     * @return     string The type of this calendar (Gregorian, ...)
3618
     *
3619
     * @author     Dominik del Bondio <[email protected]>
3620
     * @since      0.11.0
3621
     */
3622
    abstract public function getType();
3623
}
3624