Given period at least covers one night on the weekend - php

I need to check the given period will at least be covers the one night of the weekend(saturday night or sunday night) (refer the wiki article about the rule).
I found this question that, how to check the date whether it is fall on weekend or not,
function isWeekend($date) {
$weekDay = date('w', strtotime($date));
return ($weekDay == 0 || $weekDay == 6);
}
But still I am struggle with how to implement a function to get following sample results for given periods,
Sample periods and results:
04-01-2016 / 07-01-2016 : false
04-01-2016 / 09-01-2016 : false
04-01-2016 / 10-01-2016 : true (covers saturday night)
03-01-2016 / 07-01-2016 : true (covers sunday night)
04-01-2016 / 14-01-2016 : true (covers a full weekend)
The rule should wither start date is falls on weekend or end date is falls on sunday or the period covers at a full weekend.

I presume you're looking for something like this:
function coversWeekend($start, $end) {
$weekend = [0, 6]; // 0 for Sunday, 6 for Saturday.
// Loop over the date period.
while ($start < $end) {
if (in_array($start->format('w'), $weekend)) {
return true;
}
$start->modify('+1 day');
}
return false;
}
Be warned, there isn't on validation on what the user passes in. You may want to add a check that a valid DateTime object was passed for each parameter.
Hope it helps.
Edit: Updated the solution with #honzalilak's feedback.

Related

Checking if a time range contains another time range in PHP

Hi Can you help me in my problem?
checking if a time range contains another time range for example I have 2 time range:
$nightShiftStart = strtotime("22:00:00 today");
$nightShiftEnd = strtotime("06:00:00 tomorrow");
$overTimeStart = strtotime("21:00:00 today");
$overTimeEnd = strtotime("07:00:00 tomorrow");
if I check if overtime start and end contains night shift schedule it should return true. And I have a code for that.
if ($overTimeStart >= $nightShiftStart && $overTimeEnd <= $nightShiftEnd ) {
return true;
} else {
return false;
}
the code above will return true. but if I change the overtime range to this:
$nightShiftStart = strtotime("22:00:00 today");
$nightShiftEnd = strtotime("06:00:00 tomorrow");
$overTimeStart = strtotime("17:00:00 today");
$overTimeEnd = strtotime("20:00:00 today");
it also return true, it should return false because the overtime is only from 5pm to 8pm and the time not meet the Night Shift. Can you pls help me with this i've been stuck for 2days.
Take a look at the document: https://www.php.net/manual/en/datetime.formats.relative.php
Exceptions to this rule are: "yesterday", "midnight", "today", "noon" and "tomorrow". Note that "tomorrow 11:00" and "11:00 tomorrow" are different. Considering today's date of "July 23rd, 2008" the first one produces "2008-07-24 11:00" where as the second one produces "2008-07-24 00:00". The reason for this is that those five statements directly influence the current time.
So the correct strings should be:
$nightShiftStart = strtotime("today 22:00:00");
$nightShiftEnd = strtotime("tomorrow 06:00:00");
$overTimeStart = strtotime("today 17:00:00");
$overTimeEnd = strtotime("today 20:00:00");

PHP, repeating events check next one with unix timestamps

