DateTime 2018 and 2019 week count PHP bug? - php

Wanted to get maximum weeks in a year, and thought this would be the simplest way to get this number, but I was surprised,that the last day in a year could be in the first week. Is this because these days are in the first half of the week?
So I know how to get the correct number, I'm just wondering about the logic.
<?php
echo (new DateTime('2016-12-31 00:00:00'))->format('W'); //52
echo (new DateTime('2017-12-31 00:00:00'))->format('W'); //52
echo (new DateTime('2018-12-31 00:00:00'))->format('W'); //01
echo (new DateTime('2018-12-30 00:00:00'))->format('W'); //52
echo (new DateTime('2019-12-31 00:00:00'))->format('W'); //01
echo (new DateTime('2019-12-30 00:00:00'))->format('W'); //01
echo (new DateTime('2019-12-29 00:00:00'))->format('W'); //52
echo (new DateTime('2020-12-31 00:00:00'))->format('W'); //53
Found by answered links (Wikipedia):
Last week
The last week of the ISO week-numbering year, i.e. the 52nd or 53rd
one, is the week before week 01. This week’s properties are:
It has the year's last Thursday in it.
It is the last week with a majority (4 or more) of its days in
December.
Its middle day, Thursday, falls in the ending year.
Its last day is the Sunday nearest to 31 December.
It has 28 December in it. Hence the latest possible dates are 28
December through 3 January, the earliest 21 through 28 December.
If 31 December is on a Monday, Tuesday or Wednesday, it is in week 01
of the next year. If it is on a Thursday, it is in week 53 of the year
just ending; if on a Friday it is in week 52 (or 53 if the year just
ending is a leap year); if on a Saturday or Sunday, it is in week 52
of the year just ending

It's probably following the ISO week date system. Citing that wikipedia article:
The ISO 8601 definition for week 01 is the week with the year's first Thursday in it.

If you want to get the last week of the year you can use this simple function:
function getIsoWeeksInYear($year) {
$date = new DateTime;
$date->setISODate($year, 53);
return ($date->format("W") === "53" ? 53 : 52);
}

Related

DateTime modify function skips February

When adding a month to with DateTime::modify method, the result skips February.
Why isn't it outputing 2020-02-31?
How to output 2020-02-29 using DateTime? (Last day of the month).
$date = new DateTime("2020-01-31");
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-03-02
PHP DateTime::modify("+n month") adds between 28 to 31 days to the current day, depending of the month and year.
Solution
I suggest you increment months from the first day of the month by using the modify and format methods:
// Instanciates the DateTime object.
$date = new DateTime("2020-01-01");
// Adds a month to the date.
$date->modify("+1 month"); // 2020-02-01
// Format the date with "t" (gets the last day of the month).
$date->format("Y-m-t"); // 2020-02-29
Incrementing from the first day of the month will never raise the February problem which is quite a quite common, thinking that PHP DateTime will smartly add a month from 2020-02-29 and output 2020-03-31.
Why it happens?
In the Gregorian calendar, the average length of a month is 30.436875 days:
30 days in April, June, September and November;
31 days in January, March, May, July, August, October and December;
28 days or 29 days (in leap years) in February.
PHP will add to the current date the exact number of days there is in the given month.
Thus, PHP will adjust the date after the first increntation if you are incrementing from the
last day of the month.
E.g.:
Let's add a month from the final day of March (31th).
Since the current month (March) has 31 days in it, PHP will increment 31 days to the date. Adding 31 days from 2020-03-31 will result in skipping the whole month of April.
$date = new DateTime("2020-03-31"); // 2020-03-31
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-05-01 | Added 31 days (since March has 31 days).
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-06-01 | Added 31 days (since the new date is May 1st, which is a month with 31 days).
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-07-01 | Added 30 days
Now, let's add a month to the final day of April (30th).
We can see that since the next months all have 30+ days in it, final day will stay the same,
until February of the next year. Since February always has between 28 and 29 days, adding 31 days to it will pass the month, and resulting date will be March 2nd.
$date = new DateTime("2020-04-30");
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-05-30 | Added 30 days.
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-06-30 | Added 31 days.
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-07-30 | Added 30 days.
// ...
echo $date->modify("+1 month")->format("Y-m-d"); // 2021-01-30 | Added 31 days
echo $date->modify("+1 month")->format("Y-m-d"); // 2021-03-02 | Added 31 days (since January has 31 days).
echo $date->modify("+1 month")->format("Y-m-d"); // 2021-04-02 | Added 31 days (since the new date is March 2nd, which is a month with 31 days).
This is why it is recommended to increment months from the first day of the month,
since the 1st is common to all months.
$date = new DateTime("2020-01-01"); // 2020-01-01
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-02-01 | Added 31 days
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-03-01 | Added 29 days (since 2020 is leap year, yee haw).
echo $date->modify("+1 month")->format("Y-m-d"); // 2020-04-01 | Added 31 days
I'm making an assumption that you are programming in php. If so, the documentation indicates that you will receive the results you are getting php DateTime::modify().
The documentation specifically indicates to "Beware"
Example #2 Beware when adding or subtracting months
<?php
$date = new DateTime('2000-12-31');
$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";
$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";
?>
The above example will output:
2001-01-31
2001-03-03
If you just need to move to the end of the next +1 month, what we often do in R is go to the end of the current month and then add +1 day and then go to the end of the month again. If you know that you are always at the end of the month, then just add +1 day and then go to the end of the month.
Other posts have some additional suggestions in this space
How to find the last day of the month from date?
Example from this post:
$date = new DateTime('now');
$date->modify('last day of this month');
echo $date->format('Y-m-d');

