Increment one month to date 2020-01-30 cancels the next month - php

Given date is 2019-12-30, and I want to add 1 month for every iteration in the loop (so 5 times).
I wrote this code:
$begin_date = '2019-12-30';
for ($i = 1; $i <= 5; $i++) {
echo '<p>' . $begin_date . '</p>';
$time = strtotime($begin_date);
$begin_date = date("Y-m-d", strtotime("+1 month", $time));
}
And I got the following result
2019-12-30
2019-01-30
2019-03-01 invalid -- I would expect 2019-02-28, at least last day
2019-04-01 invalid
2019-05-01 invalid

You can use DateTime objects, then modify the object to the last day of the next month. If the day of the month is greater than 30, subtract one (as it can never be higher than 31 anyways).
$begin_date = '2019-12-30';
$date = new DateTime($begin_date);
for ($i = 1; $i <= 5; $i++) {
echo '<p>'.$date->format("Y-m-d")."</p>\n";
$date->modify("last day of next month");
if ($date->format("d") > 30) {
$date->modify("-1 day");
}
}
Live demo at https://3v4l.org/jhX95
If you're looking for a more dynamic way (in case the date is not always the 30th), you can duplicate the original object, and subtract the current day of month from the original day of the month.
$begin_date = '2019-12-30';
$date = new DateTime($begin_date);
$original_date = clone $date;
for ($i = 1; $i <= 5; $i++) {
echo '<p>'.$date->format("Y-m-d")."</p>\n";
$date->modify("last day of next month");
if ($date->format("d") > $original_date->format("d")) {
$date->modify("-".($date->format("d") - $original_date->format("d"))." day");
}
}
Live demo at https://3v4l.org/kkOkM

Related

List Weeks of Year in a Month in PHP

