PHP - Counting Leap Days in Date Range - php

I am trying to count the number of leap days within a date range.
This is what I have so far (adopted code from here)
<?php
$date_from = strtotime('2019-06-01');
$date_to = strtotime('2021-05-30');
$leapday_count = 0;
for($year=$date_from; $year<=$date_to; $year=strtotime('next year', $year)) {
if (date('L', $year)) {
$leapday_count++;
}
}
echo $leapday_count;
?>
Here is what I need help with:
The above code does only look at the years of the start and end date. For example it does not take into consideration if the start date is after Feb 29th. How can I make sure that it really takes the entire dates into consideration and not only the years of the dates?
Example expected result: 0 leap days between 2020-03-01 2024-02-28
Example expected result: 2 leap days between 2020-02-28 2024-03-01
Thanks in advance!

Stop doing date maths. It's hard.
Use datetime and diff
http://php.net/manual/en/datetime.diff.php
Example there
$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days');
to exactly answer the question.
$start = new DateTime('2020-03-01');
$end = new DateTime('2024-02-28');
$interval = ("last day of feb next year");
$current = clone $start;
$leapYears = 0;
while ($current->modify("last day of feb") && $current <= $end) {
if ($current->format('d') == 29 && $current > $start) {
$leapYears++;
}
$current->modify("+1 year");
}

Related

strtotime('-1 month') returning wrong date if month have 31 days

I'm trying make a function to return the exact date of previous months.
That is a example of my code:
// Dates in TimeStamp
$ts_now = strtotime('now');
$ts_month1 = strtotime("-1 month", $ts_now);
$ts_month2 = strtotime("-2 month", $ts_now);
$ts_month3 = strtotime("-3 month", $ts_now);
// Dates Formated
$date_now = date('Y-m-d', $ts_now);
$date_month1 = date('Y-m-d', $ts_month1);
$date_month2 = date('Y-m-d', $ts_month2);
$date_month3 = date('Y-m-d', $ts_month3);
//Output
echo $date_now; //2020-04-30
echo $date_month1; //2020-03-30
echo $date_month2; //2020-03-01
echo $date_month3; //2020-01-30
The problem is in $date_month2 that represents February, the output is 2020-03-01 instead 2020-02-29 and I suppose that problem will happen in months who have 30 days when present date have 31 days.
What is the best way to resolve that?
As you can see working with the end of the month can be problematic because of how PHP works with dates. Your best bet is to go back to the beginning of the month, do your date math (i.e. go backwards in time), and then go to the date you want. That way you can check to see if the current day is greater than the number of days in month. If so, use the last day of the month instead.
function getMonthsAgo(int $n): string {
$date = new DateTime();
$day = $date->format('j');
$date->modify('first day of this month')->modify('-' . $n . ' months');
if ($day > $date->format('t')) {
$day = $date->format('t');
}
$date->setDate($date->format('Y'), $date->format('m'), $day);
return $date->format('Y-m-d');
}
// Dates Formated
$date_now = date('Y-m-d');
$date_month1 = getMonthsAgo(1);
$date_month2 = getMonthsAgo(2);
$date_month3 = getMonthsAgo(3);
//Output
echo $date_now;
echo $date_month1;
echo $date_month2;
echo $date_month3;
Output:
2020-04-30
2020-03-30
2020-02-29
2020-01-30

Difference between 2 dates and skip Saturday and Sunday [duplicate]

