如何将最初为日期的序列号转换为日期最初具有但不使用日期对象的天数?
How to convert a serial number that was initially a date to the number of days that the date initially had but without using the date object?
首先,您有一个从日期转换而来的序列号,例如:40988 表示 2012 年 3 月 21 日。
那么我怎么能 return 21 知道序列号是 40988 并且 NOT 使用日期对象呢?我还有 2 个可以使用的其他函数:numberOfDaysYear(year) returns 特定年份(365 或 366)的天数,我还有 numberOfDaysMonth(month, year) returns 特定月份和特定年份的天数(31、30、28 或 29)。年份限制从 1900 一直到 2199,所以这就是我开始的
`
//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
}
}
`
从这里继续,我可以采取什么样的方法来找到日期的天数而不使用日期对象?
我可能会这样做
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);
解释...
- 从 1899 开始,因为显而易见的原因我使用 pre-increment
- 首先发生的事情是从天数中减去 1970 年的天数(使用您的函数)...因为我使用 pre-increment,1970 年在第一个循环中传入
- 因为我们已经低于零,所以将上次使用的最后天数
year
加回到 days
- 月份的类似算法 - 从天数中减去直到小于零
- 与步骤 3 中类似的月份回溯
- 您可能需要将
day
调整 2 - 因为数学原因
原始代码中存在问题...但这应该有效
虽然我更喜欢使用 Date
d = new Date('1900-01-01');
d.setDate(40988 + 1); // because of maths
// done
其他功能你没有展示,所以我嘲笑了他们。一个简单的方法是计算从1900年开始每一年的天数,直到剩下不到一年的天数。然后计算每个月的天数,直到剩下不到 1 个月的天数。其余天数为当月的第几天。
daysToDate 函数 returns 一个 [year, month, day] 的数组作为数字,使其更有用。如果你只想要一天,就得到最后一个元素。在示例中,我已将值转换为 YYYY-MM-DD 时间戳。
它对输入进行最少的验证,可能需要更多验证。
// 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('-')
));
首先,您有一个从日期转换而来的序列号,例如:40988 表示 2012 年 3 月 21 日。 那么我怎么能 return 21 知道序列号是 40988 并且 NOT 使用日期对象呢?我还有 2 个可以使用的其他函数:numberOfDaysYear(year) returns 特定年份(365 或 366)的天数,我还有 numberOfDaysMonth(month, year) returns 特定月份和特定年份的天数(31、30、28 或 29)。年份限制从 1900 一直到 2199,所以这就是我开始的
`
//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
}
}
` 从这里继续,我可以采取什么样的方法来找到日期的天数而不使用日期对象?
我可能会这样做
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);
解释...
- 从 1899 开始,因为显而易见的原因我使用 pre-increment
- 首先发生的事情是从天数中减去 1970 年的天数(使用您的函数)...因为我使用 pre-increment,1970 年在第一个循环中传入
- 因为我们已经低于零,所以将上次使用的最后天数
year
加回到days
- 月份的类似算法 - 从天数中减去直到小于零
- 与步骤 3 中类似的月份回溯
- 您可能需要将
day
调整 2 - 因为数学原因
原始代码中存在问题...但这应该有效
虽然我更喜欢使用 Date
d = new Date('1900-01-01');
d.setDate(40988 + 1); // because of maths
// done
其他功能你没有展示,所以我嘲笑了他们。一个简单的方法是计算从1900年开始每一年的天数,直到剩下不到一年的天数。然后计算每个月的天数,直到剩下不到 1 个月的天数。其余天数为当月的第几天。
daysToDate 函数 returns 一个 [year, month, day] 的数组作为数字,使其更有用。如果你只想要一天,就得到最后一个元素。在示例中,我已将值转换为 YYYY-MM-DD 时间戳。
它对输入进行最少的验证,可能需要更多验证。
// 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('-')
));