The scenario I have here is that, I need to select a Year and Month. And I need to show the Weeks in that currently selected Month. Let me explain it here ...
2017 -> Oct -> Week N
( this should be the Week of year . E.x this week is #40 for 2017.) So I need to list number of weeks that lies in Oct for this year.
Thank you.
Considered Michel's solution How to get year-sensitive calendar week ? to avoid excess week from previous december to current january.
function getWeekNo( $date ) {
$t = strtotime($date) ;
$w=(int)date('W', $t);
$m=(int)date('n', $t);
$w=($w==1?($m==12?53:1):($w>=51?($m==1?0:$w):$w));
return $w ;
}
$month = '10-2017' ;
$firstDay = '01-' . $month ;
$lastDay = Date('t-m-Y', strtotime($firstDay)) ;
$firstWeek = getWeekNo($firstDay) ;
$lastWeek = getWeekNo($lastDay) ;
for( $i = $firstWeek; $i <= $lastWeek; $i++ ) {
//echo "Week $i <br/>";
echo "Week " . ($i + 1) . "<br/>"; //if you want to start january 1st as Week 1
}
Based on Desai's answer, I tried this on Carbon PHP ( on Laravel 5.5 ). I'm posting my answer in case anyone is looking for this.
$month = 10;
$year = 2017;
$date = \Carbon\Carbon::create($year,$month);
$startOfMonth = $date->startOfMonth();
$endOfMonth = $date->copy()->endOfMonth();
$startWeek = $startOfMonth->format('W');
$endWeek = $endOfMonth->copy()->format('W');
for( $i = $startWeek; $i <= $endWeek; $i++ )
{
echo "Week #" . $i;
}
Thank you all for your answers. Have a great day.
Try this code: Get first day and last day of month, count week numbers and loop over it
$year = "2017";
$month = "10";
$day = "01";
$first_date = $year."-".$month."-".$day;
$last_date = date("Y-m-t",strtotime($first_date));
$first_week = date("W",strtotime($first_date));
$last_week = date("W",strtotime($last_date));
for($i=$first_week;$i<=$last_week;$i++)
{
echo "Week #".$i.", ";
}
Note that October has total 6 weeks. 1st date on Sunday last on Tuesday
DEMO
According to carbon documentation at CarbonDocs
$dt = Carbon::parse('2012-9-5 23:26:11.123789');
var_dump($dt->weekOfYear);
Sorry, I can't reply yet to the first comment, but the above solution is not working correctly if the last day of month have in first week of new year (test case: 2019-12-01).
I made a quick fix (based on original code):
// Input date format: YYYY-mm-dd
function getMonthWeekNumbers( $first_date )
{
$last_date = date( "Y-m-t",strtotime( $first_date ) );
$first_week = date( "W",strtotime( $first_date ) );
$last_week = date( "W",strtotime( $last_date ) );
// If last day of month have on first week on next year, subtract a week from the date
if( $last_week == '01' )
{
$last_week = date( "W",( strtotime( $last_date )-604800 ) );
}
for( $i=$first_week; $i <= $last_week; $i++ )
{
echo "Week #".$i.", ";
}
}
It working fine with any input dates.
DEMO

PHP script date modify issue when using in loop

EDITED directly to the problem :
The code :
<?php
$date = new DateTime('2000-01-31'); // or whatever
for ($i = 0; $i < 100; $i++) {
$currentDay = $date->format('d');
if ($currentDay < $date->format('t')) {
$date->modify('+1 month');
if ($date->format('d') < $currentDay) {
$date->modify('last day of previous month');
}
} else {
$date->modify('last day of next month');
}
echo $date->format('Y-m-d') . "<br>";
}
So, if starting date is 2000-01-31, it works fine. That's just because 31 is the last day of january, so, any other month it will put the last date of the month.
But, if u change starting date to 2000-01-30, it's broken. That's because 30 january is not the last day in january. But anyway, 30 january is greater than days in february, so it transform date to 28/29 february. Since 28/29 february is the last day in february, it proceed the code like when this date == number of days in the month, and on the next iteration instead of putting 30 march, it puts 'last day of next month' (31 of march).
And that's not the unique case. Same thing if u put starting date for example 30-08-2000. 30 is not the last day of august, so it change the date to 30 of september, 30 september is the last day of the september, so it change the date to 31 of octomber, but it's not what I expect.
If I've understood your question correctly then this should be what you're after:
$date = new DateTime('2000-01-31'); // or whatever
$day = $date->format('d');
$date->setDate($date->format('Y'), $date->format('m'), 1);
for ($i = 0; $i < 100; $i++) {
$date->modify('+1 month');
echo echo $date->format('t') < $day ? $date->format('Y-m-t') : $date->format('Y-m-' . $day);
echo '<br />';
}
Hope this helps!
Do I understand correctly that
you want to print the same day for all following months
in case it's higher than the maximum days in the month, last day of that month should be used instead
If yes, this could work:
<?php
$date = new DateTime('2000-01-28'); // or whatever
#echo $date->format('d')." ".$date->format('t');
$expectedDay = $date->format('d');
$month = $date->format('m');
$year = $date->format('Y');
for ($i = 0; $i < 100; $i++) {
echo $date->format('Y-m-d') . "<br>";
if ($month++ == 12) {
$year++;
$month = 1;
}
$date->modify("${year}-${month}-1");
if ($expectedDay > $date->format('t')) {
$day = $date->format('t');
} else {
$day = $expectedDay;
}
$date->modify("${year}-${month}-${day}");
}

how to get each month last date in php, year will change according to cuurent date

i want to get each month last date for every year. year will change and it should take from currdate.
i tried below one
$day = date( 't-m-Y' );
But am writing different if condition for each month. So in this code i want to give constant month. year will change. Is it possible to do like that?
can anyone help me to do this.
Check demo here.
<?php
$year = date("Y");
echo $year . "\n";
for ($i = 1; $i <= 12; $i++)
{
$month = strtotime("$year-$i");
echo date("t", $month) . "\n";
}
output:
2017
31
28
31
30
31
30
31
31
30
31
30
31
// get Current Date
$date = date('j-m-Y');
echo date("j-m-y", strtotime($date));//Current Month date with Current year
echo "Current Year =".date("Y", strtotime($date))." , Current Month Days =".date("t", strtotime($date))." , Current Month Last Day Date =".date("t-m-Y", strtotime($date));
t returns the number of days in the month of a given date
so you can pass the dynamic year and constant month like this to know the last day of month
<?php
$year ="2017";
echo date("Y-m-t", strtotime(date("$year-04-d")));
?>
OUTPUT:
2017-04-30
update 1:
$date = new DateTime('last day of 2017-04');
echo $date->format('Y-m-d');
you can check this code
$a_date = "2017-04-17";
echo date("Y-m-t", strtotime($a_date));
or use
$current_date = "2017-04-17";
$date = new DateTime($current_date);
$date->modify('last day of this month');
echo $date->format('Y-m-d');
echo $first_date = date('Y-m-d',strtotime('first day of this month'));
echo $last_date = date('Y-m-d',strtotime('last day of this month'));
this is your code
echo $last_date = date('t-03-Y');
and this is output
30-03-2017
The last date of the month stays the same year in and year out, i.e. December will have 31 days whether referencing this year or the next. The only thing that changes is on what day of the week the last day of a month falls. So, the following indicates how to obtain all this data for the current month and the remaining months of the year as well as for next year.
<?php
// preliminaries
try {
$date = new DateTime("#".time());
} catch (Exception $e) {
echo $e->getMessage();
exit(1);
}
$strDate = $date->format("Y-n-t");
list($Y,$m,$t) = explode("-",$strDate);
$offset = 12 - $m;
$max = $offset + 1; // include current month
//this year starting with current month:
for ( $i=0; $i < $max; $i++ ){
$mo_day_one_yr = "$Y-" . ( $m + $i ) . "-1";
$date->modify( $mo_day_one_yr );
echo $date->format("D, t-M-Y"),"\n";
if( $i == ( $max -1 )) echo "\n";
}
// next year:
for ( $i=1, $Y+=1, $max=12; $i <= $max; $i++ ){
$mo_day_one_yr = "$Y-$i-1";
$date->modify( $mo_day_one_yr );
echo $date->format("D, t-M-Y"),"\n";
}
Live code
Note, the DateTime object gets initialized with a Unix timestamp string but one could also just simply provide a parameter of "now". Also, the try-catch is a good idea just in case an issue should arise in terms of instantiating the DateTime object.

PHP: DatePeriod with last day of month

I'd like to work with PHP DateInterval to iterate through months:
$from = new DateTime();
$from->setDate(2014, 1, 31);
$period = new DatePeriod($from, new DateInterval('P1M'), 12);
I'd expect it to returns 31 January, 28 February (as the DateInterval is 1 month), but it actually returns 31 January, 3 March, 3 of April... hence skipping February.
Is there any way to do this simply?
Thanks!
EDIT : as a refernece, here is a solution that seems to cover most use cases:
$date = new DateTime('2014-01-31');
$start = $date->format('n');
for ($i = 0; $i < 28; $i++) {
$current = clone $date;
$current->modify('+'.$i.' month');
if ($current->format('n') > ($start % 12) && $start !== 12) {
$current->modify('last day of last month');
}
$start++;
echo $current->format('Y-m-d').PHP_EOL;
}
You can use DateTime::modify():
$date = new DateTime('last day of january');
echo $date->format('Y-m-d').PHP_EOL;
for ($i = 1; $i < 12; $i++) {
$date->modify('last day of next month');
echo $date->format('Y-m-d').PHP_EOL;
}
EDIT: I think I didn't understand your question clearly. Here is a new version:
$date = new DateTime('2014-01-31');
for ($i = 0; $i < 12; $i++) {
$current = clone $date;
$current->modify('+'.$i.' month');
if ($current->format('n') > $i + 1) {
$current->modify('last day of last month');
}
echo $current->format('Y-m-d').PHP_EOL;
}
The issue is cause by the variance between the last day in each of the months within the range. ie. February ending on 28 instead of 31 and the addition of 1 month from the last day 2014-01-31 + 1 month = 2014-03-03 https://3v4l.org/Y42QJ
To resolve the issue with DatePeriod and simplify it a bit, adjust the initial date by resetting the specified date to the first day of the specified month, by using first day of this month.
Then during iteration, you can modify the date period date by using last day of this month to retrieve the bounds of the currently iterated month.
Example: https://3v4l.org/889mB
$from = new DateTime('2014-01-31');
$from->modify('first day of this month'); //2014-01-01
$period = new DatePeriod($from, new DateInterval('P1M'), 12);
foreach ($period as $date) {
echo $date->modify('last day of this month')->format('Y-m-d');
}
Result:
2014-01-31
2014-02-28
2014-03-31
2014-04-30
2014-05-31
2014-06-30
2014-07-31
2014-08-31
2014-09-30
2014-10-31
2014-11-30
2014-12-31
2015-01-31
Then to expand on this approach, in order to retrieve the desired day from the specified date, such as the 29th. You can extract the specified day and adjust the currently iterated month as needed when the day is out of bounds for that month.
Example: https://3v4l.org/SlEJc
$from = new DateTime('2014-01-29');
$day = $from->format('j');
$from->modify('first day of this month'); //2014-01-01
$period = new DatePeriod($from, new DateInterval('P1M'), 12);
foreach ($period as $date) {
$lastDay = clone $date;
$lastDay->modify('last day of this month');
$date->setDate($date->format('Y'), $date->format('n'), $day);
if ($date > $lastDay) {
$date = $lastDay;
}
echo $date->format('Y-m-d');
}
Result:
2014-01-29
2014-02-28 #notice the last day of february is used
2014-03-29
2014-04-29
2014-05-29
2014-06-29
2014-07-29
2014-08-29
2014-09-29
2014-10-29
2014-11-29
2014-12-29
2015-01-29
You may try like this:
$date = new DateTime();
$lastDayOfMonth = $date->modify(
sprintf('+%d days', $date->format('t') - $date->format('j'))
);
I would do it probably like this
$max = array (
31,28,31,30,31,30,31,31,30,31,30,31
); //days in month
$month = 1;
$year = 2014;
$day = 31;
$iterate = 12;
$dates = array();
for ($i = 0;$i < $iterate;$i++) {
$tmp_month = ($month + $i) % 12;
$tmp_year = $year + floor($month+$i)/12;
$tmp_day = min($day, $max[$tmp_month]);
$tmp = new DateTime();
$tmp->setDate($tmp_year, $tmp_month + 1, $tmp_day);
$dates[] = $tmp;
}
var_dump($dates);
This keeps to the same day each month if possible

Find the week start and end dates of all weeks between two week numbers

I am trying to get the start date and end dates of all weeks between two week numbers.
That is one of my date is 2014-05-17 and its week number is 20 and other date is 2014-08-13 and its week number is 33.
My task is to get start and end dates of all weeks between 20 and 33. Here Sunday is the week start and Saturday week end.
$signupweek='2014-05-17';
$signupweek=date("W",strtotime($signupdate));
//week number of current date.
$weekNumber = date("W");
Can anyone help to find the dates.
try this
$signupdate='2014-05-17';
$signupweek=date("W",strtotime($signupdate));
$year=date("Y",strtotime($signupdate));
$currentweek = date("W");
for($i=$signupweek;$i<=$currentweek;$i++) {
$result=getWeek($i,$year);
echo "Week:".$i." Start date:".$result['start']." End date:".$result['end']."<br>";
}
function getWeek($week, $year) {
$dto = new DateTime();
$result['start'] = $dto->setISODate($year, $week, 0)->format('Y-m-d');
$result['end'] = $dto->setISODate($year, $week, 6)->format('Y-m-d');
return $result;
}
Output
Week:20 Start date:2014-05-11 End date:2014-05-17
Week:21 Start date:2014-05-18 End date:2014-05-24
Week:22 Start date:2014-05-25 End date:2014-05-31
Week:23 Start date:2014-06-01 End date:2014-06-07
Week:24 Start date:2014-06-08 End date:2014-06-14
Week:25 Start date:2014-06-15 End date:2014-06-21
Week:26 Start date:2014-06-22 End date:2014-06-28
Week:27 Start date:2014-06-29 End date:2014-07-05
Week:28 Start date:2014-07-06 End date:2014-07-12
Week:29 Start date:2014-07-13 End date:2014-07-19
Week:30 Start date:2014-07-20 End date:2014-07-26
Week:31 Start date:2014-07-27 End date:2014-08-02
Week:32 Start date:2014-08-03 End date:2014-08-09
Week:33 Start date:2014-08-10 End date:2014-08-16
Another method...
If you have a date, from that date you can find the start date and end date of that week. But here week number is not used.
For example:
You have a date 2014-08-13, then required start date is 2014-08-10 and end date is 2014-08-16.
PHP code is
$signupweek='2014-8-13';
/*start day*/
for($i = 0; $i <7 ; $i++)
{
$date = date('Y-m-d', strtotime("-".$i."days", strtotime($signupweek)));
$dayName = date('D', strtotime($date));
if($dayName == "Sun")
{
echo "start day is ". $date."<br>";
}
}
/*end day*/
for($i = 0; $i <7 ; $i++)
{
$date = date('Y-m-d', strtotime("+".$i."days", strtotime($signupweek)));
$dayName = date('D', strtotime($date));
if($dayName == "Sat")
{
echo "end day is ". $date."<br>";
}
}
OUTPUT
start day is 2014-08-10
end day is 2014-08-16
Hope this is useful..
Here's an example that implements the function from this answer:
$signupweek = '2014-05-17';
$signupweek = date("W", strtotime($signupweek));
$current_week = date('W');
$output = array();
// Loop through the weeks BETWEEN your given weeks
// to include the start and end week, remove the +1 below and make
// it $i <= $current_week
for($i = $signupweek + 1; $i < $current_week; $i++) {
// Get the start and end for the current week ($i)
$dates = getStartAndEndDate($i, '2014');
// if the start or end of the week is greater than now, skip it
if(strtotime($dates['start']) > time() or strtotime($dates['end']) > time())
continue;
// Add to output array
$output[] = $dates;
}
function getStartAndEndDate($week, $year)
{
$time = strtotime("1 January $year", time());
$day = date('w', $time);
$time += ((7 * $week) + 1 - $day) * 24 * 3600;
$return['start'] = date('Y-n-j', $time);
$time += 6 * 24 * 3600;
$return['end'] = date('Y-n-j', $time);
return $return;
}
Output
Try this:
$startTime = "2014-05-17";
$startWeek = 20;
$endWeek = 33;
for ($i = 0; $i <= ($endWeek - $startWeek); $i++) {
$days = $i * 7;
echo date("Y-m-d", strtotime($startTime . "+$days day")).'<br />';
}
Unfortunately, it seems that 2014-08-13 is not the start of week 33. 2014-08-16 is.
You can now use DateTime to get start/end dates of week(s)
function getDateRangeForAllWeeks($start, $end){
$fweek = getDateRangeForWeek($start);
$lweek = getDateRangeForWeek($end);
$week_dates = [];
while($fweek['sunday']!=$lweek['sunday']){
$week_dates [] = $fweek;
$date = new DateTime($fweek['sunday']);
$date->modify('next day');
$fweek = getDateRangeForWeek($date->format("Y-m-d"));
}
$week_dates [] = $lweek;
return $week_dates;
}
function getDateRangeForWeek($date){
$dateTime = new DateTime($date);
$monday = clone $dateTime->modify(('Sunday' == $dateTime->format('l')) ? 'Monday last week' : 'Monday this week');
$sunday = clone $dateTime->modify('Sunday this week');
return ['monday'=>$monday->format("Y-m-d"), 'sunday'=>$sunday->format("Y-m-d")];
}
print_r( getDateRangeForWeek("2016-05-07") );
print_r( getDateRangeForAllWeeks("2015-11-07", "2016-02-15") );

Categories