This question already has answers here:
Day difference without weekends
(12 answers)
Closed 5 years ago.
In php i am using this code to calculate difference between two dates in number of days.
$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days');
I am getting the result, but is there any way to skip Saturday and Sunday if they are in between these dates.
See I Do this And Its Working Properly
You Can Try This.
$day = date('l',strtotime($datte));
if($day == 'Saturday' || $day == 'Sunday')
{
//SOME ACTION
}else{
//SOME ACTION
}
Where L is Define Day Full Name.
I create an array with all the date numeric representation of the day (0-6 for sun-sat).
And if it's between 1-5 (mon-fri) add it in the array.
The count of the array is then the number of days without sat-sundays.
<?php
$startdate = '2017-08-04';
$datetime1 = new DateTime($startdate);
$datetime2 = new DateTime('2017-08-07');
$interval = $datetime1->diff($datetime2);
$days = $interval->format('%a');
$arr =array();
for($i=0;$i<=$days;$i++){
$day = date("w Y-m-d l", strtotime($startdate) + $i*86400);
if((int)$day[0] >= 1 && (int)$day[0] <= 5 ) $arr[] = $day;
}
var_dump($arr);
echo "days excluding sat-sundays " . count($arr);
https://3v4l.org/pPLpb
Edit added = to count the end date also.
Edit; there was something not working with my previous strtotime, it gave correct resultat but counted Tuesdays as Mondays.
Changed it to $i*86400 instead and added more data in the array for debugging.
holidayes hold saturday and sunday counts;
w hold distance without holidays
<?php
$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-12-13');
$interval = $datetime1->diff($datetime2);
$distance=$interval->format('%R%a');
$hoildays=($distance/7)*2;// *2 cuz saturday and sunday
$W=$distance-($distance/$hoildays);
echo $W;
?>

Issues with Adding 1 month to a Unix time stamp

For some reason, I cannot get strtotime('+1 month) to work. Here is my code;
$Date = $_REQUEST['date']; //This is a unix time stamp
$Start = $_REQUEST['start']; //This is a unix time stamp
$End = $_REQUEST['end']; //This is a unix time stamp
to add a month onto my dates;
$monStart =strtotime('+1 month', $Start);
$monEnd =strtotime('+1 month', $End);
$monDate =strtotime('+1 month', $Date);
then to show my changed dates;
$vEnd = date('m/d/Y', $monEnd);
$vStart = date('m/d/Y', $monStart);
$vDate = date('m/d/Y', $monDate);
The problem that I have is that the supplied dates;
$Date = 1/31/2013
$Start = 1/01/2013
$End = 1/31/2013
Return;
$vDate = 3/03/2013
$vStart = 2/01/2013 //Only correct one
$vEnd = 3/03/2013
Please can someone help me?
It's jumping to March because today is 31sth Jan, and adding a month gives 31st Feb, which doesn't exist, so it's moving to the next valid date. This is a PHP bug. You can get more info on that at https://bugs.php.net/bug.php?id=44073
You can try with DateTime to over come this scenario. You can use this function for your requirement
function add_month($date_value, $months, $format = 'm/d/Y') {
$date = new DateTime($date_value);
$start_day = $date->format('j');
$date->modify("+{$months} month");
$end_day = $date->format('j');
if ($start_day != $end_day)
$date->modify('last day of last month');
return $date->format($format);
}
Now you can call :
$vEnd = add_month($monEnd, 1);
$vStart = add_month($monStart, 1);
$vDate = add_month($monDate, 1);
This will give you :
$vDate = '02/28/2013';
$vStart = '02/01/2013';
$vEnd = '02/28/2013';
Hope this helps you :)
DateTime is much better for handling date math as it account for things like days in the month:
$dt = new DateTime('2013-02-01');
$dt->modify('+1 month');
echo $dt->format('Y-m-d');
See it in action
Since you're using timestamps it might look like this:
$dt = new DateTime('#'.$_REQUEST['start']);
$dt->modify('+1 month');
echo $dt->format('m/d/Y');

How to list dates in yyyy_mm format with PHP using a loop?