I have a problem with php that i don't really know how to solve. I have an array full of unix timestamps coming from a mysql query.
These timestamps are events that repeat every week ( For example, every Tuesday and Thursday ). They can repeat various days or just one.
Knowing the days that repeat, which day will be the next one.
For example:
In the Array I have :
1595289600 --> 2020/07/21 (Tuesday)
1595116800 --> 2020/07/19 (Sunday)
Today we are at 1595376000 (Wednesday) , so it should return 1595116800 + 604800 (Sunday).
In 5 days ( next monday) it should return 1595289600 + 604800 = 1595721600 (First tuesday + one week )
in one week (next Wednesday) , it should return the next Sunday (2020/08/02 ): 1596326400
And so on...
Thank you!
For every timestamp you have - calculate next timestamp (add a week) until it is after current timestamp. Then return lowest from those as that one will be the closest to now (but also in the future).
So lets say it is 2020-07-22 Wednesday.
Your 2020-07-21 Tuesday is in the past, so add a week: 2020-07-28 Tuesday - its in the future, so its our candidate.
Your 2020-07-19 Sunday is also in the past, so add a week: 2020-07-26 Sunday - its in the future so its out second candidate.
Now pick lower from 2 candidates: 2020-07-26 Sunday.
If the dates are more in the past then you will need more a week to them more times.
Something like this:
<?php
// those are your timestamps: $timestamps = [1595289600, 1595116800];
// $time is optional int for when you want to perform the calculation. defaults to current timestamp
function nextOccurence(array $timestamps, $time = null) {
$now = $time ?? time();
$nextTimestamps = [];
foreach ($timestamps as $timestamp) {
while ($timestamp < $now) {
$timestamp += 604800;
}
$nextTimestamps[] = $timestamp;
}
return min($nextTimestamps);
}

Pick a specific day of the week and start counting forward until a set limit is reached in php

