I think these are the correct conditions:
- Week 1 is the first week with at least 4 days of the new year.
- Week 53 happens when the new years' first day is a Thursday OR it's a leapyear and the year' first day is a Wednesday.
Examples:
Year (Input) | First day of first week (return wanted) |
---|---|
2020 (Leap Year) | 30/12/2020 |
2021 | 04/01/2021 |
2022 | 03/01/2022 |
2023 | 02/01/2023 |
2024 (Leap Year) | 01/01/2024 |
2025 | 30/12/2025 |
2026 (Starts on a wednesday, in a year of 53 weeks) | 29/12/2026 |
The year 2026 is a rare case, which happens in year 2032, 2037, 2043...
I believe I've 'solved' half the problem here:
let numOfWeeks = 52;
if (((0 == year % 4 && 0 != year % 100) || 0 == year % 400) && 'first day of first week is a wednesday') {
numOfWeeks = 53;
} else if ('first day of first week is a thursday') {
numOfWeeks = 53
}
But I can't for the life of me figure out how to get the first day of the first week in a given year.
CodePudding user response:
so I have two solutions to offer 1 quite simple (making use of the Date object - basically doing what barrycarter suggested in a comment)
Creating a Date object for the first of our desired year ... and then based on which day of the week that is, adjusting the date to end up with the first monday of the first week of the year
As you might notice when running the code. The answers are off by (mostly 1 hour) - I don't know why, and so far I only encountered this when running my code on here - in VS Code and several Online JS Playgrounds the code returned exactly what I intended it to return. So yeah there's that.
(date.getDay() 6) % 7 // 0 - 6 for Mon - Sun
function getDateOfFirstDayOfFirstWeek(year) {
const date = new Date(year, 0, 1)
if ((date.getDay() 6) % 7 === 0) return date
if ((date.getDay() 6) % 7 < 4) {
date.setDate(date.getDate() - (date.getDay() 6) % 7)
return date
} else {
date.setDate(8 - (date.getDay() 6) % 7)
return date
}
}
console.log(getDateOfFirstDayOfFirstWeek(2020))
console.log(getDateOfFirstDayOfFirstWeek(2021))
console.log(getDateOfFirstDayOfFirstWeek(2022))
console.log(getDateOfFirstDayOfFirstWeek(2100))
console.log(getDateOfFirstDayOfFirstWeek(3567))
console.log(getDateOfFirstDayOfFirstWeek(2002))
console.log(getDateOfFirstDayOfFirstWeek(1845))
the 2nd option is a tad more complicated (and I mostly wrote it just for fun - but I'll share it nonetheless maybe there's something you can take away from it)
Since I did not once use the Date object the missing hour problem does not happen here. (I want to say again I've only encountered the missing hour on stackoverflow so far - so you should be fine using the above function)
When we look at neighboring years we can see, that the date changes by 1 per year (and 2 if the year is a leap year) - so what we do is ... starting at an arbitrary point (I have chosen the year 2020 with the 30th of Dec being the Monday) we calculate the next/previous year (by adding/subtracting 1 or 2 from our date) ... we do that so long until we reach our desired year ...
until the very end (where we convert everything into day/month/year) we store our date in a value x (which can become any integer)
x % 7 = 0 -> 29/12
x % 7 = 1 -> 30/12
x % 7 = 2 -> 31/12
x % 7 = 3 -> 01/01
x % 7 = 4 -> 02/01
x % 7 = 5 -> 03/01
x % 7 = 6 -> 04/01
This thing here is to add a proper modulo method ... because % in Javascript only returns the remainder not modulo (which matters when using negative values) see this answer for more information on that: https://stackoverflow.com/a/4467559/19529102 (that's also where I got this little bit of code from)
Number.prototype.mod = function (n) {
"use strict";
return ((this % n) n) % n;};
Number.prototype.mod = function (n) {
"use strict";
return ((this % n) n) % n;
};
function isLeapYear(year) {
if (year % 4 !== 0) return false;
if (year % 100 !== 0) return true;
if (year % 400 !== 0) return false;
return true
}
function getFirstDayForNplus1(year, value) {
if (isLeapYear(year)) return [year 1, value - 2]
return [year 1, value - 1]
}
function getFirstDayForNminus1(year, value) {
if (isLeapYear(year - 1)) return [year - 1, value 2]
return [year - 1, value 1]
}
function getDateOfFirstDayOfFirstWeek(year) {
if (year < 1583) return
let baseLine = [2020, 1]
if (year > baseLine[0]) {
while (baseLine[0] !== year) {
baseLine = getFirstDayForNplus1(...baseLine);
}
} else {
while (baseLine[0] !== year) {
baseLine = getFirstDayForNminus1(...baseLine);
}
}
const month = baseLine[1].mod(7) < 2 ? 12 : 1;
const day = (baseLine[1].mod(7) 29) % 31 || 1
const retYear = month === 12 ? baseLine[0] - 1 : baseLine[0]
return day "/" month "/" retYear
}
console.log(getDateOfFirstDayOfFirstWeek(2020))
console.log(getDateOfFirstDayOfFirstWeek(2021))
console.log(getDateOfFirstDayOfFirstWeek(2022))
console.log(getDateOfFirstDayOfFirstWeek(2100))
console.log(getDateOfFirstDayOfFirstWeek(3567))
console.log(getDateOfFirstDayOfFirstWeek(2002))
console.log(getDateOfFirstDayOfFirstWeek(1845))
since you have a year, month, day variable in the function, you could easily create a Date object using that function (if needed)