I want users to be able to select a date range and an interval to display results from, such as "show me results between Jan 1, 2017 and Apr 1, 2017, listed by day|week|month"
So if they selected day, I'd group results by Jan 1, 2017; Jan 2, 2017; Jan 3, 2017; etc...
If they selected week, it'd be Jan 1, 2017; Jan 8, 2017; Jan 15, 2017; etc...
The method I'm using now is as follows:
if(isset($chosenInterval) && ($chosenInterval == "week" || $chosenInterval == "day") ) {
$timeFormat = "F j, Y";
} else {
$timeFormat = "F Y";
$chosenInterval = "month";
}
$start = (new DateTime($start))->modify('first day of this month');
$end = (new DateTime($stop))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 '.$chosenInterval);
$period = new DatePeriod($start, $interval, $end);
foreach($period as $dt) {
$dataLabels[] = $dt->format($timeFormat);
}
The problem is that if the user selects Jan 8, 2017 - Jan 20, 2017, it still includes all the dates in January.
Ideally it would show:
Day: Jan 8, 2017; Jan 9, 2017; ... Jan 19, 2017; Jan 20, 2017
Week: Jan 8, 2017; Jan 15, 2017
Month: Jan, 2017
Any suggestions on how to accomplish this? Thanks!
You need to check when adding your DateTime objects to $dataLabels if the date is before the start or after the end. If it is (and the $chosenInterval is not a month), don't add them:
<?php
$start = "2017-01-08";
$stop = "2017-01-20";
$chosenInterval = "week";
function getDates($start, $stop, $chosenInterval = "week") {
$startDT = new DateTime($start); // make a DateTime out of the date to later compare it
$stopDT = new DateTime($stop); // make a DateTime out of the date to later compare it
if(isset($chosenInterval) && ($chosenInterval == "week" || $chosenInterval == "day") ) {
$timeFormat = "F j, Y";
} else {
$timeFormat = "F Y";
$chosenInterval = "month";
}
$begin = (new DateTime($start))->modify('first day of this month');
$end = (new DateTime($stop))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 '.$chosenInterval);
$period = new DatePeriod($begin, $interval, $end);
foreach($period as $dt) {
if ($chosenInterval !== "month" && ($dt < $startDT || $dt > $stopDT)) continue; // if date is before start or after end, skip
$dataLabels[] = $dt->format($timeFormat);
}
return $dataLabels;
}
var_dump(getDates($start, $stop));
var_dump(getDates($start, $stop, "day"));
var_dump(getDates($start, $stop, "month"));
Demo
Related
How to make a period with all months between two random dates?
I tried:
$startDate = \Carbon\Carbon::parse('2021-11-17 23:59:59');
$endDate = \Carbon\Carbon::parse('2022-01-10 00:00:00');
$period = \Carbon\CarbonPeriod::create($startDate, '1 month', $endDate);
foreach($period as $month)
{
echo '<pre>'.$month->format('Y-m-d').'</pre>';
}
but it doesn't include January.
I also tried to use floor():
$startDate = \Carbon\Carbon::parse('2021-11-17 23:59:59');
$endDate = \Carbon\Carbon::parse('2022-01-31 00:00:00');
$period = \Carbon\CarbonPeriod::create($startDate, '1 month', $endDate)->floor();
foreach($period as $month)
{
echo '<pre>'.$month->format('Y-m-d').'</pre>';
}
but it includes February that don't even need.
How to get pure "unical" months between two dates using CarbonPeriod?
For example: start_date: 2021-11-17 23:59:59 & end_date: 2022-01-10 00:00:00 -> 11, 12, 01
Also: start_date: 2021-11-17 23:59:59 & end_date: 2022-01-31 00:00:00 -> 11, 12, 01
Thank you.
use startOfMonth() and endOfMonth() as below.
$startDate = Carbon::parse('2021-11-17 23:59:59')->startOfMonth();
$endDate = Carbon::parse('2022-01-10 00:00:00')->endOfMonth();
foreach (CarbonPeriod::create( $startDate, '1 month', $endDate) as $month) {
echo $month->format('m') . PHP_EOL;
}
Output will be:
11
12
01
I'd like to calculate next billing date of Recurly plan in PHP.
There are 2 types of billing cycle: yearly | monthly.
I tried to use DateTime and DateInterval classes, but didn't get expected results.
<?php
$referenceTime = new \DateTime('2016-01-31');
$oneMonthLater = $referenceTime->modify('+1 month');
var_dump($oneMonthLater);
// public 'date' => string '2016-03-02 00:00:00.000000'
Adding one month to the 31st of Januray gives me the second of March and not the 29th (or 28th) of February as I would expect.
The same for the 31st of August:
<?php
$referenceTime = new \DateTime('2016-08-31');
$oneMonthLater = $referenceTime->modify('+1 month');
var_dump($oneMonthLater);
// public 'date' => string '2016-10-01 00:00:00.000000'
If yearly, I expect Feb 29, 2016 + 1 year => Feb 28, 2017
Thanks.
Try this, if date > 28 use last day of next month else use +1 month
$get_date = strtotime("31-01-2016");
$dt = explode("-",$get_date);
$dt = $dt[0];
var_dump(($dt > 28) ? date("d-m-Y", strtotime("31-01-2016 last day of next month")) : date("d-m-Y", strtotime("31-01-2016 +1 month")));
DEMO
You can call modify with PHP's DateTime object to calculate the next date relative to the current date. The following code shows how you would do it with your specific situation.
$next_bill_date = new DateTime();
switch($plan_interval_unit) {
case "year":
$next_bill_date->modify("last day of next month");
break;
case "month":
$next_bill_date->modify("last day of this month next year");
break;
}
May be something like that:
if (date('d') !== date('d', strtotime('+1 month'))
date ('Y-m-d H:i:s', strtotime('last day of next month'));
if (date('d') !== date('d', strtotime('+1 year'))
date ('Y-m-d H:i:s', strtotime('last day of this month next year'));
You can use PHP inbuilt strtotime() function
// One month from today
$date = date('Y-m-d', strtotime('+1 month'));
// One month from a specific date
$date = date('Y-m-d', strtotime('+1 month', strtotime('2016-12-06')));
function get_next_billing_date($now, $type, $format = 'Y-m-d')
{
$date = new DateTime($now);
$y = $date->format("Y");
$m = $date->format("m");
$d = $date->format("d");
if ($type == 'year') {
$y++;
if ($m == 2 && $d == 29) {
$d = 28;
}
} else if ($type == 'month') {
if ($m == 12) {
$y++;
$m = 1;
} else {
$m++;
}
$first_date = sprintf("%04d-%02d-01", $y, $m);
$last_day_of_next_month = date('t', strtotime($first_date));
if ($d > $last_day_of_next_month) {
$d = $last_day_of_next_month;
}
} else {
// not supported
return false;
}
$date->setDate($y, $m, $d);
return $date->format($format);
}
There is this Unix timestamp and it needs to generate the first days of the week as an array.
$time = '1456034400';
// This present Month February 2016
// in calendar the February has the start of the week
// Sunday 7
// Sunday 14
// Sunday 21
// Sunday 28
How do you get an array like this from the Unix Timestamp:
$weekdays = array(
0 => 7,
1 => 14,
2 => 21,
3 => 28
);
And this method needs to work and be accurate for any given month in years not just Feb 2016.
function getSundays($y, $m)
{
return new DatePeriod(
new DateTime("first Sunday of $y-$m"),
DateInterval::createFromDateString('next sunday'),
new DateTime("last day of $y-$m")
);
}
$days="";
foreach (getSundays(2016, 04) as $Sunday) {
$days[] = $Sunday->format("d");
}
var_dump($days);
https://3v4l.org/DVYM5
A bit faster way (since it uses a simple calculation to iterate weeks):
$time = 1456034400;
$firstDay = strtotime('first Sunday of '.date('M',$time).' '.date('Y',$time));
$lastDay = mktime(0,0,0,date('m',$time)+1,1,date('Y', $time));
$weekdays = array();
for ($i = $firstDay; $i < $lastDay; $i += 7*24*3600){
$weekdays[] = date('d',$i);
}
https://3v4l.org/lQkB2/perf#tabs
This give me every monday date in date range.
Question: How to get every monday and friday of week?
$start_date = date('Y-m-d');
$end_date = date('Y-m-d', strtotime($start_date . ' + 1 MONTH'));
for(
$i = strtotime('Monday', strtotime($start_date));
$i <= strtotime($end_date);
$i = strtotime('+1 WEEK', $i)
) {
echo date('Y-m-d', $i). '<br>';
}
My Update:
$my_dates = [];
for(
$i = strtotime($start_date);
$i <= strtotime($end_date);
$i = strtotime('+1 DAY', $i)
) {
if(in_array(date('N', $i), array(1, 5))) {
$my_dates[] = date('Y-m-d', $i);
}
}
var_dump($my_dates);
Have a look at library called When, it's "Date / Calendar recursion library for PHP 5.3+".
Let's say MF schedule for next month:
$now = new DateTime('NOW');
$till = clone $now;
$till->modify('+1 month');
$r = new When();
$r->startDate($now)
->freq("weekly")
->until($till)
->byday(array('MO', 'FR'))
->generateOccurrences();
$occurrences = $r->occurrences;
If I'm not wrong than you can simply use for loop like as
$start = "2015-09-01";
$end = date('Y-m-d', strtotime("$start +1 months"));
$period = floor((strtotime($end) - strtotime($start))/(24*60*60));
for($i = 0; $i < $period; $i++){
if(in_array(date('l',strtotime("$start +$i day")),["Monday","Friday"]))
echo date('l d M, Y',strtotime("$start +$i day"))."\n";
}
Output:
Friday 04 Sep, 2015
Monday 07 Sep, 2015
Friday 11 Sep, 2015
Monday 14 Sep, 2015
Friday 18 Sep, 2015
Monday 21 Sep, 2015
Friday 25 Sep, 2015
Monday 28 Sep, 2015
Demo
sorry if this is a duplicate. Why does the following code error so? It returns Dec 6th currently, the first Friday in December (asking on 8 Oct 2013)
$thisMonth = date('m');
$year = date("Y");
$thismonthName = date("M.", mktime(0, 0, 0, $thisMonth,0,$year));
if ($thisMonth < 12) {
$nextmonthName = date("M.", mktime(0, 0, 0, $nextMonth,1,$year));
} else {
$nextMonth = 1;
$nextmonthName = date("M.", mktime(0, 0, 0, $nextMonth,1,$nextYear));
}
$thisDate = date('M j', strtotime($nextmonthName . $year . "first friday"));
print ("second friday next month is " . $thisDate);
but modifying it to be only next month, like so,
$thisMonth = date('m');
$year = date("Y");
$thismonthName = date("M.", mktime(0, 0, 0, $thisMonth,0,$year));
if ($thisMonth < 12) {
$nextmonthName = date("M.", mktime(0, 0, 0, $nextMonth,0,$year));
} else {
$nextMonth = 1;
$nextmonthName = date("M.", mktime(0, 0, 0, $nextMonth,0,$nextYear));
}
$thisDate = date('M j', strtotime($nextmonthName . $year . "first friday"));
print ("second friday next month is " . $thisDate);
returns Nov 8th, the second Friday in November. Why is that?
You REALLY should investigate DateTime, DateInterval, DatePeriod classes. They make this sort of thing trivial.
$date = new DateTime();
$interval = DateInterval::createFromDateString('second friday of next month');
$date->add($interval);
echo 'Second Friday next month is ' . $date->format('Y-m-d');
Or to get 2nd Friday for next 3 months:
$date = new DateTime();
$recurrence_count = 3;
$interval = DateInterval::createFromDateString('second friday of next month');
$period = new DatePeriod($date, $interval, $recurrence_count);
foreach ($period as $dt) {
echo $dt->format('Y-m-d');
}
Your code is way too complicated.
$secondNextFriday = new DateTime('first friday of +2 months'); // First friday in december