PHP How do I find the number of days until the next January 1 (without specifying the year)?

How do I find out the number of days until the next January 1 without specifying a year?
I always want to know how many days until the next January 1, so I don't want to say "how many until Jan 1, 2020" or I'll need to reset my variable every year.
You can use DateTime objects to do the math. Create one object which is today, and another which is January 1, to which we then add a year, and then take the difference:
$today = new DateTime();
$jan1 = new DateTime('January 1');
$jan1->modify('+1 year');
$days = $today->diff($jan1)->days;
echo "$days days until January 1\n";
Output (on December 6)
25 days until January 1
Demo on 3v4l.org

Get the last day of the next 6 months prior to the current date

I have problem with my code that gets the last day of the next 6 months. My code gets first the last day of the current month then using the date function + 6 months.
$lastday = date("Y-m-t");
$lastdayaftersixmonth = strtotime("$lastday +6 months");
But my problem is when it comes to months that do not have same number of days specifically in case of august and february. If the last day for august is 31, supposedly it must return february 28 (or 29 for leap year), but it returns March 2.
$date = date('Y-m-t',strtotime('+6 month'));
echo $date;

Get day of the week for last 7 days?

I need the names of the day (Monday, Tuesday, Wednesday, Thuesday, Friday, Saturday, Today).
I know this is a newby question and PHP has a date() function. But I tried and can't figure out how...
According to the PHP Manual at http://php.net/manual/en/function.date.php, just use "l" as the format parameter to get the full name of the day.
So 23rd Mar 2014 is a Sunday, as echoed by
<?php
echo date ("l", mktime(0, 0, 0, 3, 23, 2014));
// Echoes Sunday
?>
To get past 7, 6, 5 or 10000 days (or number of days in the future) from the current day, according the information at this page, just use negative or positive integers in a string in the strtotime function:
<?php
$backcount = -4;
echo date ("l", strtotime("$backcount day"));
// Executed on 23 Mar 2014 will give Wednesday
?>
Knowing this, you can apply a for loop to get what you need. And if want "Today" instead of the full name of the current day, just add an if condition to handle the situation where the backcount variable is zero.
Achieving this using the DateTime Class and its format method.
The below code's output changes every day.. Since today is Sunday it starts from Monday , Tuesday... If you run this code on Tuesday , you will be getting output as Thursday , Friday , Saturday .. so on.
<?php
for($i=1;$i<=7;$i++) //<--- Since we know total days in a week is 7.
{
$date = new DateTime(); //<-- Grabs today's datetime
$date->add(new DateInterval('P'.$i.'D')); //<--- Passes the current value of $i to add days..
echo $date->format('l')."<br>";
}
OUTPUT :
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Working Demo
you can use jddayofweek to retrieve day of week, it has 3 mode for string containing the day of week, string containing the abbreviated day of week and int represent number of day in week
for($i=0;$i<7;$i++){
$x=jddayofweek($i,2);
var_dump($x);
}

Get the last Thursday, but only if it's the second Thursday in this sequence

I know I can get the last Thursday with this
$firstdate = strtotime('last thursday');
However, as of the time posting this question it will return
August 2nd, 2012
What I need is the last Thursday that follows this two week cycle:
August 9
August 23
September 6
September 20
And every second Thursday after that.
So if the current date is August 10, it will return August 9
If the current date is August 21, it will also return August 9 (even though the previous Thursday is August 16)
If the current date is August 24, it will return August 23
If the current date is Sept 1, it will also return August 23 (even though the previous Thursday is August 30)
Use the week number.
What you want are Thursdays of the weeks which have an even number.
Here is one way to do it:
function getLastEvenWeekThursday()
{
$lastThursday = strtotime('last thursday');
$weeknumber = date("W", $lastThursday);
if($weeknumber % 2 == 0)
return $lastThursday;
else
return $lastThursday - 3600*24*7;
}

Categories