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
}
}
Related
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');
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 have comma separated days(1,3,5,6) and i want to count number of days between two days.
I have done this as below.
$days=$model->days; // comma saperated days
$days=explode(',',$days); // converting days into array
$count=0;
$start_date = $model->activity_start_date; // i.e. 2018-03-27
$end_date = date('Y-m-d');
while(strtotime($start_date) <= strtotime($end_date)){
if(in_array(date("N",strtotime($start_date)),$days)){ // check for day no
$count++;
}
$start_date = date ("Y-m-d", strtotime("+1 day", strtotime($start_date)));
}
This code is working fine. But the problem is if difference between two date will be year or more than a year than it loop 365 times or more.
Is there any way to reduce execution time to count days. Or it is possible to get counts of days using mysql query.
Real Scenario : I have one event which have start date and it occurs multiple in week(i.e. Monday and Wednesday ) and i want to find how many times event occur from start date to now. If start date is 2018-04-9 and today is 2018-05-9 than count will be 9
This requires no looping.
I find how many weeks between start and end and multiply full weeks (in your example 16,17,18) with count of days.
Then I find how many days there is in first week (15) that is higher than or equal to daynumber of startday.
Then the opposit for week 19.
$days="1,3"; // comma saperated days
$days=explode(',',$days); // converting days into array
$count=0;
$start_date = "2018-04-09";
$end_date = "2018-05-09";
// calculate number of weeks between start and end date
$yearW = floor(((strtotime($end_date) - strtotime($start_date)) / 86400)/7);
if($yearW >0) $count = ($yearW -1)*count($days); //full weeks multiplied with count of event days
$startday = date("N", strtotime($start_date));
$endday = date("N", strtotime($end_date));
//find numer of event days in first week (less than or equal to $startday)
$count += count(array_filter($days,function ($value) use($startday) {return ($value >= $startday);}));
//find numer of event days in last week (less than $endday)
$count += count(array_filter($days,function ($value) use($endday) {return ($value < $endday);}));
echo $count; // 9
https://3v4l.org/9kupt
Added $yearW to hold year weeks
Here, I have a code I have used previously in a project. It is used to find the distance between date from today.
public function diffFromToday($date){
$today = date('jS F, Y');
$today = str_replace(',','',$today);
$today=date_create($today);
$today = date_format($today,"Y-m-j");
$date = str_replace(',','',$date);
$date=date_create($date);
$date = date_format($date,"Y-m-j");
$today=date_create($today);
$date=date_create($date);
$diff=date_diff($today,$date);
$result = $diff->format("%R%a");
$result = str_replace('+','',$result);
return $result;
}
You can use this function according to your requirement. Date format used in this function is 'jS F, Y' DO not be confused and use your own format to convert.
$start_date = date_create('2018-03-27');
$end_date = date_create('2018-04-27');
$t = ceil(abs($endDate- $start_date) / 86400);
echo date_diff($start_date, $end_date)->format('%a');
Output with like this
396
Could you not use the date->diff function to get the values you can directly use like -5 or 5?
$diffInDays = (int)$dDiff->format("%r%a");
Here is something for format parameter descriptions if it could be helpful to you.
You may use tplaner/when library for this:
$days = str_replace(
['1', '2', '3', '4', '5', '6', '0', '7'],
['mo', 'tu', 'sa', 'th', 'fr', 'sa', 'su', 'su'],
'1,3'
);
$when = new When();
$when->rangeLimit = 1000;
$occurrences = $when->startDate(new DateTime('2018-04-9'))
->freq('daily')
->byday('mo,we')
->getOccurrencesBetween(new DateTime('2018-04-9'), new DateTime('2018-05-9'));
echo count($occurrences);
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 need to find a way to get the date of the monday of a week based on another day. So for example, if wednesday is 2011-05-11, i need to somehow tell it that monday of that week was 2011-05-09. Can anyone help?
$res looks like this:
stdClass Object
(
[link_count] => 1
[day] => 2011-05-12
[weekday] => Thu
)
$days = array(1=> 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');
foreach($res as $r) {
$day = date('N', strtotime($r->day));
$r->weekday = $days[$day];
if($r->weekday == 'Mon') {
$r->weekstarting = $r->day;
} else {
// here's the problem right here, I need to find a way to tell it
// what it's starting day is
$r->weekstarting = ;
}
}
Seems like you have the weekday (like 'Thu'), so you need to get is position in your $days array.
You can get the key with $key=array_search($r->weekday, $days); (returns 4).
Now you know the difference from Monday, so you just have to create the date:
$tempArray=explode('-', $r->day);
$tempArray[2]-=$key-1;
$r->weekstarting = implode('-', $tempArray);
EDIT: Now I see that you already had the array index in $day. So you could use that value instead of the $key I had.
EDIT 2: If you don't want to lose the leading zeros in the day, you could use sprintf() on it .
$tempArray=explode('-', $r->day);
$tempArray[2]=sprintf('%02d', $tempArray[2]-($key-1));
$r->weekstarting = implode('-', $tempArray);
And finally the LAST UPDATE. I was thinking about deleting the whole post and rewriting it again, but I will leave it here for reference... somebody might learn from my mistake.
So the final code that will correctly adjust months also:
list($y, $m, $d)=explode('-', $r->day);
$timestamp=mktime(0,0,0,$m,$d-($day-1),$y);
$r->weekstarting = date('Y-m-d', $timestamp);
Actually this is what I wanted to avoid, converting to a timestamp, but I could not. The trick I'm using here is that mktime() will handle negative numbers for days and calculate the timestamp correctly.
This seems to work fine:
<?php
$dt = new DateTime("11 May 2011");
$dt->modify("last monday");
edit: I remember seeing reports that some people had problems with the "last" modifier (windows users maybe) so this should work if you have problems with that:
<?php
$dt = new DateTime("12 May 2011");
$days = (int)$dt->format('N') - 1;
$dt->modify("-{$days} days");
Please create a testfile and execute it:
<?php
$dates = array(
'11 May 2011',
'2011-04-26',
'2011-05-04',
);
foreach($dates as $date) {
$dt = new DateTime($date);
$dt->modify("last monday");
printf("For %s last monday is %s.\n", $date, $dt->format('Y-m-d'));
}
?>
it should output the following:
For 11 May 2011 last monday is 2011-05-09.
For 2011-04-26 last monday is 2011-04-25.
For 2011-05-04 last monday is 2011-05-02.
In case not, please add your output to your question above.
I'd do something like this:
$dow = date('N', strtotime($r->day)) - 1; // 0 will be Monday, 1 Tuesday, etc.
$start = mktime() - ($dow * 86400); // 86400 is one day in seconds
$startday = date('r', $start);