calculate the dates that are between two days of the week - php

I need an algorithm that calculates dates that are between two days of the week!
for example i have
start date: 23-04-2012 and end date: 27-04-2012
now i want receive an array with this structure:
$arr = array(
'23-04-2012',
'24-04-2012',
'25-04-2012',
'26-04-2012',
'27-04-2012',
'28-04-2012'
);
thanks!

You could use the DateTime::Diff function (documentation here).
Pass your two dates into the function.
Get the return value as the number of days.
Add one to it (so as to include both the start and end dates).
Put together a for(int i = 0; i <= $days_difference; i++) loop.
Increment the date by one day each time and add it to the array.

$start = '23-04-2012';
$end = '27-04-2012';
$startTs = strtotime("$start 00:00:00");
$endTs = strtotime("$end 00:00:00");
$days = array();
$day = $startTs;
$i = 0;
while ($day <= $endTs) {
$days[] = date('d-m-Y', $day);
$i++;
$day = mktime(0, 0, 0, date('n', $startTs), date('j', $startTs) + $i, date('Y', $startTs));
}
var_dump($days);

This could help you.
$startdate=explode("-","23-04-2012");
$enddate=explode("-","27-04-2012");
$i;
$arr=array();
for($i=$startdate[0];$i<=$endate[0];$i++)
{
$dd=$i.'-'.$startdate[1].'-'.$startdate[2];
array_push($arr,$dd);
}
print_r($arr);

Related

Adding new items into PHP array and saving previous size of the array

I have the following code so far:
$months = array();
$numJoin = date("n",strtotime($me['joinTime']));
$numLast = date('n', strtotime('Dec 31'));
$numCurrent = date("n",strtotime('2016-06-01'));
array_push($months, date("F", strtotime($me['joinTime'])));
for($i = ($numJoin + 1); $i <= $numLast; $i++) {
if($numCurrent>$numJoin) {
$dateObj = date_create_from_format('!m', $i);
array_push($months, $dateObj->format('F'));
}
$numCurrent= -1;
}
What I'm trying to do here is to add into the array current month that kicks in, and save previous months in the array like for example:
Start month is -> May
June kicks in -> I add June into the array (now I should have May and June in array).
July kicks in -> I add July into the array (now I should have May, June and July in array).
How can I do this achieve this? Current solution works only for +1 month.. I can't add more than 1 month :/
P.S. New item should only be added when the new month kicks in, and previous content of the array should be saved...
Here we go, you need to check that your month is less than the current month or not. Check Online
$months = array();
$num = date("n",strtotime($me['joinTime'])); //join month number
$now = date("n"); //Current month number
for($i = $num; $i <= $now; $i++){
$dateObj = DateTime::createFromFormat('!m', $i);
array_push($months, $dateObj->format('F'));
}
print_r($months);
I'm still a little confused, but I think this is what you are after... all month names after the join month and until current month...
$me = array('joinTime'=>'2016-03-01');
$dtCurrent = strtotime($me['joinTime']);
$arrMonths = array();
while($dtCurrent < time()) {
$dtCurrent = strtotime("+1 month",$dtCurrent);
$arrMonths[] = date('F',$dtCurrent);
}
var_dump($arrMonths);

Count weekend days between range dates from array in php

