need to obtain all wednesday dates between two dates. For ex
start and end date=
01/07/2019 - 01/25/2019
expected result=
01/09/2019,
01/16/2019,
01/23/2019
can i use if ($startDate->format('w') == 2) {}
condition to filter wednesdays and push into array. any method to get the result?
Use DatePeriod Class. date period allows iteration over a set of dates and times, recurring at regular intervals, over a given period.
$period = new DatePeriod(
new DateTime($date1),
new DateInterval('P1D'),
new DateTime($date2)
);
$cnt = 0;
foreach ($period as $key => $value) {
if($value->format('D') == 'Wed'){
$wed[$cnt] = $value->format('m/d/Y');
$cnt++;
}
}
Output
[0] => 01/09/2019
[1] => 01/16/2019
[2] => 01/23/2019
<?php
$from_date ='01/07/2019';
$to_date ='01/25/2019';
$from_date = new DateTime($from_date);
$to_date = new DateTime($to_date);
$get_date = array();
for ($date = $from_date; $date <= $to_date; $date->modify('+1 day')) {
if($date->format('l') == 'Wednesday'){
$get_date[] = $date->format('m/d/Y');
}
}
print_r($get_date);
Out put
Array ( [0] => 01/09/2019 [1] => 01/16/2019 [2] => 01/23/2019 )
You will get the required output.
<?php
$date1 = date("01/07/2019");
$date2 = date("01/25/2019");
$day1 = date('D', strtotime($date1));
$period = new DatePeriod(New Datetime($date1),New DateInterval('P1D'),New DateTime($date2));
$cnt = 0;
foreach($period as $key => $value ){
if($value->format('D') == 'Wed'){
$wed[$cnt] = $value->format('m/d/Y');
echo $wed[$cnt];
$cnt++;
echo '<BR>';
}
}
?>
Using the base DateTime class and instead of checking every day, just keep adding 7 days to the date and check if it is still less than the end date. The only additional logic is that if the start date is a Wednesday, then use this date, otherwise get the next Wednesday...
$fromDate = new DateTime('01/02/2019');
if ( $fromDate->format('D') != 'Wed') {
$fromDate->modify("next wednesday");
}
$toDate = new DateTime('01/25/2019');
do {
echo $fromDate->format("m/d/Y").PHP_EOL;
}
while ( $fromDate->modify(""+7 day"") < $toDate );
outputs...
01/02/2019
01/09/2019
01/16/2019
01/23/2019
Related
I am new to PHP. I am displaying the monthly events which is starting event from 03/31/2021 on every month, so here is a critical situation come because not every month exists 31 date. So there is some php function available to check this date is exists in next coming months. If exists then display the event on that date otherwise display the last date of the month.
$monthly_counter = 0;
$monthly_counter_offset = 0;
$begin = new DateTime($val->start); // $val->start = '03/31/2021'
$end = new DateTime($val->repeat_end_date); // $val->repeat_end_date= '03/31/2022'
$interval = DateInterval::createFromDateString('1 month');
$period = new DatePeriod($begin, $interval, $end);
foreach ($period as $dt)
{
$loop_date = $dt->format('m/d/Y');
$loop_date_formatted = $dt->format('Y-m-d');
$due_dates[] = $from_date_times;
$from_new_date_times = date('Y-m-d H:i', strtotime('+1 month', strtotime($from_date_times)));
$from_date_times = $from_new_date_times;
$deletedevents2=$val->deletedevents;
$arrayofdeleted=explode(",",$deletedevents2);
$originalDate = $from_date_times;
$newDateforcompare = date("m/d/Y", strtotime($originalDate));
if (in_array($loop_date_formatted, $arrayofdeleted))
{
continue;
}
$number_of_days = $val->number_of_days;
$end_new_date_times = date('Y-m-d H:i', strtotime('+'.$number_of_days.' day', strtotime($loop_date)));
if(date('Y-m-d ', strtotime($val->start))<date('Y-m-d', strtotime($val->ends)))
{
$end_new_date_times = date('Y-m-d H:i', strtotime('+1 day', strtotime($end_new_date_times)));
}
$skipcounter = $val->interval_value;
if (!empty($skipcounter) || $skipcounter != 1) {
$monthly_counter++;
$monthly_counter_offset++;
if ($monthly_counter == $skipcounter || $monthly_counter_offset == 1) {
$monthly_counter = 0;
} else {
continue;
}
} else {
}
$rows[] = array(
'id' => $val->id,
'title' => $val->title,
'description' => $val->calendar_comments,
'start' => $loop_date,
'end' => $end_new_date_times,
'borderColor'=>$val->color,
'backgroundColor'=>$val->color_bg,
'className'=>'timegridclass',
'allDay' => $allday,
);
}
Since you're using fullCalendar, you can simply specify an event which uses RRule to specify the recurrence, rather than using complex PHP code to try and generate it.
e.g.
events: [
{
title: "Sales Meeting",
rrule: "FREQ=MONTHLY;BYMONTHDAY=28,29,30,31;BYSETPOS=-1"
}
]
Working demo: https://codepen.io/ADyson82/pen/bGByBaV
This will generate an event which repeats on the last day of every month, regardless whether the month is 28, 29, 30 or 31 days long.
Obviously you can use PHP to generate this event object, and enhance it with a custom title, start/end dates etc as per your database contents. But I have shown you the basic approach.
Credit to this answer for the specific RRule string.
Documentation: https://fullcalendar.io/docs/rrule-plugin and https://github.com/jakubroztocil/rrule
I want to generate a list of salary coverage dates using the last salary date of an employee. The employee gets a salary every 15 days. So every month the coverage should be 1st - 15th and 16th - last day of the month.
For example,
$last_salary_date = "2020-12-01";
$date_now = "2021-02-27";
// I should get the following start and end dates:
// 2020-12-01 - 2021-12-15
// 2020-12-16 - 2021-15-31
// 2021-01-01 - 2021-01-15
// 2021-01-16 - 2021-01-31
// 2021-02-01 - 2021-02-15
// 2021-02-16 - 2021-02-28
$last_salary_date = "2020-02-16";
$date_now = "2021-02-27";
// I should get the following start and end dates:
// 2021-02-16 - 2021-02-28
So far I've done something like this:
$start_date = new DateTime("2021-01-16");
$end_date = new DateTime(date("Y-m-d"));
$interval = \DateInterval::createFromDateString('1 month');
$period = new \DatePeriod($start_date, $interval, $end_date);
$salary_dates = [];
foreach ($period as $dt) {
if (date("Y-m-d") > $dt->format("Y-m-01")) {
$salary_dates[] = (object) [
'start_dt' => $dt->format("Y-m-01"),
'end_dt' => $dt->format("Y-m-15")
];
}
if (date("Y-m-d") > $dt->format("Y-m-15")) {
$salary_dates[] = (object) [
'start_dt' => $dt->format("Y-m-16"),
'end_dt' => $dt->format("Y-m-t")
];
}
}
return $salary_dates;
The problem is it still gets the 1-15th of the first month even though the start should be the 16th.I'm thinking of a better way to do this. Please help
Here is the modified implementation. It is sketched for understanding, but can also be written in a shorter form.
<?php
$start_date = new DateTime("2021-02-16");
$end_date = new DateTime("2021-02-27");
$interval = \DateInterval::createFromDateString('1 month');
$period = new \DatePeriod($start_date, $interval, $end_date);
$salary_dates = [];
foreach ($period as $dt) {
$check_date = function ($date) use ($start_date, $end_date) {
// check if salary interval is in correct range
return
$start_date->format("Y-m-d") <= $date->start_dt
and $end_date->format("Y-m-d") >= $date->start_dt; // are you sure it shouldn't be ->end_dt ? now it's on order
};
// check first two weeks in month
$salary_date = (object)[
'start_dt' => $dt->format("Y-m-01"),
'end_dt' => $dt->format("Y-m-15"),
];
if ($check_date($salary_date)) {
$salary_dates[] = $salary_date;
}
// check second two weeks in month
$salary_date = (object)[
'start_dt' => $dt->format("Y-m-16"),
'end_dt' => $dt->format("Y-m-t")
];
if ($check_date($salary_date)) {
$salary_dates[] = $salary_date;
}
}
print_r($salary_dates);
Recordset when looped shows the results of the associated array.
[date] = startDate and [dateLast] = $endDate
Result:
2019-01-19 - 2019-01-22
2019-01-19 - 2019-01-23
2019-01-20 - 2019-01-25
2019-01-22 - 2019-01-25
2019-01-27 - 2019-01-30
2019-01-29 - 2019-01-31
2019-02-01 - 2019-02-05
Each row designates a booking start and end date. I want to generate a list of unique comma separated dates to use in a calendar.
Looping the same recordset I am trying to create an array of all the actual dates (start, end, and in between).
As I am looping a recordset, I am first using the first start and end date and putting those in an array.
Then using array_push to update that array with each records start and end dates. Then using array_unique to retain only unique values.
<?php
$wa_startindex = 0;
while(!$reservALL->atEnd()) {
$wa_startindex = $reservALL->Index;
?>
<?php
$startDate = ($reservALL->getColumnVal("date"));
$endDate = ($reservALL->getColumnVal("dateLast"));
$format = "Y-m-d";
$begin = new DateTime($startDate);
$end = new DateTime($endDate);
$interval = new DateInterval('P1D'); // 1 Day
$dateRange = new DatePeriod($begin, $interval, $end);
$range = [];
foreach ($dateRange as $date) {
$range[] = $date->format($format);
$result = array_unique($range, SORT_REGULAR);
}
?>
<?php
$reservALL->moveNext();
}
$reservALL->moveFirst(); //return RS to first record
unset($wa_startindex);
unset($wa_repeatcount);
?>
But it seems to neglect many of the records as well as display repeating dates. Because the keys are preserved in array_unique that may explain the repeating records.
In any event the results of a print_r($result) show the following that is not what is expected. It's working but only showing the Last record and not appending each records Start End as well as in-between dates.
Array
(
[0] => 2019-02-01
[1] => 2019-02-02
[2] => 2019-02-03
[3] => 2019-02-04
)
Is the problem how that array is appended with array_push? It seems like it over writing rather than appending.
UPDATE TO SHOW FINAL CORRECT CODE:
<?php
$wa_startindex = 0;
$range = []; // declare Arry
while(!$reservALL->atEnd()) {
$wa_startindex = $reservALL->Index;
?>
<?php
$startDate = ($reservALL->getColumnVal("date"));
$endDate = ($reservALL->getColumnVal("dateLast"));
$format = "m-d-Y";
$begin = new DateTime($startDate);
$end = new DateTime($endDate);
$interval = new DateInterval('P1D'); // 1 Day
$dateRange = new DatePeriod($begin, $interval, $end);
foreach ($dateRange as $date) {
$range[] = $date->format($format);
}
array_push($range, $result);
?>
<?php
$reservALL->moveNext();
}
$result = array_filter(array_unique($range)); // array_filter removes any empty records
$reservALL->moveFirst(); //return RS to first record
unset($wa_startindex);
unset($wa_repeatcount);
?>
Without the array_filter() applied there is a single empty record:
[0] => 01-10-2019
[1] => 01-11-2019
[2] => 01-12-2019
[3] => 01-13-2019
[4] =>
[15] => 01-19-2019
[16] => 01-20-2019
[17] => 01-21-2019
Today's date being "01-19-2019" suggests it may be related to the DateInterval('P1D').
Your first problem is that you are rewriting $range on every pass through the loop with this line:
$range = [];
You should move that line outside the loop. i.e.
$wa_startindex = 0;
$range = [];
while(!$reservALL->atEnd()) {
...
You also have issues with pushing data into $range. You are pushing arrays into it instead of single values. Change this code:
foreach ($dateRange as $date) {
$range[] = $date->format($format);
$result = array_unique($range, SORT_REGULAR);
}
array_push($range, $result);
to
foreach ($dateRange as $date) {
$range[] = $date->format($format);
}
and then at the end of your loop, call array_unique:
...
}
$range = array_unique($range);
$reservALL->moveFirst(); //return RS to first record
I'm looking into trying to set up and array that will look something like this:
$dates = array(
[0] => "07/11/2013",
[1] => "14/11/2013",
[2] => "21/11/2013",
[3] => "28/11/2013",
[4] => "05/12/2013",
[5] => "12/12/2013");
I'm willing to use this, but as I want this to reoccur again next year I'd prefer to have PHP do this and enter it into an array for me. I know how to limit it to a specific amount that I want, but I don't know how to add a week onto the current date or specific date if I wanted to start 08/11/2013 for example.
I've had a quick look and I can't seem to find anything that does this.
I just need a script to add a week to the current date, at the moment this is every Thursday, and then add that to the array.
My only problem is I'm not sure how to specify a date, and then add a week every time. I assume a for loop would be best here.
Use DateTime class. DateInterval and DatePeriod classes were introduced in PHP 5.3.0, so the below solution works for only PHP >= 5.3.0:
$start = new DateTime('2013-11-07');
$end = new DateTime('2013-12-31');
$interval = new DateInterval('P1W'); // one week
$p = new DatePeriod($start, $interval, $end);
foreach ($p as $w) {
$weeks[] = $w->format('d-m-Y');
}
Demo!
As Glavic notes in the comments below, this can also be done in previous versions of PHP using the modify() method:
$start = new DateTime('2013-11-07');
$end = new DateTime('2013-12-31');
$weeks = array();
while ($start < $end) {
$weeks[] = $start->format('d-m-Y');
$start->modify('+1 week');
}
Demo.
You can use strtotime('+1 week', $unixTimestamp) for this:
<?php
$startDate = '2013-11-07';
$endDate = '2013-12-31';
$startDateUnix = strtotime($startDate);
$endDateUnix = strtotime($endDate);
$dates = array();
while ($startDateUnix < $endDateUnix) {
$dates[] = date('Y-m-d', $startDateUnix);
$startDateUnix = strtotime('+1 week', $startDateUnix);
}
print_r($dates);
?>
Outputs:
Array
(
[0] => 2013-11-07
[1] => 2013-11-14
[2] => 2013-11-21
[3] => 2013-11-28
[4] => 2013-12-05
[5] => 2013-12-12
[6] => 2013-12-19
[7] => 2013-12-26
)
DEMO
(format the date() call in any way you want to get the format you want).
strtotime does what you need
$nextWeek = strtotime('08/11/2013 + 1 week');
If you need that 8 times, loop it 8 times. You can make a function with $start and $numWeek to return an array with $numWeeks+1 values (the start added)
function createDateList($start, $numWeeks){
$dates = array($start);// add first date
// create a loop with $numWeeks illiterations:
for($i=1;$<=$numWeeks; $i++){
// Add the weeks, take the first value and add $i weeks to it
$time = strtotime($dates[0].' + '.$i.' week'); // get epoch value
$dates[] = date("d/M/Y", $time); // set to prefered date format
}
return $dates;
}
would the strtotime() function work here?
$nextweek = strtotime('thursday next week');
$date = date('d/m/Y', $nextweek);
To create a 5 element array containing today (or this thursday) and the next 4:
for ($a = 0; $a < 5; $a++)
{
$thur = date('d/m/Y', strtotime("thursday this week + $a weeks"));
$dates[] = $thur;
}
What I am trying
I am making an event management system using PHP. In this the event may repeat for some days. In cases where event repeats, the array will contain an end date for repeat ie; the end date till which the event should repeat.
array[] = array([0]=>array(
[name]=>test1
[start]=>2013-06-23 11:00
[end]=>2013-06-23 13:00
[repeat]=>true
[repeat-end]=>2013-06-25)
[1]=>array(
[name]=>test2
[start]=>2013-06-21 14:00
[end]=>2013-06-21 16:00
[repeat]=>false))
What I require
If an event repeats then the array must populate with all data till the repeat end date and corresponding start and end.
In the above case the event duration is shown as start and end and repeat end date is shown as repeat-end. In this the array should be populated as shown below:
array[] = array([0]=>array(
[name]=>test1
[start]=>2013-06-23 11:00
[end]=>2013-06-23 13:00
[repeat]=>true
[repeat-end]=>2013-06-25)
[1]=>array(
[name]=>test2
[start]=>2013-06-21 14:00
[end]=>2013-06-21 16:00
[repeat]=>false
[2]=>array(
[name]=>test1
[start]=>2013-06-24 11:00
[end]=>2013-06-24 13:00
[repeat]=>true
[repeat-end]=>2013-06-25)
[3]=>array(
[name]=>test1
[start]=>2013-06-25 11:00
[end]=>2013-06-25 13:00
[repeat]=>true
[repeat-end]=>2013-06-25)
))
What I tried
I tried using the php DatePeriod functionality here
foreach ($array as $result){
if($result['repeat == true']){
$period = new DatePeriod(
new DateTime($result['start']),
new DateInterval('P1D'),
new DateTime($result['repeat-end']), DatePeriod::EXCLUDE_START_DATE);
$period = iterator_to_array($period);
}
}
Using this all the dates between the start and repest-end where obtianed and i inserted values foreach dates into the array. But I could not obtain the last start date in the array and end date became complicated when start and end date [not repeat-end] where different.
Maybe something like this: (probably could be optimized, but i have feel that this works... or if it is not working completely - it is good start:))
$array = array(
array(
'name'=>'test1',
'start'=>'2013-06-23 11:00',
'end'=>'2013-06-23 13:00',
'repeat'=>true,
'repeat-end'=>'2013-06-25'
),
array(
'name'=>'test2',
'start'=>'2013-06-21 14:00',
'end'=>'2013-06-21 16:00',
'repeat'=>false
)
);
$final=array();
foreach ($array as $sub)
{
if($sub['repeat']==1)
{
//print_r($sub);
$start_date = $sub['start'];
$end_date = $sub['repeat-end'];
$begin = new DateTime($sub['start'] );
$end = new DateTime( $sub['repeat-end'] );
$end = $end->modify( '+1 day' );
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($begin, $interval, $end);
foreach ( $period as $dt ) {
// echo $dt->format( "Y-m-d H:i" );
$new_day=$dt->format( "Y-m-d H:i" );
$new_end= new DateTime($dt->format( "Y-m-d H:i" ));
$new_end = $new_end->modify( '+2 hours' );
$temp=array();
$temp['name']=$sub['name'];
$temp['start']=$new_day;
$temp['end']=$new_end->format('Y-m-d H:i');
$temp['repeat']=true;
$temp['repeat-end']=$end_date;
$final[]=$temp;
}
}
}
//print_r($final);
$done=array_merge($array,$final);
$done=array_unique($done,SORT_REGULAR);
print_r($done);
I think your problem is not adding timestamp to $result['repeat-end'] element.
The number of days between 2013-01-01:11:00 and 2013-01-02 is less than 1. So you should replace this line in your code:
new DateTime($result['repeat-end']);
by this one:
new DateTime($result['repeat-end'] . " 23:59:59");
This code would work for you:
foreach ($array as $result){
if($result['repeat'] === true){
$date_start = new DateTime($result['start']);
//Becouse "time start" > "time repeat-end" you need add timestamp
$date_end = new DateTime($result['repeat-end'] . " 23:59:59");
$period = new DatePeriod($date_start,
new DateInterval('P1D'),
$date_end,
DatePeriod::EXCLUDE_START_DATE
);
//Adding new tests to the original array
foreach($period as $dt){
$result['start'] = $date_start->modify("+1 day")->setTime(11,0)->format('Y-m-d h:i');
$result['end'] = $date_start->modify("+2hours")->format('Y-m-d h:i');
$array[] = $result;
}
}
}
I hope it should be useful for you.