What I have:
I have table with a unique date column.
id
date
1
2021-09-01
2
2021-08-01
3
2021-07-01
4
2020-04-01
5
2020-03-01
6
2020-12-01
I pull data based on a month and year from a GET parameter.
DB::table('budgets')->whereMonth('created_at', $request->get('month'))->whereYear('created_at', $request->get('year'))->get()->first();
I do a check to see if a previous month is available in table
$pm = DB::table('budgets')->whereMonth('created_at', $prev_month)->whereYear('created_at', $prev_year)->count();
if ($pm > 0) {
$prev_month = date('m', strtotime($_GET['month']. ' - 1 month'));
$prev_year = date('m', strtotime($_GET['month']. ' - 1 month'));
Previous Month
}
This works great... if there is a previous month i.e. 1 month behind.
My question is:
How can I check what the nearest/next date is?
Example:
If I was already on '2021-07-01', how would I know the next 'previous' date is '2020-12-01' and visa versa?
The solution as per #CBroe advice:
<?php
$this_date = date('Y-m-d', strtotime($_GET['month'].'-'.$_GET['year'].'-01'));
$pm = DB::table('budgets')->where('created_at', '<', $this_date)->orderby('created_at', 'desc')->get()->first(); // Find dates less than the one searching for and order it descending order and get only the first row.
if ($pm) {
$prev_month = date('m', strtotime($pm->created_at));
$prev_year = date('Y', strtotime($pm->created_at)); ?>
Previous Month
<?php } ?>
You can check the nearest/next date this way
$next_date = DB::table('budgets')
->where('created_at', '<', $date)
->orderByDesc('created_at')
->first()
->value('created_at');
Related
I have a user in a database with a creation_date. This user can run a job in my app UI, but he is limited by a number of job to run in one year.
This user has been created in 2014. I would like to do something like :
function runJob($user){
$nbRemainingJob = findReminingJobs($user);
if ($nbRemainingJob > 0){
runJob($user);
}
else {
die("no more credits";)
}
}
findReminingJobs($user){
$dateRangeStart = ?; //start date to use
$endRangeStart = ?; //end date to use
$sql = "SELECT count(*) FROM jobs WHERE user_id=?";
$sql .= "AND job_created_at BETWEEN ($dateRangeStart AND $endRangeStart)";
$res = $pdo->execute($sql, [$user->id]);
$done = $res->fetchOne();
return ($user->max_jobs - $done);
}
Every user's creation birthday, the $user->max_jobs is reset.
The question is how to find starting/ending date ? in other words, I would like to get a range of date starting from the user's creation date.
For example, if the user was created on 2014-04-12, my start_date should be 2018-04-12 and my end_date = 2019-04-11.
Any idea ?
First get the user register date from db and split it into Year, Month and Day like
$register= explode('-', $userCridate);
$month = $register[0];
$day = $register[1];
$year = $register[2];
Then get the current year like
$year = date("Y");
$dateRangeStart = $year."-".$month."-".$day; //start date to use
Now, check if this date is greater then today date, then use last year as starting date
$previousyear = $year -1;
$dateRangeStart = $previousyear ."-".$month."-".$day; //start date to use
$endRangeStart = date("Y-m-d", strtotime(date("Y-m-d", strtotime($dateRangeStart))
. " + 365 day"));
It is a idea, check if it work for you.
function getRange($registrationDate) {
$range = array();
// Split registration date components
list($registrationYear, $registrationMonth, $registrationDay) = explode('-', $registrationDate);
// Define range start year
$currentYear = date('Y');
$startYear = $registrationYear < $currentYear ? $currentYear : $registrationYear;
// Define range boudaries
$range['start'] = "$startYear-$registrationMonth-$registrationDay";
$range['end'] = date("Y-m-d", strtotime($range['start'] . ' + 364 day'));
return $range;
}
And for your example:
print_r(getRange('2014-04-12'));
Array
(
[start] => 2018-04-12
[end] => 2019-04-11
)
print_r(getRange('2014-09-13'));
Array
(
[start] => 2018-09-13
[end] => 2019-09-12
)
$created='2025-04-12';
$date=explode('-',$created);
if($date[0]<date("Y")){
$newDate=date('Y').'-'.$date[1].'-'.$date[2];
$dateEnding = strtotime($newDate);
$dateEnding = date('Y-m-d',strtotime("+1 year",$dateEnding));
}
else{
$newDate=$created;
$dateEnding = strtotime($newDate);
$dateEnding = date('Y-m-d',strtotime("+1 year",$dateEnding));
}
echo 'starting date is: '.$newDate;
echo '</br>';
echo 'ending date is: '.$dateEnding;
This code will get the date you have and match it with the current year. If the year of the date you provided is equal or above the current year the start date will be your date and end date will be current date +1 year. Otherwise if the year is below our current year (2014) it will replace it with the current year and add 1 year for the end date. Some example outputs:
For input
$created='2014-04-12';
The output is :
starting date is: 2018-04-12
ending date is: 2019-04-12
But for input
$created='2025-04-12';
The outpus is :
starting date is: 2025-04-12
ending date is: 2026-04-12
The solution that match my need :
$now = new DateTime();
$created_user = date_create($created);
$diff = $now->diff($created_user)->format('%R%a');
$diff = abs(intval($diff));
$year = intval($diff / 365);
if ($year == 0){
$startDate=$created_user->format("Y-m-d");
}else{
$startDate=$created_user->add(new DateInterval("P".$year."Y"))->format("Y-m-d");
}
The problem was to define the starting date that is comprised in the one year range max from the current date and starting from the user's creation date.
So if the user's creation_date is older than one year, than I do +1 year, if not, take this date. the starting date must not be greater than the current date_time
thanks to all for your help
I've just discovered a problem with the usually used method to sum months to a PHP Date. If you search on google or this forum, you usually find somethings like these:
$date = strtotime(date("Y-m-d", strtotime($date)) . " +1 month");
or
$months = DateInterval::createFromDateString('1 month');
$dateInDateTime->add($months);
Both approach are not correct, in my opinion.
For example in my code I have to increment 3 times the month of a starting date beginning with last day of April and return the last day of that months.
So my code generates this results:
2017-04-30
2017-05-31
2017-07-31
The second time the script add +1 month to date, goes from 2017-05-31 to 2017-07-01 because 31-05 + 30 days is over the last day of JUNE.
What Im expecting is 06-30 because you are summing MONTHS not DAYS and if you have an overflow, the code has to correct it, not me.
This is a common error that explode when you manage February or December (due to change of year).
Im expecting a script that increment month. So if I have 2017-03-23 and sum +1 month, I get 2017-04-23 and if I sum +1 month to 2017-03-31 I got 2017-04-30.
So. Pay attention when using this functions.
I think you are trying something dangerous.
What s going on for february? if you want all the time to change only month number it will break for latest days of this month, same for months with 30 days instead of 31...
You have to think about your approach in another way, because changing the month alone won't make an existing date sometimes.
+30 days seems to be the best thing to do
What Im expecting is 06-30 because you are summing MONTHS not DAYS and if you have an overflow, the code has to correct it, not me.
PHP corrects it, indeed. It never returns 31st of June as such a date doesn't exist. It corrects it to 1st of July.
What you apparently expect is that when you add 1 month to the last day of a month to get the last day of the next month. But this doesn't make any sense.
What should strtotime('2017-06-30 +1 month') return?
2017-07-31, because you are adding 1 month to the last day of June or 2017-07-30 because you are adding 1 month to the 30th day of June?
The times runs forward, counting the days from the end of the month is not natural. Sometimes it's useful but not that many times. And there always is a better solution: subtract 1 day from the first day of the next month. This way you don't have to do any correction or care about months with different number of days or even about leap years.
This is the function I wrote:
//it accept negative month value
public static function realAddMonthsToDate($month,$dateToModify,
$dateFormatInput = DEFAULT_SQL_DATE_FORMAT, $dateFormatOutput = DEFAULT_SQL_DATE_FORMAT)
{
$currentDate = DateTime::createFromFormat($dateFormatInput, $dateToModify);
$cDay = $currentDate->format('d');
$cMonth = $currentDate->format('m');
$cYear = $currentDate->format('Y');
$monthRest = $month;
$yearOffset = 0;
if ($month > 12)
{
$yearOffset = floor($month / 12);
$monthRest = $month - ($yearOffset * 12);
}
$cMonth += $monthRest;
if ($cMonth > 12) {
$cMonth = $cMonth - 12;
$cYear += 1;
}
if ($cMonth <= 0)
{
$cMonth = 12 + $cMonth;
$cYear -= 1;
}
$cYear += $yearOffset;
$arrivalMonthDays = cal_days_in_month(CAL_GREGORIAN, $cMonth, $cYear);
if ($cDay >= $arrivalMonthDays) $cDay = $arrivalMonthDays;
$newDate = new DateTime($cYear.'-'.$cMonth.'-'.$cDay);
return $newDate->format($dateFormatOutput);
}
i am trying to get dates of current month or any other month from a date range.
Let Suppose I have a Date Range as Below.
$startDate = "2014-12-10";
$endDate = "2015-2-3";
I want to count only days/dates of current month "February"
which would result in 3 if start date and end date is above one.
but how can i make it work in a programming manner??
-=-=-=-=-==-=
update:
I think i could not explain my question,
Lets Take the same date range..
if i want to programmatically take out days of December Month
it would be like
21 days, as start date is 2014-12-10;
Dates Are in Range Coming Programmatically from database..
-=-==-=-=-=-=-=
UPDATE 2:
An other simple example
Lets Suppose If Leaves Have Been Approved For an Employee from 28-1-2015 to 6-2-2015
so Here Employees Leaves Taken Start Date Would Be
$sartDate = '28-1-2015';
$endDate = '6-2-2015';
So Total Leaves Employee would be taking is
$totalleaves = $endDate - $startDate //It is not right way to take out the differece only For sake of Example shown it
which would give me total leaves 9 or 10 days
But If We See, These Leaves Are Divided in Two Different Months.
And i want to generate a Report and i want to see how many leaves employee has taken for specific month which is lets suppose last month January
it would be 4 days i suppose for below dates as below dates comes in date range and they belong to January.
28-1-2015
29-1-2015
30-1-2015
31-1-2015
so if i would like to have a result of array of every month leaves it would
be like
array(
'January' => array(
'TotalLeavesTaken' => 4
),
'February' => array(
'TotalLeavesTaken' => 6
)
);
I think thats the best i could explain..
Adjusted after update in question
Ok, now I have adjusted after your last update. Hope it is what you're looking for:
function getLeavesInPeriod($start, $end) {
$date = new DateTime($start);
$endDate = new DateTime($end);
$leaves = array();
while($date <= $endDate ) {
$year = $date->format('Y');
$month = $date->format('M');
if(!array_key_exists($year, $leaves))
$leaves[$year] = array();
if(!array_key_exists($month, $leaves[$year]))
$leaves[$year][$month] = 0;
$leaves[$year][$month]++;
$date->modify("+1 day");
}
return $leaves;
}
$leaves = getLeavesInPeriod("2015-1-5", "2015-2-3");
print $leaves[2015]["Jan"]; //27
Not sure if understood your question correctly,
date('d', strtotime($endDate));
Lets try this
$month = strtotime(date('Y-m-01', time()));
$daysCount = (int)(time() - $month) / (24 * 3600);
It will help you: i m using this to get days
$date_diff = $end_date - $start_date;
//difference of two dates
This will return you number of days.Is just you want this or something else.Please confirm if it will help you.
$days_left = floor($date_diff / (60*60*24));// No. of days
I am trying to get stripe to set a end_trial date on the next occurrence of whatever day of the month the user chooses. i.e. If today is the 16th and the user chooses the 15th I need the unix timestamp for the 15th of the next month. However if today was the 14th I need the timestamp for tomorrow.
I tried the solution found on this SO question Find the date for next 15th using php .
When i ran the code suggested in that question and substituted 15 for 31
$nextnth = mktime(0, 0, 0, date('n') + (date('j') >= 31), 31);
echo date('Y-m-d', $nextnth);
The result is 2013-03-03
I also tried this one Get the date of the next occurrence of the 18th .
The second one would actually give me 2013-03-31 when i ran it one 2013-1-31.
Both had unexpected results. Is february the problem? Any guidance will be much appreciated.
Here is a way to do it.
function nextDate($userDay){
$today = date('d'); // today
$target = date('Y-m-'.$userDay); // target day
if($today <= $userDay){
$return = strtotime($target);
}
else{
$thisMonth = date('m') + 1;
$thisYear = date('Y');
if($userDay >= 28 && $thisMonth == 2){
$userDay = 28;
}
while(!checkdate($thisMonth,$userDay,$thisYear)){
$thisMonth++;
if($thisMonth == 13){
$thisMonth = 1;
$thisYear++;
}
}
$return = strtotime($thisYear.'-'.$thisMonth.'-'.$userDay);
}
return $return;
}
// usage
echo date('Y-m-d',nextDate(29));
We get the user's choice and compare it today.
If today is less than or equal to user choice, we return the timestamp for this month.
If today is greater than user choice, we loop through dates, adding a month (or a year if it's $thisMonth hits 13). Once this date does exist again, we have our answer.
We check the dates using php's checkdate function, strtotime and date.
I really don't understand the question completely. You can easily determine the date for next 30 days for example
$next_ts = time() + 30 * 86400; // add 30 days to current timestamp
$next = date('Y-m-d', $next_ts); // format string as Y-m-d
echo $next;
If that is not what you need, please explain the problem.
Ok, I've got a logistical question here more so than coding one, but a code example/solution might answer both, so here goes...
If I have a form that I pass in PHP with start_date and end_date (full on m/d/Y format) and I need to print out a table of all entries in mysql database that fall in that range (so from m1/d1/Y1 to m2/d2/Y2) grouped by month, how would I even go about doing that in an elegant way?
For example, if I pass start_date = 5/20/2012, end_date = 7/31/2012, I need the resulting table to show results in this format:
May 2012 | June 2012 | July 2012
.... | .... | .....
where the first column for May 2012 would show results from an mysql query like
SELECT ... WHERE signup_date >= 5/20/2012 AND signup_date <= 5/31/2012
and June 2012 would similarly show:
SELECT ... WHERE signup_date >= 6/1/2012 AND signup_date <= 6/30/2012
etc
So I am looking for a way to parse the start and end date into an array of dates properly arranged from the starting day of the month until the last day of the month, and if the end_date is a few months later then cover all the other months in-between in full (from 1st til last of that month), so that I can cycle through them in a for/while loop? So something like:
[0]['start'] => '5/20/2012'
[0]['end'] => '5/31/2012'
[1]['start'] => '6/1/2012'
[1]['end'] => '6/30/2012'
[2]['start'] => '7/1/2012'
[2]['end'] => '7/31/2012'
Any ideas?
You should be do achieve this with mktime() . Sample code below.
<?php
$startDate = '05/20/2012';
$endDate = '07/31/2012';
$curMonth = date("m", strtotime($endDate)); //End Month
$curYear = date("Y", strtotime($endDate)); //End Year
$months = array();
$months[] = array('start' => "$curMonth/01/$curYear", 'end' => $endDate);
while ("$curMonth/01/$curYear" > $startDate) {
$monthEnd = date("m/d/Y", mktime(0, 0, 0, $curMonth, 0, $curYear));
$curMonth = date('m', strtotime($monthEnd));
$curYear = date('Y', strtotime($monthEnd));
$monthStart = ($curMonth/01/$curYear > $startDate) ? $startDate : "$curMonth/01/$curYear";
$months[] = array('start' => $monthStart, 'end' => $monthEnd);
}
print_r(($months));
?>
try this:
$date = '5/20/2012';
$dateStart = date("m/01/y", strtotime($date));
$start = date("Y-m-d", strtotime($dateStart));
$end = date("Y-m-d", strtotime($dateStart. '+ 1 month - 1 day') );
echo $start;
echo $end;
See my comments first for mysql db date format.
written a bit in pseudo language
$sql="SELECT * FROM ... WHERE `signup_date`>='2012-5-20' AND `signup_date`<'2012-5-31' ORDER BY `signup_date`";
$result=mysql_query($sql);
$month_year=array() //3-dimensional array $month_year[year][month][primary_key];
$month_index=-1;
while($row=mysql_fetch_assoc($result)){
// find $month_of_the_date AND $year_of_the_date
//find different months ,corresponding years, and db primary key and keep track in the $month_year array
}
for( all the years in the array ){
for(all the corresponding months of the year in the array){
//**EDIT:** you MIGHT need other loops and arrays to collect distinct years and corresponding months together
// show the records with the primary keys corresponding to that month and year
}
}