I'm trying to calculate the number of weekend days between dates from the array below:
$dates[] = array ( 'DateFrom' => '2015-07-10', 'DateTo' => '2015-07-10', 'DateFrom' => '2015-07-12', 'DateTo' => '2015-07-12', 'DateFrom'=> '2015-07-17', 'DateTo'=> '2015-07-19') ;
The result must return number of weekend days between these dates
Between these dates are 3 days of weekend (2015-07-12, 2015-07-18, and 2015-07-19).
Anyone have any idea?
You need to loop through from start date to end date and in each iteration need to check for day (sat/sun)
Algo :
$weekends = 0;
$startDate = strtotime($startDate);
$endDate = strtotime($endDate);
while($startDate<$endDate) {
//"N" gives ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0)
$day = date("N",$startDate);
if($day == 6 || $day == 7) {
$weekends++;
}
$startDate = 24*60*60 ; //1 day
}
Firstly, if you're defining your array exactly as written, you're duplicating keys and four of those items will be overwritten. But assuming we're just looking at the pairs. Pass the FromDate and ToDate from each pair to this function and add up all the return values.
function getWeekends ($fromDate, $toDate) {
$from = strtotime($fromDate);
$to = strtotime($toDate);
$diff = floor(abs($to-$from)/(60*60*24)); // total days betwixt
$num = floor($diff/7) * 2; // number of weeks * 2
$fromNum = date("N", $from);
$toNum = date("N", $to);
if ($toNum < $fromNum)
$toNum += 7;
// get range of day numbers
$dayarr = range($fromNum, $toNum);
// check if there are any weekdays in that range
$num += count(array_intersect($dayarr, array(6, 7, 13)));
return $num;
}
There may be a more elegant solution.
To be used on each pair of dates:
function getWeekendDays($startDate, $endDate)
{
$weekendDays = array(6, 7);
$period = new DatePeriod(
new DateTime($startDate),
new DateInterval('P1D'),
new DateTime($endDate)
);
$weekendDaysCount = 0;
foreach ($period as $day) {
if (in_array($day->format('N'), $weekendDays)) {
$weekendDaysCount++;
}
}
return $weekendDaysCount;
}

How many of a certain week day has passed this month

