Determine if a week is odd or even - php

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**

Related

Find the Christian Liturgical Year - Return a letter A, B, or C for any Year

In the Christian liturgical year, Advent starts things off four weeks before Christmas, and there are three cycles (Year A, B, and C).
In PHP, what would be the most efficient and elegant method to determine what cycle we would be in for any given year.
Here are the rules:
The beginning of the cycle occurs on whatever Sunday falls on or closest to Nov. 30
November 30, 2016 was the beginning of year A.
There are three iterations, being year A, year B, and year C, after which we return to year A.
So if given any year month and day, would it be possible to determine whether that date was in the cycle A, B, or C?
UPDATE: What I've tried
I'm not very good with math, so haven't had much luck in figuring this out.
I've been focusing first on the year and how it relates to A B and C.
So if I equate A to 1 and B to 2 and C to 3, I could get the first three years by subtracting 2015 from the current date - but I don't know what to do after 2018.
To calculate the year, I think this would work:
$year = date('Y');
$year_A = strtotime(date('Y', strtotime('-1 year', strtotime($year))));
if($year % 3 == 0) {
$liturgical_year = "C" ;
} else if ($year_A % 3 == 0) {
$liturgical_year = "A" ;
} else {
$liturgical_year = "B" ;
}
echo $liturgical_year;
Also, to calculate the first date of the Liturgical year you can use St Andrew's feast day and find the closest Sunday:
$St_Andrew = date("Y") . "-11-30";
$St_Andrew = date($St_Andrew);
$last_Sunday = date('Y-m-d', strtotime('last Sunday', strtotime($St_Andrew)));
$next_Sunday = date('Y-m-d', strtotime('next Sunday', strtotime($St_Andrew)));
$days_delta = abs(strtotime($St_Andrew) - strtotime($last_Sunday))/(60 * 60 * 24);
if ($days_delta <= 3) {
$advent = $last_Sunday;
} else {
$advent = $next_Sunday;
}
Thanks to #Qirel for pointing me in the right direction. I've never really used the modulus operator before!
So problem is solved as follows (though my coding might be sloppy / inefficient):
$cycle = array(1=>"A",2=>"B",3=>"C");
for($year=2016;$year<2120;$year++){
$date = strtotime("Nov 30, " . $year);
echo "Sunday closest to " . date("Y-m-d",$date) . " is ";
$date = new DateTime($year . "/11/30 -4 days");
$date->modify("next Sunday");
echo $date->format("Y-d-m");
echo " where we start Year " . $cycle[(($year % 3) + 1)] . "<br/>";
}
Here's what's going on:
$cycle is defined as an array, where numbers 1, 2, and 3 are associated with years A, B, and C.
I then start a for loop to work through the years 2016 to 2120, incrementing the years by 1 on each iteration.
I then create a date of XXXX Nov 30 minus 4 days, where XXXX is the year we're iterating through. The minus four days helps us to be sure we're considering the date closest to the 30th, so that when we modify it in the following line to "next Sunday" it will always be the one closest to the 30th.
We then use the array $cycle, divide the year by 3 and take the remainder (using the modulus operator) which gives us either 0, 1, or 2 as an answer. I add one to it so it's returning 1, 2, or 3.
That isn't really necessary if I assign 0=>A, 1=>B, and 2=>C but...
I wrote a function to return this information:
function returnLiturgicalYear($year){
$cycle = array(0=>"A",1=>"B",2=>"C");
$date = new DateTime($year . "/11/30 -4 days");
$date->modify("next Sunday");
return $cycle[($year % 3)];
}
Hopefully this helps someone else trying to determine the Christian liturgical year for any date.

PHP is date between 2 other dates - Ignoring month

I am trying to determine if a day and time are between two others, I have the following...
$currentdate = date("N h:i:s A");
This returns the day of the week as a number and then the current time in 24 hour format.
I want to check if the $currentdate is between 9am on a Friday and 9am on a Monday.
What is the best way to tackle this?
I believe this should give you what your asking for but I'm sure there are better ways to implement. So basically the time has been converted into an INT for comparing and the hours are configured not to have a leading zero hence why $timeOne and $timeTwo is shorter. I've then used an if statement to test days and time on that specific day leaving you a slot to add your code if those conditions are met.
function checkDayTime() {
$day = date(w); //0 (for Sunday) through to 6 (for Saturday)
$timeOne = 90000;
$timeTwo = 90000;//Added for easier reading
$currentTime = (int) date('Gis'); //Time as INT 00000 > 240000
if (($day == 5 && $currentTime > $timeOne) || ($day == 6 || $day == 0) || ($day == 1 && $currentTime < $timeTwo)) {
//Between those hours
return TRUE;
} else {
//Not between those hours
return FALSE;
}
}
Just removed the extra if statement as it was not needed

Bi-weekly rotation of three options, rolling on a Friday at Midday

