移动端中踩过的关于日历&时间的坑

2,164 阅读5分钟

① 情景-在移动端日历中,选择日期并转成时间戳,在iOS端莫名失效

日历相信是大家都做过的小玩意,它有可能是HTML5自带的也可能是自己做的,同时取到的时间格式也是千奇百怪的。不废话了,我们直接上代码。

let a = Date.parse('2017-1-1');
console.log(a);
let b = Date.parse('2017-01-1');
console.log(b);
let c = Date.parse('2017-01-01');
console.log(c);

let a1 = Date.parse('2017/1/1');
console.log(a1);
let b1 = Date.parse('2017/01/1');
console.log(b1);
let c1 = Date.parse('2017/01/01');
console.log(c1);

这些都是我们常见的时间格式,无论是从后端取得还是我们前端转换而来的。那么大家知道每个console的结果是什么吗?

let a = Date.parse('2017-1-1');
console.log(a);
//chrome浏览器--1483200000000
//Android微信端(类Android内置浏览器)--1483200000000
//iOS微信端(类Safari浏览器)--NAN
let b = Date.parse('2017-01-1');
console.log(b);
//chrome浏览器--1483200000000
//Android微信端(类Android内置浏览器)--1483200000000
//iOS微信端(类Safari浏览器)--NAN
let c = Date.parse('2017-01-01');
console.log(c);
//chrome浏览器--1483228800000
//Android微信端(类Android内置浏览器)--1483228800000
//iOS微信端(类Safari浏览器)--1483228800000

let a1 = Date.parse('2017/1/1');
console.log(a1);
//chrome浏览器--1483200000000
//Android微信端(类Android内置浏览器)--1483200000000
//iOS微信端(类Safari浏览器)--1483200000000
let b1 = Date.parse('2017/01/1');
console.log(b1);
//chrome浏览器--1483200000000
//Android微信端(类Android内置浏览器)--1483200000000
//iOS微信端(类Safari浏览器)--1483200000000
let c1 = Date.parse('2017/01/01');
console.log(c1);
//chrome浏览器--1483200000000
//Android微信端(类Android内置浏览器)--1483200000000
//iOS微信端(类Safari浏览器)--1483200000000

惊不惊喜!神不神奇!iOS的浏览器是无法解析2017-1-1和2017-01-1(2017-1-01)这两类格式的日期。所以如果用童鞋们在写日历组件的时候发现安卓和iOS行为不一致的时候不妨看看日期格式那边是否存在问题。

总的来说,在移动端中使用'/'作为日期分割是最保险的,但是这一般与前端展示的期望不一,这时候就改取舍一下,是用多的代码量来提高项目容错率还是严格控制自己的日期格式...

②项目引入了"完美时间插件moment.js"但是它又粗又大...

也许有些童鞋还不太了解moment,可以点击传送门看看它的文档。

不得不说它的功能确实很强大,基本可以满足大部分项目对时间显示或转换的各种需求,它甚至还内置了语言包,只能说功能很强大并且用途很广泛,看看GitHub上的star就大概能感受到它的地位了。

它这么好用,用起来简单粗暴,又粗又大又有什么所谓呢?

其实不然,因为你没有在项目打包之后整体的分析项目bundle的占比。如果你是用webpack构建项目的话可以选择使用webpack-bundle-analyzer来分析一下你的包体结构,如果在项目中引入了moment,你会发现它真的很大...

无论是站在项目角度还是用户角度,个人认为都不应该草率的使用如此巨大的依赖包。并且,只要我们静下来仔细分析一下我们的项目,会发现,其实我们对日期时间方面的需求并没有想象中的那么繁杂。

下面我会贴一个自己正在使用的工具类--

//用法--TimeStream(1500614243, 'CN-YMD')
function TimeStream(timestamp, type) {
    let date = new Date(timestamp * 1000);
    let Y = date.getFullYear();
    let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1);
    let D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
    let h = date.getHours() < 10 ? '0' + date.getHours() : date.getHours();
    let m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes();
    let s = date.getSeconds();

    switch (type) {
        case 'YMD': //年-月-日
            return Y + '-' + M + '-' + D;
        case 'MD': //月-日
            return M + '-' + D;
        case 'MD_HM': //月-日
            return M + '-' + D + ' ' + h + ':' + m;
        case 'YMD_HMS': // 月-日 时:分:秒
            return Y + '-' + M + '-' + D + ' ' + h + ':' + m + ':' + s;
        case 'CN_YMD': //x年x月x日
            return Y + '年' + M + '月' + D + '日';
        case 'CN_YMD_HM': //x年x月x日
            return Y + '年' + M + '月' + D + '日' + ' ' + h + ':' + m;
        case 'hm': // 时:分
            return h + ':' + m;
        case '-D': //天数差
            return Math.floor(((timestamp * 1000) - Date.parse(new Date())) / 1000 / 3600 / 24);
        case '-H': //小时差
            return Math.ceil((timestamp * 1000 - Date.parse(new Date())) / 1000 / 3600);
        default: //年-月-日 时:分
            return Y + '-' + M + '-' + D + ' ' + h + ':' + m;
    }
}

这是我正在使用的自己写的有关时间的工具类,当然它与我们的项目是密切结合的(其实就我们的项目而言也只需要这几种类型的转换),并且它可以灵活的根据需求的变化而变化,用法也并不算很麻烦,只要稍作注释,任何同事都可以随心使用。

以上工具类肯定还有很多别的更优写法,我只是想借助这个解释一下为什么我不提倡盲目使用moment(可代入任何又粗又大的依赖),要知道,在这几十行代码诞生之前,我们用着的是一个Gzip过后还有几十K的依赖。