我发现Java中的Date类在1900-01-01 08:00:00之前的时间数据在使用SimpleDateFormat进行格式化与解析是出现了5分43秒的偏差。
1、发现过程
想用Java实现根据数据库表名称将Excel表格中的数据导入到该表中的功能,就类似于Navicat通过Excel导入数据的功能。
首先我用DBeaver将表数据导出为CSV文件,然后将文件另存为Excel格式,mysql中time类型的数据会被存储为时间格式(使用Navicat导出Excel的话会被存储为常规字符串)。
将Excel文件使用POI读取到Java代码中,对时间格式的时间进行解析读取,会将time类型的数据读取为Date,从而包含年月日时分秒的数据。
例如:数据库中存储的是 “00:00:00” ,读取格式化之后就会变为“1899-12-31 00:00:00”。
因为MySQL的time类型允许小时部分大于24(测试了下最大可以输入到838:59:59),如果直接取Date的时分秒部分显然是不对的,我的想法是 “用每次读取到的date的毫秒值-1899-12-31 00:00:00的毫秒值 = 实际的数据的毫秒值, 然后经过计算就能得到对应的时分秒。
按照上述想法计算完成进行测试时,发现部分比较的数据导入到数据库之后时间少了5分43秒,于是做了以下几个测试案例,发现确实有一部分数据有偏差。
2、测试案例
2.1案例一
利用格式化字符串解析为Date数据,获取Date的毫秒值,并将Date数据在格式化为字符串;
以下四个数据都是边界值:
当时间大于1900-01-01 08:05:42相互转换都一切正常;
当时间小于等于1900-01-01 08:05:42,大于等于1900-01-01 08:00:00 时,解析出的时间比字符串数据大343000毫秒,再次格式化正常,现象就是格式化比原始时间大了5分43秒。
当时间小于1900-01-01 08:00:00,解析出的时间毫秒值比字符串数据大了343000毫秒,但是再次格式化的字符串又与原始时间一致。
解析的时间毫秒值是否正确可以找任意的在线转换工具进行验证。
@Test
public void test1() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String teststr1 = "1900-01-01 08:05:43";
String teststr2 = "1900-01-01 08:05:42";
String teststr3 = "1900-01-01 08:00:00";
String teststr4 = "1900-01-01 07:59:59";
List<String> list = Arrays.asList(teststr1, teststr2, teststr3, teststr4);
for (String s : list) {
Date parse = sdf.parse(s);
String format = sdf.format(parse);
System.out.println("--------------------------");
System.out.println("原始时间: " + s);
System.out.println("时间戳: " + parse.getTime());
System.out.println("格式化时间:" + format);
}
}
执行结果:
2.2 案例二
在网上找时间戳在线转换工具,找出了五个时间的毫秒值,将这些毫秒值转为Date并进行格式化。
执行的结果发现:
当时间大于1900-01-01 08:05:42的时候一切正常;
当时间小于等于1900-01-01 08:05:42的时候,格式化出的时间字符串始终小5分43秒。
将毫秒值转为Date的时候Date所表示的值已经变小了。
@Test
public void test2() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long time0 = 567993942000l; // 1988-01-01 08:05:42
long time1 = -2208988800000l; // 1900-01-01 08:05:43
long time2 = -2208988801000l; // 1900-01-01 08:05:42
long time3 = -2208989143000l; // 1900-01-01 08:00:00
long time4 = -2208989144000l; // 1900-01-01 07:59:59
long time5 = -2240553943000l; // 1899-01-01 00:00:00
List<Long> longs = Arrays.asList(time0, time1, time2, time3, time4, time5);
for (Long aLong : longs) {
Date date = new Date(aLong);
System.out.println("--------------------------");
System.out.println("原始时间戳: " + aLong);
String format = sdf.format(date);
System.out.println("格式化时间:" + format);
}
}
执行结果:
3、总结
以上是发现的问题以及案例描述,我不太清楚为什么会出现这样的现象,只是碰巧遇到了这个问题,希望看到的大佬能够解答一下出现这个现象的原因,感谢!