I have a calendar that I want to allow events to be repeated on a week day of the month. Some examples would be:
Repeat every 4th Tuesday of the month
Repeat every 2nd Friday of the month
And so on...
What I need is the ability to find out how many week days (for example Tuesday's) have passed this month so far.
I found some code that returns how many Monday's have passed.
$now=time() + 86400;
if (($dow = date('w', $now)) == 0) $dow = 7;
$begin = $now - (86400 * ($dow-1));
echo "Mondays: ".ceil(date('d', $begin) / 7)."<br/>";
This works well but how do I make it so that I can determine any week day? I cannot seem to get my head around the code to make this work.
strtotime is really useful for this kind of thing. Here are lists of the supported syntax. Using your example of repeat every 2nd Friday of the month I wrote the following simple snippet for you:
<?php
$noOfMonthsFromNow=12;
$dayCondition="Second Friday of";
$months = array();
$years = array();
$currentMonth = (int)date('m');
for($i = $currentMonth; $i < $currentMonth+$noOfMonthsFromNow; $i++) {
$months[] = date('F', mktime(0, 0, 0, $i, 1));
$years[] = date('Y', mktime(0, 0, 0, $i, 1));
}
for ($i=0;$i<count($months);$i++){
$d = date_create($dayCondition.' '.$months[$i].' '.$years[$i]);
if($d instanceof DateTime) echo $d->format('l F d Y H:i:s').'<br>';
}
?>
This can be tested at: http://www.phpfiddle.org/lite/
$beginningOfMonth = strtotime(date('Y-m-01')); // this will give you the timestamp of the beginning of the month
$numTuesdaysPassed = 0;
for ($i = 0; $i <= date('d'); $i ++) { // 'd' == current day of month might need to change to = from <= depending on your needs
if (date('w', $beginningOfMonth + 3600 * $i) == 2) $numTuesdaysPassed ++; // 3600 being seconds in a day, 2 being tuesday from the 'w' (sunday == 0)
}
Not sure if this will work, and there's probably a better way to do it; don't have the means to test it right now but hopefully this puts you on the right track! (I get tripped up on date math a bit too, especially with timezones)

PHP - Is there a simple way to loop between two dates and fill in missing values?

I have 2 dates. Lets say they look like this.
$start = 2010/12/24;
$end = 2012/01/05;
I query the database to look for visits between these two dates. I find some. I then populate an array called stats.
$stats['2010/12/25'] = 50;
$stats['2010/12/31'] = 25;
...
As you can see, there are days missing. I need to fill the missing dates with a value of zero. I was thinking something like this. (I have pulled day / month / year from start and end dates.
for($y=$start_year; $y <= $end_year; $y++) {
for($m=$start_month; $m <=$end_month; $m++) {
for($d=$start_day; $d <= $end_day; $d++) {
This would work fine for the year however the months and days wouldn't work. If the start day is the 15th. Days 1-14 of each subsequent month would be missed. I could have a solution like this then...
for($y=$start_year; $y <= $end_year; $y++) {
for($m=1; $m <13; $m++) {
$total_days = cal_days_in_month(CAL_GREGORIAN, $m, $y) + 1;
for($d=1; $d <= $total_days; $d++) {
I would then need a bunch of if statements making sure starting and end months and days are valid.
Is there a better way of doing this? Or could this even be done in my mysql query?
Just to demonstrate the power of some of PHP's newer interval handling method (mentioned by pgl in his answer):
$startDate = DateTime::createFromFormat("Y/m/d","2010/12/24",new DateTimeZone("Europe/London"));
$endDate = DateTime::createFromFormat("Y/m/d","2012/01/05",new DateTimeZone("Europe/London"));
$periodInterval = new DateInterval( "P1D" ); // 1-day, though can be more sophisticated rule
$period = new DatePeriod( $startDate, $periodInterval, $endDate );
foreach($period as $date){
echo $date->format("Y-m-d") , PHP_EOL;
}
Does require PHP >= 5.3.0
EDIT
If you need to include the actual end date, then you need to add a day to $endDate immediately before the foreach() loop:
$endDate->add( $periodInterval );
EDIT #2
$startDate = new DateTime("2010/12/24",new DateTimeZone("Europe/London"));
$endDate = new DateTime("2012/01/05",new DateTimeZone("Europe/London"));
do {
echo $startDate->format("Y-m-d") , PHP_EOL;
$startDate->modify("+1 day");
} while ($startDate <= $endDate);
For PHP 5.2.0 (or earlier if dateTime objects are enabled)
If you're using PHP5.3 then Mark Baker's answer is the one to use. If (as you say in your comment) you're still on PHP5.2 something like this should help you:
$startdate = strtotime( '2010/12/24' );
$enddate = strtotime( '2012/01/05' );
$loopdate = $startdate;
$datesArray = array();
while( $loopdate <= $enddate ) {
$datesArray[$loopdate] = 0;
$loopdate = strtotime( '+1 day', $loopdate );
}
It will create an array of the unix timestamp of every date between the start and end dates as the index and each value set to zero. You can then overwrite any actual results you have with the correct values.
$start_date = DateTime::createFromFormat('Y/m/d', '2010/12/24');
$end_date = DateTime::createFromFormat('Y/m/d', '2012/01/05');
$current_date = $start_date;
while($current_date <= $end_date) {
$current_date = $current_date->add(new DateInterval('P1D'));
// do your array work here.
}
See DateTime::add() for more information about this.
$i = 1;
while(date("Y/m/d", strtotime(date("Y/m/d", strtotime($start)) . "+ $i days")) < $end) {
... code here ...
$i++;
}
I would calculate the difference between start and end date in days, iterate on that adding a day to the timestamp on each iteration.
$start = strtotime("2010/12/24");
$end = strtotime("2012/01/05");
// start and end are seconds, so I convert it to days
$diff = ($end - $start) / 86400;
for ($i = 1; $i < $diff; $i++) {
// just multiply 86400 and add it to $start
// using strtotime('+1 day' ...) looks nice but is expensive.
// you could also have a cumulative value, but this was quicker
// to type
$date = $start + ($i * 86400);
echo date('r', $date);
}
I have this bit of horrible code saved:
while (($tmptime = strtotime('+' . (int) $d++ . ' days', strtotime($from))) && ($tmptime <= strtotime($to))) // this code makes baby jesus cry
$dates[strftime('%Y-%m-%d', $tmptime)] = 0;
(Set $from and $to to appropriate values.) It may well make you cry, too - but it sort of works.
The proper way to do it is to use DateInterval, of course.

PHP: Populating an array with the names of the next 12 months

for($x=0; $x<12; $x++)
{
$month = mktime(0, 0, 0, date("m")+$x, date("d"), date("Y"));
$key = date('m', $month);
$monthname = date('F', $month);
$months[$key] = $monthname;
}
I know for sure I'm doing the math incorrectly for the 4th parameter of mktime. I'm starting with the current month number ( 7 being July ) and adding 1 for each next month, sometimes it ends up being that the same month is returned twice, maybe because I'm not setting it to the beginning of the month? How would you improve/recode this?
Result is that $months would result in an array where 07 = July 08 = August, 09 = September. Right now it populates October twice. I think it has to do with today being the 31st and it incorrectly adds and reaches the next month.
Just fixed your code slightly, this should work pretty well:
$months = array();
$currentMonth = (int)date('m');
for ($x = $currentMonth; $x < $currentMonth + 12; $x++) {
$months[] = date('F', mktime(0, 0, 0, $x, 1));
}
Note that I took out the array key, as I think it's unnecessary, but you can change that of course if you need it.
An alternative would be to use strtotime:
for ($x=0; $x < 12; $x++) {
$time = strtotime('+' . $x . ' months', strtotime(date('Y-M' . '-01')));
$key = date('m', $time);
$name = date('F', $time);
$months[$key] = $name;
}
In my opinion this code is easier to read.
Less complicated, no loops, generic array keys:
function stackoverflow_get_monthname($x){
return date("F",mktime(NULL, NULL, NULL, (int)date("n") + ($x+1), NULL, NULL));
}
$months = array_map("stackoverflow_get_monthname", range(1,12) );
var_dump($months);
Given 2592000 is 30 days.
$month_time = 60*60*24*30; // 30 Days
for($x=0; x<12; $x++)
{
$time = time()+($month_time*$x);
$key = date('m', $time);
$month[$key] = date('F', $time);
}
In an answer on StackOverflow, can't find it right now, someone compared the performance of multiple methods of creating a time 1 week from now. Directly using numbers was much more efficient than any other method.
You might be getting the last day of the month (the 31st) bug - which led to two months with the same link - that Eddy very nicely figured out for me with this answer:
$current_month = date('n');
$MONTHS = array();
for ($m=0; $m<12; $m++) {
$display_month = $m + $current_month;
$MONTHS[] = date('F',mktime(1,1,1,$display_month,1,date("Y")));
"Result is that $months would result in an array where 07 = July 08 = August, 09 = September."
for ($key = 1; $key <=12; $key++) {
$months[str_pad($key, 2, '0', STR_PAD_LEFT)] = date('F', strtotime('2000-' . $key));
}
If you're okay with 7 = July 8 = August, 9 = September, then:
for ($key = 1; $key <=12; $key++) {
$months[$key] = date('F', strtotime('2000-' . $key));
}
Sometime you need to be careful on your locale, so this is my solution (in a function):
$months = [];
for ($x=1; $x < 13; $x++) {
$time = mktime(0, 0, 0, $x, 1);
$key = date('m', $time);
$name = ucfirst(strftime('%B', $time));
$months[(int)$key] = $name;
}
return $months;
Here is a simple script to go forward 12 months from the current date. It includes the year with it.
# Set Number of Months to Traverse
$num_months = 12;
# Set Current Month as the 1st
$current_month = date('Y-m').'-01';
for ($count = 0; $count <= $num_months; $count++) {
# Fetch Date for each as YYYY-MM-01
$dates[] = date('Y-m', strtotime($current_month.' + '.$count.' Months')).'-01';
}
You could turn this into a select list with the current month selected by dropping this in:
echo '<select name="month">';
foreach ($dates as $d) {
echo '<option value="'.$d.'"';
if ($d == date('Y-m').'-01') echo 'selected="selected"';
echo '>'.date('F, Y', strtotime($d)).'</option>';
}
echo '</select>';

Categories