记得以前参加校招的时候,总是有日期相关的面试题,比如计算两个日期之间的间隔天数。以前还觉得这种题就是为了纯粹为了面试的,但工作了之后,还就碰到了跟日期相关的bug。下面是一段js代码,是要把字符串描述的日期转换为Date类型的函数。其中,字符串的格式为年占用4个字符,月份2个字符,天数2个字符,小时2个字符,分钟2个字符,秒数2个字符。

 function str2Date(str) {
var year = parseInt(str.substr(0, 4));
// Month value range is [0, 11]
var month = parseInt(str.substr(4, 2)) - 1;
var day = parseInt(str.substr(6, 2));
var hour = parseInt(str.substr(8, 2));
var minute = parseInt(str.substr(10, 2));
var second = parseInt(str.substr(12, 2)); var date = new Date();
date.setYear(year);
date.setMonth(month);
date.setDate(day);
date.setHours(hour);
date.setMinutes(minute);
date.setSeconds(second);
return date;
} console.log(str2Date('20150515180000').toString());
console.log(str2Date('20160229235959').toString());
console.log(str2Date('20171231235959').toString());
console.log(str2Date('20181101000000').toString());

今天的日期是2019年3月20日,以上代码的测试用例运行结果全部正常。输出结果如下

1
2
3
4
Fri May 15 2015 18:00:00 GMT+0800 (CST)
Mon Feb 29 2016 23:59:59 GMT+0800 (CST)
Sun Dec 31 2017 23:59:59 GMT+0800 (CST)
Thu Nov 01 2018 00:00:00 GMT+0800 (CST)

但是在某个特定日期(月末),就发现这段代码的运行结果出错了。原来,new Date()生成的值是运行时的时间,在不同的时间,运行的结果是不同的。下面来看一个特定日期的运行结果。把第10行代码中的new Date的初始化,设置日期为2019年3月31日。

var date = new Date('2019-03-31 00:00:00');

修改之后的运行结果如下,有两个用例的运行结果是不符合预期的。

1
2
3
4
Fri May 15 2015 18:00:00 GMT+0800 (CST)
Tue Mar 29 2016 23:59:59 GMT+0800 (CST)
Sun Dec 31 2017 23:59:59 GMT+0800 (CST)
Sat Dec 01 2018 00:00:00 GMT+0800 (CST)

那究竟是怎么回事呢?只能逐步调试来看下哪一步出了问题。因为是日期错了,我这里通过日志把改变日期值的中间过程都打印出来。下面以第2个用例(2016年2月29日)调试看下。

function str2Date(str) {
var year = parseInt(str.substr(0, 4));
// Month value range is [0, 11]
var month = parseInt(str.substr(4, 2)) - 1;
var day = parseInt(str.substr(6, 2));
var hour = parseInt(str.substr(8, 2));
var minute = parseInt(str.substr(10, 2));
var second = parseInt(str.substr(12, 2)); var date = new Date('2019-03-31 00:00:00');
date.setYear(year);
console.log(date.toString());
date.setMonth(month);
console.log(date.toString());
date.setDate(day);
console.log(date.toString());
date.setHours(hour);
date.setMinutes(minute);
date.setSeconds(second);
return date;
}

输出的结果如下:

1
2
3
4
Thu Mar 31 2016 00:00:00 GMT+0800 (CST)
Wed Mar 02 2016 00:00:00 GMT+0800 (CST)
Tue Mar 29 2016 00:00:00 GMT+0800 (CST)
Tue Mar 29 2016 23:59:59 GMT+0800 (CST)

从输出结果来看SetMonth这一步就出错了。原来在当前场景下,调用SetMonth设置的月份,会导致预期时间是一个不合法的时间,而Date类进行了自动的纠正,也就改变了月份的值。后面又重新设置了天数,是合法值,Date不再对日期进行改变,最终就导致月份是错误的。
通过查询MDN文档,发现setFullYear函数是可以把年月日都作为参数输入,这样就能保证日期的完整性,特殊日期也不会出错。修改后的代码如下:

function str2Date(str) {
var year = parseInt(str.substr(0, 4));
// Month value range is [0, 11]
var month = parseInt(str.substr(4, 2)) - 1;
var day = parseInt(str.substr(6, 2));
var hour = parseInt(str.substr(8, 2));
var minute = parseInt(str.substr(10, 2));
var second = parseInt(str.substr(12, 2)); var date = new Date('2019-03-31 00:00:00');
date.setFullYear(year, month, day);
date.setHours(hour, minute, second);
return date;
} console.log(str2Date('20150515180000').toString());
console.log(str2Date('20160229235959').toString());
console.log(str2Date('20171231235959').toString());
console.log(str2Date('20181101000000').toString());

通过这个例子说明,每个函数的异常处理都有可能导致最终的结果出错,如果使用了系统函数或者其他库的函数,都需要对每个函数的异常处理有足够的了解,才能保证结果符合预期。

