服务订购到期日
在真实的业务场景中,客户可以在任意一天订购我们的服务,订购周期可以是一个月、一个季度、半年或一年,在订购日后的这么多月的当天凌晨 0 点订单到期。
以下举例说明订购的过期计算方式:
-
在 2018-11-10 订购一个月,订购将在 2018-12-10 过期
-
在 2018-12-10 订购一个月,订购将在 2019-01-10 过期
-
在 2019-01-30 订购一个月,订购将在 2019-02-28 过期
-
在 2019-04-30 订购一个月,订购将在 2019-05-30 过期
-
在 2019-05-31 订购三个月,订购将在 2019-08-31 过期
问题1(无需编程)
假定我们每天可以收到 4 个订单,其中一个是一个月周期的,一个是一个季度周期的,一个是半年周期的,一个是一年周期的。这样的订单从很久以前,比如五年前就开始了。
请通过分析回答:在哪一天到期的订单会最多,有多少个?具体是哪几个订单?
并对分析过程进行解释。
问题解答
假设五年前开始,我们每一天收到 月、季、半年、一年周期的订单各一个。
那么当这个假设开始一年后,在对称日期(每月都存在的日期(除28号以外),如1号,2号)时每天都会有 一个月周期、一个季度周期、一个半年周期、一个一年周期,4个订单到期。
除了对称日期外,因为每个月天数不同,当订购月份是大月份到期月份是小月份时,到期的订单会存在月末叠加。
如,8月有31天,9月有30天。9月月末30号就会有两个月订单到期,8月30日、8月31日。(其他周期订单不计)
在非对称日期中,最不对称的就是2月28日(2月天数最少),对该日期着重分析:
-
月订单:回退到1月,1月有31天,则在2月28日有4个月订单到期(1月28日、1月29日、1月30日、1月31日)。
-
季订单:回退到去年11月,11月有30天,则在2月28日有3个季订单到期(11月28日、11月29日、11月30日)。
-
半年订单:回退到去年8月,8月有31天,则在2月28日有4个半年订单到期(8月28日、8月29日、8月30日、8月31日)。
-
年订单:回退到去年2月,有两种情况:
-
平年过度到平年时,2月有28天,在2月28日会有1个年订单到期(2月28日)。
-
闰年过度到平年时,2月有29天,在2月28日会有2个年订单到期(2月28日、2月29日)。
-
在这五年中,只有2020年到2021年是闰年过度到平年,则在 2021年2月28日 到期的订单会最多,有 13个。具体哪些订单到期如上分析:
-
月订单:2021年1月28日、2021年1月29日、2021年1月30日、2021年1月31日。
-
季订单:2020年11月28日、2020年11月29日、2020年11月30日。
-
半年订单:2020年8月28日、2020年8月29日、2020年8月30日、2020年8月31日。
-
年订单:2020年2月28日、2020年2月29日。
问题2
请实现一个方法,给定订购的年月日 (year, month, day),已知订购时长是一个月,请返回订单的到期日。year, month, day 均为整数,输入已保证是正确的日期。
在考虑我们的喜好(Python == Javascript > Java > C/C++)的基础上,选择你最擅长的语言,给出 「可在生产环境中放心使用」 级别的代码。
Python 请实现以下方法:
def getExpirationDate(year, month, day):
# TODO
return [year, month, day]
Javascript 请实现以下方法:
function getExpirationDate(year, month, day) {
// TODO
return [year, month, day];
}
其余语言请参考上述语言入参和返回值进行实现。
主体代码避免使用日期相关的系统库/第三方库。
-
Python 应避免使用
datetime及同类库。 -
Javascript 应避免使用
Date对象。
测试代码部分无限制。需要包括至少 3 个测试数据。
简要解释解决思考过程和代码实现思路。
问题解答
需求:已知订购时长是一个月,给定订购的日期,在 Javascript 中不使用 Date 对象的前提下获取订单的到期日。
代码实现思路:
-
讨论不同情况:
-
通常情况:年(year)、日(day )不变,月份(month)加 1。
-
特殊情况:
-
1、订购日期是 12 月份,需要年份加 1,月份变为 1月。
-
2、订单到期日是 2 月份且日(day )大于 28,则将 day 改为 28(平年)或 29(闰年)。
-
通过年份可以判断该年份是否为闰年。
-
-
3、在 2 处理之后,订购日期是大月的31号且订单到期日是小月,则将 day 改为 30。
-
-
代码实现
/**
* @description: 判断年份是否为闰年
* @param {Number} year 年份
* @return {Boolean}
*/
function isLeapYear(year) {
if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
return true;
} else {
return false;
}
}
// 每月有 31 天的大月月份
const bigMonths = [1, 3, 5, 7, 8, 10, 12];
function getExpirationDate(year, month, day) {
// TODO
if(month < 12) {
month = month + 1;
} else {
year = year + 1;
month = 1;
}
if(month === 2 && day > 28) {
if(isLeapYear(year)) {
day = 29;
} else {
day = 28;
}
}
if(day === 31 && !bigMonths.includes(month)) {
day = 30;
}
return [year, month, day];
}
// 代码测试
console.log("订购:2020年1月31日 --> 到期:", getExpirationDate(2020, 1, 31));
console.log("订购:2021年5月6日 --> 到期:", getExpirationDate(2021, 5, 6));
console.log("订购:2021年4月5日 --> 到期:", getExpirationDate(2021, 4, 5));
// 打印结果
// 2020年1月31日 --> 到期:[2020, 2, 29]
// 2021年5月6日 --> 到期:[2021, 6, 6]
// 2021年4月5日 --> 到期:[2021, 5, 5]
2606

被折叠的 条评论
为什么被折叠?



