笔试题 — 美登(通过)

服务订购到期日

在真实的业务场景中,客户可以在任意一天订购我们的服务,订购周期可以是一个月、一个季度、半年或一年,在订购日后的这么多月的当天凌晨 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]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值