Having a php challenge with dynamically setting a day of the week say -thursday, to a function and have the function loop through each day (friday, saturday.. tuesday until a condition i>0 is met.
I have searched thoroughly but could not finding a matching solution.
Please see break down below:
My form:
showing user input that's counted
My code:
//get duraiton in days
function durationInDays($data) {
$startDate = date_create($data['startdate']);
$endDate = date_create($data['enddate']);
$dateDiff = date_diff($startDate,$endDate);
$durationInDays = $dateDiff -> format("%a");
return $durationInDays;
}
//pass duration in days to function to break into weeks and days
function numberOfWeeksAndDays($durationInDays) {
$days = $numdays%7;
$weeks = floor($numdays/7);
return [$weeks, $days];
}
//parse in number of days into function to loop starting from
//day of week of start date say --thursday for example with a
//condition to stop loop once numberOfDays is zero.
function extraMassCount($dayOfWeek, $numberOfDays, $countMass) {
$daysOfTheWeek = [
'monday','tuesday','wednesday','thursday','friday','saturday','sunday',
'monday','tuesday','wednesday','thursday','friday','saturday','sunday'
];
$massCountForExtraDays = 0;
for ($i = $numberOfDays; $i > 0; $i--) {
if($daysOfTheWeek[$i]=='monday')
$massCountForExtraDays += $countMass[0];
if($daysOfTheWeek[$i]=='tuesday')
$massCountForExtraDays += $countMass[1];
if($daysOfTheWeek[$i]=='wednesday')
$massCountForExtraDays += $countMass[2];
if($daysOfTheWeek[$i]=='thursday')
$massCountForExtraDays += $countMass[3];
if($daysOfTheWeek[$i]=='friday')
$massCountForExtraDays += $countMass[4];
if($daysOfTheWeek[$i]=='saturday')
$massCountForExtraDays += $countMass[5];
if($daysOfTheWeek[$i]=='sunday')
$massCountForExtraDays += $countMass[6];
}
return $massCountForExtraDays;
}
The problem: If $numberOfDays=6,then i=6 and the function starts with friday which is not the start date.
My question: how do I implement dayOfWeek parameter so the function extraMassCount will start counting dynamically e.g thursday if startdate is thursday and not the way it is hardcoded to start? I hope my question is clear.
That is, as shown in the form, the function is supposed count the number of masses checked per day and add them together. Starting from startdate to the enddate. Once the durationInDays is broken down to weeks and days I need the function to start at the startdate say --wednesday and add countMass(which is a count of the Masses checked by the user with datatype int) for each day onward.. thursday, friday, etc. – I appreciate the help!
Like this, with relative date formats and DateTime class
$Date = new DateTime;
//go to monday
$Date->modify('monday this week');
for($i=0;$i<10;++$i){
echo $Date->format('l')."\n";
$Date->modify('+1 days'); //go to next day
}
Output
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Monday
Tuesday
Wednesday
Sandbox
I think the rest you can work out as I am not really sure what that does.
If you want a number for the day, for like this part $countMass[0]; you can use the w format. But 0 is Sunday, if I remember correctly.
for($i=0;$i<10;++$i){
$Date->modify('+1 days');
//dont assume your inputs will be correct
if(isset($countMass[$Date->format('w')])){
$massCountForExtraDays += $countMass[$Date->format('w')];
}
}
PS. instead of all these separate if statements, which is bad performance wise. I would just use a switch statement, but at the very least connect those with else so they don't all evaluate every time, needlessly. $daysOfTheWeek[$i] can only equal one of those. If you notice above, I just optimized them out.

PHP | How to find EVERY OTHER SUNDAY from SECOND SUNDAY of THIS YEAR to second sunday of NEXT YEAR

CONTEXT: My client, a local movie theater, runs a Sunday Matinee Special every other Sunday starting with the SECOND SUNDAY every year. So for this year the dates are 1/11, 1/18, 2/8, 2/22, .... [The only exception is the SUNDAY after their film festival which runs the the THIRD FULL WEEK OF OCTOBER, but automating this single exception is a "would-be-nice" item, not essential.]
MY SKILL LEVEL: BEGINNER (I need your help!) I believe I need to use a combination of mktime() and date() but I don't know how to put it together.
WHAT I'VE TRIED: I suspect the answer is a combination of what I see on these three posts:
(1) a do-while loop to get a specific day of the week from a date range
(2) there may be a shortcut for referencing the second sunday in the ACCEPTED ANSWER here, but I'm not sure this helps
(3) MOST RELEVANT(?): Get the First Sunday of Every Month
END RESULT: I want to display the [Month] and [Day] of the next Sunday Matinee (so I want to find and display the first item in the array AFTER the current date). The text will appear like this: "Next: [Month] [Day]"
Make sense? Let me know if I've forgotten anything.
If it's not too much to ask, please explain your code so I (and others?) can learn from this; but I'd be more than grateful for "merely" a straight-up solution.
Many thanks.
Debra
UPDATE/PROGRESS: This code will get me the array of Sundays:
$startDate = strtotime("second Sunday of ".date('Y')."");
for ($i=0; $i < 27; $i++){
$sundays = date('F j', ($startDate + (($i*14) * 24 * 3600))) . '<br>';
print $sundays;
}
NEXT TO FIGURE OUT: write a statement to find in the array of Sundays the first date after the current date.
This is a pretty manual, procedural solution, but it should work.
<?php
$SECS_PER_DAY = 86400;
# Find the first Sunday on or after a given timestamp
function firstSundayOnOrAfter($time) {
global $SECS_PER_DAY;
# What day of the week is the given date?
$wday = date('w', $time);
if ($wday == 0) {
# it's already a Sunday
return $time;
}
return $time + (7 - $wday) * $SECS_PER_DAY;
}
# return an array of timestamps representing
# (noon on) the special matinee Sundays for the given year
function specialMatineeSundays($year) {
global $SECS_PER_DAY;
# When's the film festival?
$oct1 = mktime(12,0,0,10,1,$year);
$festivalStart = firstSundayOnOrAfter($oct1);
$festivalSkip = $festivalStart + 7 * $SECS_PER_DAY;
# find the first Sunday of the year
$jan1 = mktime(12,0,0,1,1,$year);
$sunday = firstSundayOnOrAfter($jan1);
# Add a week to start with the second Sunday
$sunday += 7 * $SECS_PER_DAY;
# Build up our result list
$result = [];
# As long as the Sunday under examination is still the same year,
# add it to the list (unless it's the post-festival skip date)
# and then add two weeks
while (date('Y',$sunday) == $year) {
if ($sunday != $festivalSkip) {
$result[] = $sunday;
}
$sunday += 14 * $SECS_PER_DAY;
}
return $result;
}

Determine if a week is odd or even

I have debugged this legacy code, and would like a sanity check on it.
The purpose of it is to allow someone to choose a delivery frequency for shipping a product. If someone wants their product Every Other Week, the system needs to determine if they should get an order next week, or two weeks from now. We call it A week, or B Week.
Keep in mind I did not write this, I am just trying to make sense of it and would like some help evaluating its accuracy:
if (date("l") == "Monday" ) {
$start = 0;
} else if (date("l") == "Tuesday" || date("l") == "Wednesday" || date("l") == "Thursday" || date("l") == "Friday" || date("l") == "Saturday"|| date("l") == "Sunday") {
$start = -1;
}
// if changing to every other week set to next week's a/b-ness
$a_week_tid = 34;
$b_week_tid = 35;
$every_other_week_frequency_id = 32;
if ($delivery_frequency == $every_other_week_frequency_id) {
$julian = (int) (strtotime('Monday +' . $start . ' week') / 86400);
$julian_week = ($julian-4) / 7;
if ($julian_week % 2) {
$today_a_or_b = $b_week_tid;
$next_week_a_or_b = $a_week_tid;
$a_or_b_week_string = '(A Week)';
} else {
$today_a_or_b = $a_week_tid;
$next_week_a_or_b = $b_week_tid;
$a_or_b_week_string = '(B Week)';
}
} else {
$next_week_a_or_b = NULL;
$a_or_b_week_string = NULL;
}
This code is not commented or documented. The part that confuses me is:
Why is 4 subtracted from Julian, then divided by 7?
If today is Monday, $julian_week is 2129, and 2129 % 2 evaluates TRUE. Is that correct?
Is this even how it should be done? Can't I rewrite this using date('w') a lot easier?
Yeah using date would totally be easier, plus it takes into account leap years, daylight saving time, all that extra stuff you don't want to have to deal with.
if (date('W')%2==1)
That's SOOOO much easier to maintain than the above.
I don't believe you can use date("W") in this case. According to the ISO calculation, on occasion, there will be years with 53 weeks. In those years, Week 53 is followed by Week 01, both odd numbers, and an A/B calculation based on Even/Odd ISO week number would result in two successive A or B weeks.
The original calculation determines the number of days from the UNIX epoch of the present Monday, or of the most recent Monday if today is not a Monday. The -4 causes the A/B week labels to change on Thursdays. Even/oddness of a week is determined from a fixed date (the Unix Epoch), so there will be no discontinuity in the oscillation of A/B-ness using the original code.
The ISO standard for week one in a year is that it is the week that the first Thursday of the year falls. This is the reason for the 4 subtracted from the Julian date. The week number is then found by dividing by 7.
Again the ISO standard implies that week number cannot be greater than 53. I don't understand how your figure of 2129 can arise. However the div operator will not evaluate TRUE for this figure. Checking the div operator on the week number is the way of determining whether you are in week a or b. If it is before Thursday, it is quite likely that the number will be 1 less than you anticipate.
The coding looks fairly good to me, though I have not stepped through all of it. It does look correct.
Using W on consecutive Fridays, mod by 2. Both lines output 1. So doing it this way will occasionally fail.
echo date('W',strtotime('2016-01-01'))%2;
echo date('W',strtotime('2016-01-08'))%2;
Just a simple way.
<?php
$weekNumber = date("W");
echo 'Week number:',$weekNumber;
if($weekNumber&1) {
echo '<strong>Week A.</strong>';
} else {
echo '<strong>Week B.</strong>';
}
?>
$day = '2019-11-10';
$date = new DateTime($day);
$dayOfMonth = $date->format("j"); // month days 1 - 30
$weekNumber = ceil($dayOfMonth / 7); // get the week number
if ($weekNumber % 2 == 0) { //if week number is even
echo "Even Week";
} else {
echo "Odd Week";
}
**// output Even Week**

Categories