Is it possible to get the current day in next 12 months?
Take a look at these scenarios:
Today is 2014-05-09
next month will be 2014-06-09
and so on and so fourth
what if today is 2014-01-31
next month is 2014-02-28
Other examples
what if today is 2014-05-31
next month will be 2014-06-30
thanks
try this.It will work fine even if date is last day of the month also
$date = "2013-03-31";
$d1 = explode("-",$date);
$i = 0;
while ($i < 12)
{
$j = $d1[2];
if(cal_days_in_month(CAL_GREGORIAN, $d1[1], $d1[0]) < $d1[2])
$j = cal_days_in_month(CAL_GREGORIAN, $d1[1], $d1[0]) ;
echo $d1[0]."-".$d1[1]."-".$j."<br>";
$d1[1]++;
if($d1[1] == 13)
{
$d1[0]++;
$d1[1] = 1;
}
$i++;
if($d1[1] < 10)
$d1[1]="0".$d1[1];
}
You can add a DateInterval to the given date. But there is no unified logic in your examples.
For example:
$date = new DateTime( '2014-01-31' );
$aMonthLater = clone $date;
$aMonthLater->add( new DateInterval( 'P1M' ) );
var_dump(
$date->format( DateTime::ISO8601 ),
$aMonthLater->format( DateTime::ISO8601 )
);
This will result in an output like:
2014-01-31T00:00:00+01:00
2014-03-03T00:00:00+01:00
Thus adding a month will actually add a whole month – you example (skipping from 2014-01-31 to 2014-02-28) does not add a full month.
See DateTime::add()
Related
I am creating a app where user can create monthly event (Just like Google/Outlook), so if user has selected 31st date of any month and next month have 30 days than all next dates are changing to 30th.
Same goes with 30th, lets say user selected 30th of December than after Feb all next date is changing to 28th.
so if in next month days are lesser than user's selected date its changing the date to that.
Example :
Start Date : 2020-10-31
End Date : 2021-11-30
$diffInMonths = $startDate->diffInMonths($endDate);
for ($i = 0; $i <= $diffInMonths; $i++) {
$newStartDate = $i == 0 ? $startDate : $startDate->addMonthWithNoOverflow();
print('<pre>' . print_r($newStartDate->toDateString(), true) . '</pre>');
}
its giving output like this
2020-10-31
2020-11-30
2020-12-30
2021-01-30
2021-02-28
2021-03-28
2021-04-28
2021-05-28
2021-06-28
2021-07-28
2021-08-28
2021-09-28
2021-10-28
What i need is skip the month if in that month have less days than user;s selected date. With Above example the correct output should be
2020-10-31 //November has less than 31st day
2020-12-31
2021-01-31 //Feb has less than 31st day
2021-03-31 //April has less than 31st day
2021-05-31 //June & July has less than 31st day
2021-07-31
2021-08-31 //September has less than 31st day
2021-10-31
Struggling on this from last 2-3 days so any Kind of help or guidance will made my day :)
This might be dumb way of doing this, but as i am running out of time so here is solution
$dateRange = Carbon::parse($callPlanner->start_date)->toPeriod($callPlanner->end_date, 1, 'month');
$startDate = Carbon::parse($callPlanner->start_date);
foreach ($dateRange as $date) {
// compare the event date with end of month date
if ($startDate->day <= $date->endOfMonth()->day) {
//create new date with this month's year, month and event start date
$newDate = Carbon::createFromDate($date->endOfMonth()->year, $date->endOfMonth()->month, $startDate->day);
echo $newDate->toDateString(). "\n";
}
}
addMonths() add a month to a date. with no overflow, it makes the end of the next month, which is suppose 2020-02-29. in the next step it adds another month to 2020-02-29 and that makes the next date 2020-03-29 because it just added a month. you don't call it to update the date. so your solution would be using lastOfMonth()
$startDate = Carbon::parse('2020-01-31');
$endDate = Carbon::parse('2020-12-31');
$diffInMonths = $startDate->diffInMonths($endDate);
for ($i = 0; $i <= $diffInMonths; $i++) {
$newStartDate = $i == 0 ? $startDate : $startDate->addMonthWithNoOverflow()->lastOfMonth();
print('<pre>' . print_r($newStartDate->toDateString(), true) . '</pre>');
}
which will give you dates like
2020-01-31
2020-02-29
2020-03-31
2020-04-30
2020-05-31
2020-06-30
2020-07-31
2020-08-31
2020-09-30
2020-10-31
2020-11-30
2020-12-31
with addMonth you can't skip months that has less days. you have to check it manually with some condition. like
$startDate = Carbon::parse('2020-10-31');
$endDate = Carbon::parse('2021-11-30');
$highestDate = $startDate->format('d');
$diffInMonths = $startDate->diffInMonths($endDate);
for ($i = 0; $i <= $diffInMonths; $i++) {
$newStartDate = $i == 0 ? $startDate : $startDate->addMonthWithNoOverflow()->lastOfMonth();
if ($newStartDate->format('d') >= $highestDate) {
print('<pre>' . print_r($newStartDate->toDateString(), true) . '</pre>');
}
}
the output is
2020-10-31
2020-12-31
2021-01-31
2021-03-31
2021-05-31
2021-07-31
2021-08-31
2021-10-31
In such cases (similar to monthly subscriptions issues), it could be better to always start from the first date instead of chaining the additions:
$diffInMonths = $startDate->diffInMonths($endDate);
for ($i = 0; $i <= $diffInMonths; $i++) {
$newStartDate = $startDate->copy()->addMonthsWithNoOverflow($i + 1);
print('<pre>' . print_r($newStartDate->toDateString(), true) . '</pre>');
}
This way, you get last day of month is the day is not available but it does not change next iterations.
Note that ->copy() is not needed if you use CarbonImmutable.
How to manipulate the date and exclude saturday and sunday?. The objective is, I need to create a cron job that will run and execute on datas that were created 5 days ago,"BUT", saturday and sunday shouldn't be included in that 5 days period.
here's what I have so far
$numdays = 5;
$today = strtotime('now');
$start = date('Y-m-d',strtotime('-'.$numdays.' day',$today));
echo $start;
if you try to run my code snippet above, it will show you the exact date 5 days ago 2016-02-10. But that one doesn't "exclude" saturday and sunday in the computation. it should be be 2016-02-08. So how to do that?
You can use PHP's date week of day, there are several versions, here is one using N:
<?php
$current = new DateTime();
$interval = new DateInterval('P1D');
$x = 5;
while ($x > 1) {
// Check if day of week is not saturday/sunday (1 => Monday ... 7 -> Sunday)
if ($current->format('N') >= 6) {
$x++;
}
$current->sub($interval);
$x--;
}
echo $current->format('Y-m-d') . PHP_EOL;
Example Run.
You can get a whole week and discard the weekends, keeping the furthest element in the array as a result.
$days = array_filter(array_map(function ($daysBack) {
$date = new \DateTimeImmutable("$daysBack days ago", new \DateTimeZone('UTC'));
return (!in_array($date->format('N'), [6, 7])) ? $date : null;
}, Range(1, 7)));
$fiveWorkingDaysAgo = end($days);
I want to calculate a date based on a timestamp and some other informations.
My function looks like:
function getLastDeliveryDate($timestamp,$endOfMonth=true,$extraMonth=0){
$days = 0;
$extraDays = 0;
$endOfCurrentMonth = 0;
$tsDay = 86400;
if($endOfMonth){
$endOfCurrentMonth = date("t", $timestamp) - date("d",$timestamp);
//rest of days in current month. In this sample 16 days
}
for($i=0;$i<$extraMonth;$i++){
$x = $i + 1;
$date = new DateTime(date("Y-m-d", $timestamp)); //create dateobject to add a month
$date->modify("+{$x} month"); // add the month (next month)
$extraDays += date("t", strtotime($date->format("Y-m-d")));
// get the days of the selected month and add them to count
// in this case its 31 + 30 + 31 = 92
}
$days = $endOfCurrentMonth + $extraDays;
// count everything together 16 + 92 = 108 days
return date("d.m.y", $timestamp + ($tsDay*$days));
//returning date with 108 days added.
}
As a sample I call the function like:
// the timestamp is 2015-07-15
echo getLastDeliveryDate(1436911200, true, 3);
// should return 2015-10-31
But this return 2015-10-30 and I don't know why. But 108 Days shold be 2015-10-31. Whats going wrong here ?
If I call
echo getLastDeliveryDate(1436911200, true, 2);
Its correct and gives me 2015-09-30
Actually I allways want the last day of the month.
EDIT:
Wired, if I test this here: IDEONE everything works fine. Im my Project it doesn't :(
You need to create the datetime object before the loop:
$date = new DateTime(date("Y-m-d", $timestamp)); //create dateobject to add month
// simpler alternative: $date = new DateTime("#$timestamp");
for($i=0;$i<$extraMonth;$i++){
$date->modify("+1 month"); // add the month (next month)
// $extraDays += date("t", strtotime($date->format("Y-m-d")));
// you can reduce this line to:
$extraDays += $date->format("t");
}
// Result: 15-10-31
otherwise there is always 31 added because you use the day of the timestamp + 1 month.
Note:
You can reduce the whole function to this:
function getLastDeliveryDate($timestamp,$endOfMonth=true,$extraMonth=0){
$date = new DateTime("#$timestamp");
$date->modify("+$extraMonth month");
if ($endOfMonth)
$date->modify("last day of this month");
return $date->format("d.m.y");
}
The problem is the daylight savings time. You loose one hour on the 25th of october 2015. Since your timestamp is exactly 0:00:00 you lose one hour resulting in "30.10.2015 23:00:00" what should actually be 0:00:00
function getLastDeliveryDate($timestamp,$endOfMonth=true,$extraMonth=0){
$days = 0;
$extraDays = 0;
$endOfCurrentMonth = 0;
$tag = 86400;
if(date( 'H',$timestamp)==0){$timestamp+=3601;}
if($endOfMonth){
$endOfCurrentMonth = date("t", $timestamp) - date("d",$timestamp);
}
$date = new DateTime(date("Y-m-d", $timestamp));
for($i=0;$i<$extraMonth;$i++){
$date->modify("+1 month");
$extraDays += $date->format("t");
}
$days = $endOfCurrentMonth + $extraDays;
return date("d.m.y", $timestamp + ($tag*$days));
}
echo getLastDeliveryDate(1436911200, true, 3);
This code has a dirty fix for this problem by adding one hour and one second if your datetime is fixed to 0:00:00. When you don't care about the hours themselves, then this solution will fix your problem and is viable in any case. If you care about the hours, you have to check whether you are in daylight savings time or not and act acordingly.
How do I go about getting all the work days (mon-fri) in a given time period (let's say, today till the end of the next month) ?
If you're using PHP 5.2+ you can use the library I wrote in order to handle date recursion in PHP called When.
With the library, the code would be something like:
$r = new When();
$r->recur(<start date here>, 'weekly')
->until(<end date here>)
->wkst('SU')
->byday(array('MO', 'TU', 'WE', 'TH', 'FR'));
while($result = $r->next())
{
echo $result->format('c') . '<br />';
}
This sample does exactly what you need, in an quick and efficient way.
It doesn't do nested loops and uses the totally awesome DateTime object.
$oDateTime = new DateTime();
$oDayIncrease = new DateInterval("P1D");
$aWeekDays = array();
$sStart = $oDateTime->format("m-Y");
while($oDateTime->format("m-Y") == $sStart) {
$iDayInWeek = $oDateTime->format("w");
if ($iDayInWeek > 0 && $iDayInWeek < 6) {
$aWeekDays[] = clone $oDateTime;
}
$oDateTime->add($oDayIncrease);
}
Try it here: http://codepad.org/wuAyAqnF
To use it, simply pass a timestamp to get_weekdays. You'll get back an array of all the weekdays, as timestamps, for the rest of the current month. Optionally, you can pass a $to argument - you will get all weekdays between $from and $to.
function get_weekdays ($from, $to=false) {
if ($to == false)
$to = last_day_of_month($from);
$days = array();
for ($x = $from; $x < $to; $x+=86400 ) {
if (date('w', $x) > 0 && date('w', $x) < 6)
$days[] = $x;
}
return $days;
}
function last_day_of_month($ts=false) {
$m = date('m', $ts);
$y = date('y', $ts);
return mktime(23, 59, 59, ($m+1), 0, $y);
}
I suppose you could loop through the dates and check the day for each one, and increment a counter.
Can't think of anything else off the top of my head.
Pseudocode coming your way:
Calculate the number of days between now and the last day of the month
Get the current day of the week (i.e. Wednesday)
Based on the current day of the week, and the number of days left in the month, it's simple calculation to figure out how many weekend days are left in the month - it's going to be the number of days remaining in the month, minus the number of Sundays/Saturdays left in the month.
I would write a function, something like:
daysLeftInMonth(daysLeftInMonth, startingDayOfWeek, dayOfWeekToCalculate)
where:
daysLeftInMonth is last day of the month (30), minus the current date (15)
startingDayOfWeek is the day of the week you want to start on (for today it would be Wednesday)
dayOfWeekToCalculate is the day of the week you want to count, e.g. Saturday or Sunday. June 2011 currently has 2 Sunday, and 2 Saturdays left 'til the end of the month
So, your algorithm becomes something like:
getWeekdaysLeft(todaysDate)
...getWeekdaysLeft is something like:
sundaysLeft = daysLeftInMonth(lastDayOfMonth - todaysDate, "Wednesday", "Sunday");
saturdaysLeft = daysLeftInMonth(lastDayOfMonth - todaysDate, "Wednesday", "Saturday");
return ((lastDayOfMonth - todaysDate) - (sundaysLeft + saturdaysLeft));
This code does at least one part you ask for. Instead of "end of next month" it simply works with a given number of days.
$dfrom = time();
$fourweeks = 7 * 4;
for ($i = 0; $i < $fourweeks; $i ++) {
$stamp = $dfrom + ($i * 24 * 60 * 60);
$weekday = date("D", $stamp);
if (in_array($weekday, array("Mon", "Tue", "Wed", "Thu", "Fri"))) {
print date(DATE_RSS, $stamp) . "\n";
}
}
// Find today's day of the month (i.e. 15)
$today = intval(date('d'));
// Define the array that will hold the work days.
$work_days = array()
// Find this month's last day. (i.e. 30)
$last = intval(date('d', strtotime('last day of this month')));
// Loop through all of the days between today and the last day of the month (i.e. 15 through 30)
for ( $i = $today; $i <= $last; $i++ )
{
// Create a timestamp.
$timestamp = mktime(null, null, null, null, $i);
// If the day of the week is greater than Sunday (0) but less than Saturday (6), add the timestamp to an array.
if ( intval(date('w', $timestamp)) > 0 && intval(date('w', $timestamp)) < 6 )
$work_days[] = mktime($timestamp);
}
The $work_days array will contain timestamps which you could use this way:
echo date('Y-m-d', $work_days[0]);
The code above with work in PHP 4 as well as PHP 5. It does not rely on the functionality of the DateTime class which was not available until PHP 5.2 and does not require the use of "libraries" created by other people.
i am develop a webpage in that i need to calculate x days from a specified date , The problem is we exclude the saturday and sunday . For example $Shipdate = '06/30/2009' and the x is 5 means , i want the answer '7' [ie 30 is tuesday so after 5 days it will be sunday , so there is two holiday(saturday and sunday) so we add 5+2(for saturday and sunday)]=7. Please help me to find out , Thanks in advance.
Generally you will need to be able to specify a calendar with significant days excluded. Consider Christmas Day or public holidays. This appears to be code that will consider public holidays, you need to modify it or parameterise it with your set of holidays.
<?php
// ** Set Beginning and Ending Dates, in YYYY-mm-dd format **
$begin = '2008-01-01';
$end = '2008-03-31';
$begin_mk = strtotime("$begin");
$end_mk = strtotime("$end");
// ** Calculate number of Calendar Days between the two dates
$datediff = ( $end_mk > $begin_mk ? ( $end_mk - $begin_mk ) : ( $begin_mk - $end_mk ) );
$days = ( ( $datediff / 3600 ) / 24 );
$days = $days + 1; // to be inclusive of last date;
// ** Count days excluding Sundays **
$iteration = 0;
$numDaysExSunday = 0;
for ($i=1; $i<=$days; $i++) {
$weekday = date("w", strtotime("$begin + $iteration day"));
echo "$weekday<br>";
**// i change only this line to add saturday**
if ($weekday !== '0' && $weekday !== '6') {
$numDaysExSunday++;
}
$iteration++;
}
// ** Output number of days excluding Sundays **
echo $numDaysExSunday;
?>
i take it from
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_23499410.html
the solution Excluding Sundays but need to change only one line to exclude saturday i write it in the code
function Weekdays($start,$end){
$days=0;
if ( $end <= $start ) {
// This is invalid data.
// You may consider zero to be valid, up to you.
return; // Or throw an error, whatever.
}
while($start<$end){
$dayofweek = date('w',$start);
if( 6!= $dayofweek && 0 != $dayofweek){
$days++;
}
$start = strtotime('+1 day',$start);
}
return $days;
}
You may want to tweak it a bit depending on whether you want to count it as one day or zero if the start is the same day as the end.