First you have a serial number which was converted from a date, for example : 40988 would be March 21st 2012. How could I then return 21 knowing that the serial number is 40988 and by NOT using the date object? I also have 2 other functions that I can use : numberOfDaysYear(year) which returns the number of days for a specific year (365 or 366) and I also have numberOfDaysMonth(month, year) which returns the number of days for a specific month and a specific year (31, 30, 28 or 29). The year limit goes from 1900 all the way to 2199, so this is what I started with
`
//Count the number of 365 years and 366 years
var counterNormalYears = 0
var counterLeapYears = 0
for (let i = 1900; i <= 2199; i++) {
if (numberOfDaysYear(i) == 365) {
counterNormalYears += 1
}
else if (numberOfDaysYear(i) == 366) {
counterLeapYears += 1
}
}
` Moving on from here what kind of approach could I take to then find the days that the date has without using the date object?
I'd probably do it like
let day = 40988, year = 1899, month = 0;
while (day > 0) day -= numberOfDaysYear(++year);
day += numberOfDaysYear(year);
while (day > 0) day -= numberOfDaysMonth(++month, year);
day += numberOfDaysMonth(month, year);
To explain ...
year back to daysday by 2 - because of maths 🤣had an issue in the original code ... but this should work
I much prefer using Date though
d = new Date('1900-01-01');
d.setDate(40988 + 1); // because of maths 🤣
// done
You don't show the other functions so I've mocked them. A simple method is to count the days for each year since 1900 until there are fewer than 1 year's days left. Then count the days for each month until there are fewer than 1 month's days left. The remaining days are the day in the month.
The daysToDate function returns an array of [year, month, day] as numbers to make it more useful. If you just want the day, just get the last element. In the example, I've turned the values into a YYYY-MM-DD timestamp.
It does minimal validation of input, likely a bit more is required.
// Return true if year is a leap year
function isLeap(year) {
return !(year % 4 || !(year % 100) && year % 400);
}
// Return number of days in year
function daysInYear(year) {
return isLeap(year)? 366 : 365;
}
// Return number of days in month
// Month is calendar month number
function daysInMonth(year, month) {
if (month == 2 && isLeap(year)) {
return 29;
}
return [,31,28,31,30,31,30,31,31,30,31,30,31][month];
}
// Convert days since 1900 to [year, month, day]
// Month is calendar month number
// Assumes 1 Jan 1900 is 1
function daysToDate(days) {
// Ensure days is within range 1990-01-01 to 2199-12-31
if (days < 1 || days > 109573) {
return;
}
let daysCounted = 0;
let year = 1900;
// Loop over years until less than a year's worth
// of days left
while (daysInYear(year) < (days - daysCounted)) {
daysCounted += daysInYear(year);
++year;
}
let month = 1;
// Loop over month until less than a month's worth
// of days left
while (daysInMonth(year, month) < (days - daysCounted)) {
daysCounted += daysInMonth(year, month);
++month;
}
return [year, month, days - daysCounted];
}
[ 1, // 1 Jan 1900
365, // 31 Dec 1900
366, // 1 Jan 1901
730, // 31 Dec 1901
40988, // 21 Mar 2012
109573 // 31 Dec 2199
].forEach(days => console.log(
days + ': ' + daysToDate(days).map(n=>(n<10?'0':'')+n).join('-')
));