I need to rotate 3 options based on the current week number; ie:
if($weekNumber == 42 || $weekNumber == 43){
$thisID = 1;
}
else if($weekNumber == 44 || $weekNumber == 45){
$thisID = 3;
}
else if($weekNumber == 46 || $weekNumber == 47){
$thisID = 2;
}
else if($weekNumber == 48 || $weekNumber == 49){
$thisID = 1;
}
I'd obviously prefer this to be less manual! I've considered placing the 3 ID's in an array and selecting based on the number of weeks that have passed since date X but I'm not sure how to implement that.
And additionally... the rollover needs to be at Midday on a Friday. I considered simply incrementing the week number in the above plan too, with additional adjustments for when we're rolling from week 52 to week 1, but there must be a more sensible approach!
Thanks
Why don't you take the rounded half of the week number? Then you only need a catalog holding 26 IDs and you can implement a direct lookup:
$catalog=[1,2,3,4,5,6,3,4,2,5,6,7,4,4,7,9,5,8,8,9,2,4,5,7,6,8,9];
$thisID = $catalog[floor($weekNumber/2)];
This should work:
$options = array(1,2,3);
$offset = 129600;
$twoWeeks = 1209600;
$idx = floor((time()-$offset)/$twoWeeks) % count($options);
$chosenOption = $options[$idx];
Some explanation:
0 Unix time was a Thursday at midnight, so the first Friday at midday was 129600 seconds later.
With time()-$offset we shift the time to set Friday at midday as the zero point of our time calculation.
Now as Friday at midday is the zero point, we can count the number of full two weeks from the first Friday at midday by simply dividing the passed seconds by 1209600.

(PHP) Display link ONLY during business hours?

I am trying to make a live chat link appear on the website only during business hours. I have the code below which seems to work in the afternoon, but won't work in the morning and I'm not sure why... $start and $end are values received from a MySQL database but in my example I've hard coded them to make the example simpler.
$LinkStatus = "on";
$start = 9:00:00;
$end = 23:00:00;
$current_time = date('G:i:s'); //9:35:00
if (($start > $current_time) || ($end < $current_time)) {
$LinkStatus = "off";
}
If the start time is greater than the current time, then the business is not open yet. If the end time is less than the current time, then it's after hours. Any time between 9am and 11pm (23:00) neither one of those conditions should be true, therefore $LinkStatus should remain "on". However, it does not seem to be doing that right now. Something is setting it to "off".
I've echoed the variable above the if statement and below it so I can confirm it's this if statement causing the variable to be set to "off".
As you can probably see from my code example, I'm not very knowledgeable when it comes to PHP. Any help is appreciated.
date('G:i:s') // 24 hours time without leading zero for hour
...won't sort well as a string, for example '9' > '10'.
Use 24 hour time with a leading zero instead, which makes the correct sort '09' < '10';
date('H:i:s') // 24 hour time with leading zero for hour
date_default_timezone_set('Europe/London');
$day_start = '09:00:00';
$day_end = '16:59:59';
$current_time = date('H:i:s'); // For 9-5 hours only
$current_day = date('N'); // For Monday to Friday only
if (($current_day <= 5) && ($current_time >= $day_start) && ($current_time <= $day_end)) {
echo 'ON';
} else {
echo 'OFF'
}

How do I get next occurrence of a certain day of the month

I am trying to get stripe to set a end_trial date on the next occurrence of whatever day of the month the user chooses. i.e. If today is the 16th and the user chooses the 15th I need the unix timestamp for the 15th of the next month. However if today was the 14th I need the timestamp for tomorrow.
I tried the solution found on this SO question Find the date for next 15th using php .
When i ran the code suggested in that question and substituted 15 for 31
$nextnth = mktime(0, 0, 0, date('n') + (date('j') >= 31), 31);
echo date('Y-m-d', $nextnth);
The result is 2013-03-03
I also tried this one Get the date of the next occurrence of the 18th .
The second one would actually give me 2013-03-31 when i ran it one 2013-1-31.
Both had unexpected results. Is february the problem? Any guidance will be much appreciated.
Here is a way to do it.
function nextDate($userDay){
$today = date('d'); // today
$target = date('Y-m-'.$userDay); // target day
if($today <= $userDay){
$return = strtotime($target);
}
else{
$thisMonth = date('m') + 1;
$thisYear = date('Y');
if($userDay >= 28 && $thisMonth == 2){
$userDay = 28;
}
while(!checkdate($thisMonth,$userDay,$thisYear)){
$thisMonth++;
if($thisMonth == 13){
$thisMonth = 1;
$thisYear++;
}
}
$return = strtotime($thisYear.'-'.$thisMonth.'-'.$userDay);
}
return $return;
}
// usage
echo date('Y-m-d',nextDate(29));
We get the user's choice and compare it today.
If today is less than or equal to user choice, we return the timestamp for this month.
If today is greater than user choice, we loop through dates, adding a month (or a year if it's $thisMonth hits 13). Once this date does exist again, we have our answer.
We check the dates using php's checkdate function, strtotime and date.
I really don't understand the question completely. You can easily determine the date for next 30 days for example
$next_ts = time() + 30 * 86400; // add 30 days to current timestamp
$next = date('Y-m-d', $next_ts); // format string as Y-m-d
echo $next;
If that is not what you need, please explain the problem.

Categories