Working on a small app which excludes weekends and public holidays from two set dates range. ie if user enters 2019-05-01 and 2019-05-10 it returns the range without the weekends and if there are any public holidays exclude those from results.
i get the date range with the time per day, working hours from two variables
$duration = $endTime - $startTime;
How can i use in_array to
results returned when i print date between 2019-05-01 and 2019-05-09
//date range
Array
(
[2019-05-01] => 09:30:00
[2019-05-02] => 09:30:00
[2019-05-03] => 09:30:00
[2019-05-06] => 09:30:00
[2019-05-07] => 09:30:00
[2019-05-08] => 09:30:00
[2019-05-09] => 09:30:00
)
// public holiadys
Array
(
[0] => 2019-05-08
[1] => 2019-05-09
)
$start = new DateTime('2019-05-01');
$end = new DateTime('2019-05-31');
// getting the day interval https://php.net/manual/en/class.dateinterval.php
$day = new DateInterval("P1D");
//holidays hardcoded for testing, must create database abd select dates from there
$holidays = array('2016-01-01','2016-03-25');
$days = array();
//hours set to 8 hours a daye
$startTime = new DateTime('08:00:00');
$endTime = new DateTime('17:30:00');
$duration = $startTime->diff($endTime);
$data = $endTime - $startTime;
foreach(new DatePeriod($start, $day, $end->add($day)) as $day => $k) {
$day_num = $k->format("N");
$w = $day_num;
if($w < 6) { //if its wmore than 5 its weekend
$days[$k->format("Y-m-d")] = $duration->format("%H:%I:%S");
}
}
foreach ($holidays as $value) {
$value = $value;
}
print_r($days);
print_r($holidays);
need to calculate the total time between those dates excluding weekend and public holidays
You didn't say, so I will assume that the weekend part is working. Just check the $holidays array:
foreach(new DatePeriod($start, $day, $end->add($day)) as $k) {
$dnm = $k->format("N");
$key = $k->format("Y-m-d")
if($dnm < 6 && !in_array($key, $holidays)) {
$days[$key] = $duration->format("%H:%I:%S");
}
}
Related
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);
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
I have a start date and end date.
I'm trying to get all the Tuesdays and Wednesdays of every two weeks.
Example:
2017-05-23 (tu)
2017-05-24 (we)
2017-06-06 (tu)
2017-06-07 (we)
...
What I'm trying to do in PHP:
$start = new FrozenTime('2017-05-23'); // Date is in this format 'cause I'll save into DB
$endOfYear = $start->endOfYear();
$perWeek = new \DateInterval('P14D'); // I want every 2 weeks
$periodPerWeek = new \DatePeriod($start, $perWeek, $endOfYear);
$days = ['2', '3']; // Tuesday and Wednesday
foreach ($periodPerWeek as $value) {
if (in_array($value->format('N'), $days)) {
$test[] = [
'start' => $value
];
}
}
The results:
"start": "2017-05-23",
"start": "2017-06-06",
"start": "2017-06-20",
It's getting only one date in array. I need to get the Wednesday's too! How can I do it?
IMPORTANT:
The start date will not be always Tuesday. The user can choose the week days that he wants.
Ex:
The user can choose every SU, WE and FR in every two weeks.
// start date example: 2017-05-20 (saturday)
// output should be like:
2017-05-22 (SU)
2017-05-24 (WE)
2017-05-26 (FR)
2017-06-05 (SU)
2017-06-07 (WE)
2017-06-09 (FR)
...
One way to do it
/**
* #param \DateTime $start
* #param \DateTime $end
* #param array $days i.e. ['tue', 'wed', 'sat']
*
* #return array
*/
function every_two_weeks($start, $end, $days)
{
$dates = [];
$mon = new DateTime('mon this week '.$start->format('Y-m-d'));
while ($mon <= $end) {
$of = 'this week '.$mon->format('Y-m-d');
foreach ($days as $day) {
$date = new DateTime("$day $of");
if ($date < $start) {
continue;
}
if ($date > $end) {
break 2;
}
$dates[] = $date;
}
$mon->add(new DateInterval('P2W'));
}
return $dates;
}
Usage:
$start = new DateTime('2017-05-23');
$end = new DateTime('2017-06-21');
$dates = every_two_weeks($start, $end, ['tue', 'wed', 'sat']);
Output:
2017-05-23 Tue
2017-05-24 Wed
2017-05-27 Sat
2017-06-06 Tue
2017-06-07 Wed
2017-06-10 Sat
2017-06-20 Tue
2017-06-21 Wed
3v4l demo
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;
}
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;
}