关于作者

bingoli

原文地址:https://www.cnblogs.com/bingoli/p/10574465.html

JavaScript的Date类的函数特殊处理导致的问题的更多相关文章

  1. JavaScript Date对象和函数 (一)

    JavaScript_Date对象说明  Date中文为"日期"的意思,Date继承自Object对象,此对象提供操作,显示日期与时间的函数 Date对象构造函数 Date对象具有 ...

  2. 前端(十四)—— JavaScript常用类:Number、Date类、字符串、数组、Math类、正则

    JS常用类:Number类.Date类.Math类.字符串.数组.正则 一.Number 1.常用数字 整数:10 小数:3.14 科学计数法:1e5 | 1e-5 正负无穷:Infinity | - ...

  3. js之序列化、eval和Date类用法

    序列化 JSON.stringify() 将对象转换为字符串 JSON.parse() 将字符串转换为对象类型 示例 var jsonStr = '{"name":"le ...

  4. Javascript学习6 - 类、对象、继承

    原文:Javascript学习6 - 类.对象.继承 Javasciprt并不像C++一样支持真正的类,也不是用class关键字来定义类.Javascript定义类也是使用function关键字来完成 ...

  5. PHP类和函数注释大全

    每次要用PHP的某个功能的时候,都要去查一下,于是决定将PHP所有类和函数都整理出来,加上注释 大致实现 将php.jar文件解压,取出目录stubs 将stubs中的所有php文件中的注释去掉,并做 ...

  6. javascript常用工具类整理(copy)

    JavaScript常用工具类 类型 日期 数组 字符串 数字 网络请求 节点 存储 其他 1.类型 isString (o) { //是否字符串 return Object.prototype.to ...

  7. JavaScript权威指南--类和模块

    知识要点 每个javascript对象都是一个属性集合,相互之间没有任何联系.在javascript中也可以定义对象的类,让每个对象都共享某些属性,这种“共享”的特性是非常有用的.类的成员或实例都包含 ...

  8. 你可能不知道的 Date 类

    Date 是 JS 中的重要的一个内置对象,其实例主要用于处理时间和日期,其时间基于 1970-1-1 (世界标准时间)起的毫秒数,时间戳长度为 13 位(不同于 Unix 时间戳的长度 10 位). ...

  9. JavaScript 中对变量和函数声明的“提前”

    变量声明“被提前” JavaScript 的语法和 C .Java.C# 类似,统称为 C 类语法.有过 C 或 Java 编程经验的同学应该对“先声明.后使用”的规则很熟悉,如果使用未经声明的变量或 ...

随机推荐

  1. Tomcat-servlet基础

    1.1 概念 运行在服务器上的小程序   定义了浏览器访问到(tomact)的规则 1.2 步骤 1.3 执行原理 1  当服务器 接收到客户端浏览器的请求后  会解析url地址  获得url路径   ...

  2. eclipse配置Servlet连接Mysql要注意的几个地方

    用Servlet即把jdbc那套放到继承于HttpServlet的派生类之内,那段代码很简单 protected void doPost(HttpServletRequest request, Htt ...

  3. RESTful API格式 图片验证码接口

    之前公司写图片验证码时用的是session 后来写接口时也想用session存验证码  不过领导说RESTful API 写接口 没有session这一说 于是就用了redis 存验证码 还有就是接口 ...

  4. 数据库-1055报错-把only_full_group_by去掉

    [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated c ...

  5. Lozad.js 简单使用

    GayHub位置:https://github.com/ApoorvSaxena/lozad.js 导入: <script type="text/javascript" sr ...

  6. 微信小程序记账本进度一

    一,1.注册微信公众号 2.点击“立即注册”后,点击“”小程序“” 3.填写邮箱等信息.完成并激活.

  7. [leetcode]84. Largest Rectangle in Histogram直方图中的最大矩形

    Given n non-negative integers representing the histogram's bar height where the width of each bar is ...

  8. Head First Servlets & JSP 学习笔记 第十三章 —— 过滤器的威力

    过滤器可能是最强大的Web应用开发工具了! 与Servlet非常类似,过滤器就是Java组件,请求发送到Servlet之前,可以用过滤器截获和处理请求:另外Servlet结束工作之后,但在响应发回给客 ...

  9. Sonar+maven+jenkins集成,Java代码走查

    Sonar服务在Sonar安装与使用篇已经介绍过,此文章不再说了 Jenkins的安装与配置方法参考http://www.cnblogs.com/chenchen-tester/p/6408815.h ...

  10. org.hibernate.InvalidMappingException: Could not parse mapping document from resource com/domain/book.hbm.xml 联网跑一跑

    org.hibernate.InvalidMappingException: Could not parse mapping document from resource com/domain/boo ...