What's the cleanest way to use a loop in PHP to list dates in the following way?
2011_10
2011_09
2011_08
2011_07
2011_06
...
2010_03
2009_02
2009_01
2009_12
2009_11
The key elements here:
Should be as simple as possible - I would prefer one for loop instead of two.
Should list this month's date as the first date, and should stop at a fixed point (2009-11)
Should not break in the future (eg: subtracting 30 days worth of seconds will probably work but will eventually break as there are not an exact amount of seconds on each month)
Had to make a few tweaks to the solution:
// Set timezone
date_default_timezone_set('UTC');
// Start date
$date = date('Y').'-'.date('m').'-01';
// End date
$end_date = '2009-1-1';
while (strtotime($date) >= strtotime($end_date))
{
$date = date ("Y-m-d", strtotime("-1 month", strtotime($date)));
echo substr($date,0,7);
echo "\n";
}
Maybe this little code does the thing? :
more complicated situations.
<?php
// Set timezone
date_default_timezone_set('UTC');
// Start date
$date = '2009-12-06';
// End date
$end_date = '2020-12-31';
while (strtotime($date) <= strtotime($end_date)) {
echo "$date\n";
$date = date ("Y-m-d", strtotime("+1 day", strtotime($date)));
}
?>
The credit goes to: http://www.if-not-true-then-false.com/2009/php-loop-through-dates-from-date-to-date-with-strtotime-function/
This is what im guessing your asking for cause it doesnt really make sense......
$startmonth = date("m");
$endmonth = 7;
$startyear = date("Y");
$endyear = 2012;
//First for loop to loop threw years
for($i=$startyear; $i<=$endyear; $i++, $startmonth=0) {
//Second for loop to loop threw months
for($o=$startmonth; $o<=12; $o++) {
//If statement to check and throw stop when at limits
if($i == $endyear && $o <= $endmonth)
echo $i."_".$o."<br/>";
else
break;
}
}
Will output:
2012_0
2012_1
2012_2
2012_3
2012_4
2012_5
2012_6
2012_7
PHP 5.3 introduces some great improvements to date/time processing in PHP. For example, the first day of, DateInterval and DatePeriod being used below.
$start = new DateTime('first day of this month');
$end = new DateTime('2009-11-01');
$interval = new DateInterval('P1M');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $date) {
echo $date->format('Y_m') . PHP_EOL;
}

How to find first day of the next month and remaining days till this date with PHP

