Reputation: 7805
I have 3 values:
$timezone = new \DateTimeZone('America/New_York');
$year = 2019;
$week = 52;
I then take these 3 values and run it through a script:
$nowTime = new \DateTime('now', $timezone);
$currTime = clone $nowTime;
$currTime->setISODate($year, $week, 1);
$currTime->setTime(0,0,0);
As you can see, I am setting the current time to be the beginning of Week 52 in 2019.
I am then trying to get information about the next week.
$nextTime = clone $currTime;
$nextTime->modify('+1 week');
$nextWeek = [
'year' => $nextTime->format('Y'),
'week' => $nextTime->format('W'),
];
This script has worked in almost every instance I have found...
Hopever, in Week 52 in 2019, instead of returning the next week as Week 1 in 2020, it returns the next week as Week 1 in 2019... which sends me backwards in time.
How do I fix this? This seems to happen in every year where there are 53 weeks in the year.
Upvotes: 1
Views: 67
Reputation: 2871
There are 2 different ways how weeks can be handled, depending on the task.
Weeks start with Monday. Each week's year is the Gregorian year in which the Thursday falls. The first week of the year, hence, always contains 4 January. ISO week year numbering therefore slightly deviates from the Gregorian for some days close to 1 January.
These rules may be hard to handle manually, that's why it's a part of standard PHP, so you can just use 'week' => $nextTime->format('W')
It is indeed possible that a day in 2019 will belong to a week from 2020. And it's easy to prove: when you open a calendar for 2019 / December, you may notice that last week "may share" days from next year. To prevent a problem with overlapping, when the same week belongs to different years but its number is different, e.g. week 52 in a year 2019 is the same as week 1 in a year 2020, they decided to make a set of rules: ISO. These rules are especially useful in accounting to prevent "ambiguous weeks".
$nextWeek = [
'year' => $nextTime->format('Y'),
'week' => (int)(($nextTime->format('z')) / 7) + 1
];
z
formatter is The day of the year (starting from 0) and that's why I am adding "+1" at the end.
Even though it may look as a good approach, it has a drawback: the week #52 in 2019 is the same as week #1 in 2020.
Upvotes: 0
Reputation: 17426
You're combining two date formats (Y
and W
) that don't make sense together. W is the ISO week number, but Y is the calendar year.
The first ISO week of 2020 starts on December 30, 2019, so for that date, W
returns 1, but Y
still refers to the calendar year 2019.
PHP offers the o
date modifier that can be used in place of Y
in your code, defined in the manual as:
ISO-8601 week-numbering year. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0)
So you can change your code to
$nextWeek = [
'year' => $nextTime->format('o'),
'week' => $nextTime->format('W'),
];
and it should work as intended.
Upvotes: 1