misiek Posted March 1, 2017 Share Posted March 1, 2017 Hello Freaks, Currently I have this: <div>Week: <input type="text" name="weekNo" id="weekNo" placeholder="<?php echo $weekNumber = date("W"); ?>"/> </div> Then on form submission, the week of the year number is part of WHERE statement in my query. In results I get all entries withing this week. Until now it has work great, but I have been requested to change it to calculate data not from Monday to Sunday, but from Wednesday to Tuesday. I have probably spent 4ish hours browsing through search engines but can't find a solution. Can anyone be so kind and help me with this, please? Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 1, 2017 Share Posted March 1, 2017 (edited) OK, how will the first week of the year be determined and how are you going to determine how many weeks there are in a year (hint: it is not always 52)? You can't simply "shift" the results of "W" to get the right answer (well depends on what your rules are I guess). The "W" format is for specifying the ISO-8601 week number. Here are the "rules" for determining the first and last week for that model First weekThe ISO 8601 definition for week 01 is the week with the Gregorian year's first Thursday in it. The following definitions based on properties of this week are mutually equivalent, since the ISO week starts with Monday: It is the first week with a majority (4 or more) of its days in January. Its first day is the Monday nearest to 1 January. It has 4 January in it. Hence the earliest possible first week extends from Monday 29 December (previous Gregorian year) to Sunday 4 January, the latest possible first week extends from Monday 4 January to Sunday 10 January. It has the year's first working day in it, if Saturdays, Sundays and 1 January are not working days. If 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in week 01. If 1 January is on a Friday, it is part of week 53 of the previous year; if on a Saturday, it is part of week 52 (or 53 if the previous Gregorian year was a leap year); if on a Sunday, it is part of week 52 of the previous year. Last week The last week of the ISO week-numbering year, i.e. the 52nd or 53rd one, is the week before week 01. This week’s properties are: It has the year's last Thursday in it. It is the last week with a majority (4 or more) of its days in December. Its middle day, Thursday, falls in the ending year. Its last day is the Sunday nearest to 31 December. It has 28 December in it. Hence the earliest possible last week extends from Monday 22 December to Sunday 28 December, the latest possible last week extends from Monday 28 December to Sunday 3 January (next gregorian year). If 31 December is on a Monday, Tuesday or Wednesday, it is in week 01 of the next year. If it is on a Thursday, it is in week 53 of the year just ending; if on a Friday it is in week 52 (or 53 if the year just ending is a leap year); if on a Saturday or Sunday, it is in week 52 of the year just ending. So, determine your rules for determining how you will decide the first and last week - THEN we can help write code for it. Edited March 1, 2017 by Psycho Quote Link to comment Share on other sites More sharing options...
requinix Posted March 1, 2017 Share Posted March 1, 2017 After four hours of searching, maybe it's time to try to solve the problem rather than continue trying to find somebody who has done it before. Assuming that "W" worked perfectly for you before (because it may do unexpected things at the beginning of the year) then, As documented, "W" starts on a Monday. That means Monday and Tuesday dates will be one week number ahead of where you want them to be. You could just -1 but that will cause problems for the first M/Tu of the year. - If today is a Monday or Tuesday, pick the day one week earlier, otherwise use today - Get the "W"eek number of that date if (date("N") <= 2) { // monday or tuesday $date = strtotime("-1 week"); } else { $date = time(); } echo date("W", $date); Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 1, 2017 Share Posted March 1, 2017 - If today is a Monday or Tuesday, pick the day one week earlier, otherwise use today - Get the "W"eek number of that date if (date("N") <= 2) { // monday or tuesday $date = strtotime("-1 week"); } else { $date = time(); } echo date("W", $date); I think that would cause scenarios where the "first week" of the year, will be mis-calculated. Take the following example where Jan 1 starts on a Friday Mon Tue Wed Thu Fri Sat Sun DEC 28 29 30 31 1 2 3 JAN 4 5 6 7 8 9 10 - First week For a standard ISO week, the first week of the year is the one beginning on Jan 4, because it has at least four days in the current year. Using the logic above, the 4th and 5th of January would be counted as the last week of the previous year. For a Wed - Tue week, the first week for that same year should begin on Dec 30th (of the prior year). Wed Thu Fri Sat Sun Mon Tue DEC 30 31 1 2 3 4 5 - First week JAN 6 7 8 9 10 1 Quote Link to comment Share on other sites More sharing options...
requinix Posted March 1, 2017 Share Posted March 1, 2017 Then it's more complicated. Can we get some clarification about exactly how week numbers are supposed to work? Is it ISO 8601 but using Wednesday as the start of the week, so week 1 is - First week with 4+ days in January - First week with the Monday Wednesday closest to Jan 1 - The one with Jan 4 in it - The one with the first working day, not counting Saturday or Sunday (weekends) or Jan 1 (New Year's Day) I suspect so, in which case you'd have to emulate the same logic. Not sure if there's an easy way that works for all days of the year, or else just do a condition on whether the day is December 29 - January 10 for the special logic and the -1 week stuff for the rest of the year. Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 1, 2017 Share Posted March 1, 2017 . . . or else just do a condition on whether the day is December 29 - January 10 for the special logic and the -1 week stuff for the rest of the year. Without determining the FIRST week of the year, you cannot know the logic for determining the "week" for any other dates in the year. I've already got a solution - except it doesn't handling the "remaining" days at the end of the year that should belong to week one. Should have a complete solution shortly. Quote Link to comment Share on other sites More sharing options...
misiek Posted March 1, 2017 Author Share Posted March 1, 2017 I think I could be acceptable to have an error in calculation just for one week as long as the rest of year would calculate properly. Today is Wednesday and 9th week of the year just started. I could go around the problem by giving users 2 fields with pick date and then query the range. But I would like to remain with just single entry of week number as it looks neat. Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 1, 2017 Share Posted March 1, 2017 (edited) This is ugly, but it works. I would likely go through and refactor make it more efficient. I'm sure it could be done in a simpler fashion, but I had to change direction multiple times. It works on the same logic as the ISO logic. For any weeks that span Dec/Jan, the week will belong to the prior year or the next year based on which year has the most days in that week (i.e. at least 4). Note; There is debugging code at the bottom that shows the results for the days at the end/beginning of each year to validate the results <?php function weekNo($dateTs) { //Create return variable and set initial 'year' value $result = array(); $result['year'] = date('Y', $dateTs); //Get Jan 1 for the provided timestamp and the DOW $janFirst = strtotime(date("1/1/Y", $dateTs)); $janFirstDow = date('N', $janFirst); //Determine first day of first week if($janFirstDow == 3) { //First day of first week is Jan 1 $firstDayOfFirstWeek = $janFirst; } elseif(in_array($janFirstDow, [3,4,5,6])) { //First day of first week is Wed prior to Jan 1 $firstDayOfFirstWeek = strtotime('last Wednesday', $janFirst); } else { //First day of first week is Wed following Jan 1 $firstDayOfFirstWeek = strtotime('next Wednesday', $janFirst); } //Calculate number of weeks since first day of first week $startDate = new DateTime(date('m/d/Y', $firstDayOfFirstWeek)); $currDate = new DateTime(date('m/d/Y', $dateTs)); $daysDiff = $currDate->diff($startDate)->format("%a"); //Calculate the Week NO $result['week'] = ceil( ($daysDiff+1) / 7); //Handle the first three days or last three days of the year //if they should fall in the adjoining year's first/last week //If selected date is Jan 1 - 3 if(date('m', $dateTs)==1 && date('j', $dateTs)<=3) { //If Jan 1st falls on Sun/Mon/Tue AND selected date is on Sun/Mon/Tue if(in_array($janFirstDow, [7,1,2]) && in_array(date('N', $dateTs), [7,1,2])) { //Get year/week no for the last week of prior year $result = weekNo(strtotime(date("m/d/Y", $dateTs).' -3 days')); //Increment year & set to week 1 } } //If selected date is Dec 29 - 31 if(date('m', $dateTs)==12 && date('d', $dateTs)>=29) { //If 12-31 falls on Wed/Thu/Fri AND selected date is on Wed/Thu/Fri if(in_array(date('N', strtotime(date('12/31/Y', $dateTs))), [3,4,5]) AND in_array(date('N', $dateTs), [3,4,5])) { //Increment year & set to week 1 $result['year']++; $result['week'] = 1; } } //Return result return $result; } //Debugging code echo "<pre>"; for($year=2005; $year<=2015; $year++) { $startDate = "12/15/{$year}"; $noOfDays = 30; echo "<h1>{$year}</h1>"; for($day=0; $day<$noOfDays; $day++) { $timeStamp = strtotime("{$startDate} + {$day} days"); //$isoWeek = date("W", $timeStamp); $weekNo = weekNo($timeStamp); $dow = date('N',$timeStamp); if( date('N',$timeStamp) == 3 ) { echo "<br>\n"; } echo "<b>" . date('D, m/d/Y', $timeStamp) . "</b> -- Year: {$weekNo['year']}, Week: {$weekNo['week']}\n"; } } echo "</pre>"; ?> Edited March 1, 2017 by Psycho Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.