How can I find first day of the next month and the remaining days till this day from the present day?
Thank you
Create a timestamp for 00:00 on the first day of next month:
$firstDayNextMonth = strtotime('first day of next month');
The number of days til that date is the number of seconds between now and then divided by (24 * 60 * 60).
$daysTilNextMonth = ($firstDayNextMonth - time()) / (24 * 3600);
$firstDayNextMonth = date('Y-m-d', strtotime('first day of next month'));
For getting first day after two months from current
$firstDayAfterTwoMonths = date('Y-m-d', strtotime('first day of +2 month'));
You can use DateTime object like this to find out the first day of next month like this:
$date = new DateTime('first day of next month');
You can do this to know how many days left from now to the first day of next month:
$date = new DateTime('now');
$nowTimestamp = $date->getTimestamp();
$date->modify('first day of next month');
$firstDayOfNextMonthTimestamp = $date->getTimestamp();
echo ($firstDayOfNextMonthTimestamp - $nowTimestamp) / 86400;
The easiest and quickest way is to use strtotime() which recognizes 'first day next month';
$firstDayNextMonth = date('Y-m-d', strtotime('first day next month'));
Since I googled this and came to this answer, I figured I'd include a more modern answer that works for PHP 5.3.0+.
//Your starting date as DateTime
$currentDate = new DateTime(date('Y-m-d'));
//Add 1 month
$currentDate->add(new DateInterval('P1M'));
//Get the first day of the next month as string
$firstDayOfNextMonth = $currentDate->format('Y-m-1');
You can get the first of the next month with this:
$now = getdate();
$nextmonth = ($now['mon'] + 1) % 13 + 1;
$year = $now['year'];
if($nextmonth == 1)
$year++;
$thefirst = gmmktime(0, 0, 0, $nextmonth, $year);
With this example, $thefirst will be the UNIX timestamp for the first of the next month. Use date to format it to your liking.
This will give you the remaining days in the month:
$now = getdate();
$months = array(
31,
28 + ($now['year'] % 4 == 0 ? 1 : 0), // Support for leap years!
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
);
$days = $months[$now['mon'] - 1];
$daysleft = $days - $now['mday'];
The number of days left will be stored in $daysleft.
Hope this helps!
$firstDayNextMonth = date('Y-m-d', mktime(0, 0, 0, date('m')+1, 1, date('Y')));
As another poster has mentioned the DateInterval object does not give accurate results for the next month when you use dates such as 1/31/2016 or 8/31/2016 as it skips the next month. My solution was to still use the DateInterval object but reformat your current date to be the first day of the current month prior to utilizing the DateInterval.
$currentDate = '8/31/2016';
$date = new DateTime(date("n", strtotime($currentDate))."/1/".date("Y", strtotime($currentDate)));
//add 1 month
$date->add(new DateInterval('P1M'));
$currentDate=$date->format('m/1/Y');
echo($currentDate);
easiest way to get the last day of the month
date('Y-m-d', mktime(0, 0, 0, date('m')+1, 1, date('Y')));
I took mattbasta's approach because it's able to get the 'first day of next month' with a given date, but there is a tiny problem in calculating the $nextmonth. The fix is as below:
$now = getdate();
$nextmonth = ($now['mon'] + 1) % 13 + 1;
$year = $now['year'];
if($nextmonth == 1)
$year++;
else
$nextmonth--;
$thefirst = gmmktime(0, 0, 0, $nextmonth, $year);
I initially thought about using a DateInterval object (as discussed above in another answer) but it is not reliable. For example, if the current DateTime is 31 January and then we add on a month (to get the next month) then it will skip February completely!
Here is my solution:
function start_of_next_month(DateTime $datetime)
{
$year = (int) $datetime->format('Y');
$month = (int) $datetime->format('n');
$month += 1;
if ($month === 13)
{
$month = 1;
$year += 1;
}
return new DateTime($year . '-' . $month . '-01');
}
Even easier way to get first and last day of next month
$first = strttotime("first day of next month");
$last = strttotime("last day of next month");
You could do something like this. To have this functionality, you need to make use of a php library available in https://packagist.org/packages/ishworkh/navigable-date.
With that is really easy to do what you're asking for here.
For e.g:
$format = 'Y-m-d H:i:s';
$Date = \NavigableDate\NavigableDateFacade::create('2017-02-24');
var_dump($Date->format($format));
$resetTime = true;
$resetDays = true;
$NextMonth = $Date->nextMonth($resetTime, $resetDays);
var_dump($NextMonth->format($format));
$DayUntilFirstOfNextMonth = $NextMonth->getDifference($Date);
var_dump('Days left:' . $DayUntilFirstOfNextMonth->format('%d'));
gives you ouput:
string(19) "2017-02-24 00:00:00"
string(19) "2017-03-01 00:00:00"
string(11) "Days left:5"
Note: Additionally this library let you navigate through dates by day(s), week(s), year(s) forward or backward. For more information look into its README.
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
To get the first day of next month a clean solution:
<?php
$date = new DateTimeInmutable('now');
$date->modify('first day of next month');//here the magic occurs
echo $date->format('Y-m-d') . '\n';
Since you just want to calculate it I suggest using DateTimeInmutable class.
using the class DateTime and $date->modify('first day of next month'); will modify your original date value.
$month = date('m')+1;
if ($month<10) {
$month = '0'.$month;
}
echo date('Y-').$month.'-01';
Simplest way to achieve this. You can echo or store into variable.
I came up with this for my needs:
if(date('m') == 12) { $next_month = 1; } else { $next_month = date('m')+1; }
if($next_month == 1) { $year_start = date('Y')+1; } else { $year_start = date('Y'); }
$date_start_of_next_month = $year_start . '-' . $next_month . '-01 00:00:00';
if($next_month == 12) { $month_after = 1; } else { $month_after = $next_month+1; }
if($month_after == 1) { $year_end = date('Y')+1; } else { $year_end = date('Y'); }
$date_start_of_month_after_next = $year_end . '-' . $month_after . '-01 00:00:00';
Please note that instead of getting $date_end_of_next_month I chose to go with a $date_start_of_month_after_next date, it avoids the hassles with leap years and months containing different number of days.
You can simply use the >= comparaision sign for $date_start_of_next_month and the < one for $date_start_of_month_after_next.
If you prefer a timestamp format for the date, from there you will want to apply the strtotime() native function of PHP on these two variables.
You can use the php date method to find the current month and date, and then you would need to have a short list to find how many days in that month and subtract (leap year would require extra work).

Categories