Java小记 —— 日期时间转换问题(相差一小时)

    日期操作的时候经常会在字符串、毫秒和日期对象间转换,而且很多人都使用joda time库进行操作,这就会遇到以下说的问题(相信很多人也遇到了):就是对于某些特殊的日期,转换的时候会报错,或者出现转换不准确(相差一小时)的问题。

    1,字符串转日期,转long

    首先,我们先将日期字符串转为日期,再打印出long值,以‘1986-05-04’为例:

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
System.out.println(formatter.parseDateTime("1986-05-04").getMillis());

    这时就会出现下面的异常:org.joda.time.IllegalInstantException: Cannot parse “1986-05-04”: Illegal instant due to time zone offset transition (Asia/Shanghai)

    对于一般的日期字符串这样写并不会报错,这种引起报错的特殊日期还不止一个,比如:1988-04-10,1989-04-16,1990-04-15,1991-04-14等。这其实是时区相关的错误,是夏令时引起的,详情参考http://www.bubuko.com/infodetail-997580.html

    解决办法:

//1.指定使用UTC时区,但是需要考虑时差
System.out.println(formatter.withZone(DateTimeZone.UTC).parseDateTime(date).getMillis());
System.out.println(formatter.withZone(DateTimeZone.UTC).parseDateTime(date).getMillis()-8*60*60*1000);
//2.转为Local时间
System.out.println(formatter.parseLocalDate(date).toDateTimeAtStartOfDay().getMillis());
System.out.println(formatter.parseLocalDateTime(date).toDate().getTime());
//可以转为LocalDate或者Date,但是不能转为LocalDateTime,否则还是会报错
System.out.println(formatter.parseLocalDateTime(date).toDateTime().getMillis());//会报错

    或者,直接使用java.util.Date是不会出现上边的问题的:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(sdf.parse("1986-05-04").getTime());//可以正常打印

    使用jdk8增加的time包,也可以,也是需要指定时区的:

DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
System.out.println(LocalDate.parse("1986-05-04", df).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());

    2,long转日期,转字符串

    接着上边的说,将’1986-05-04’转为long后的结果是515520000000(时区Asia/Shanghai),现在我们再逆向转回去:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date(l))); //打印结果:1986-05-04 01:00:00

    打印结果发现问题来了,时间部门变成了01:00:00,多了一个小时(有的日期可能是少一个小时,都是夏令时的原因),使用joda time也是一样:

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(new DateTime(l).toString(formatter)); //打印结果:1986-05-04 01:00:00

    解决办法:

//还是要借助时区转换,注意补齐时差
System.out.println(new DateTime(l+8*60*60*1000).withZone(DateTimeZone.UTC).toString(formatter));//打印结果:1986-05-04 00:00:00
System.out.println(new DateTime(l+DateTimeZone.getDefault().getOffsetFromLocal(l)).withZone(DateTimeZone.UTC).toString(formatter));//打印结果:1986-05-04 00:00:00

    原文作者:冥加
    原文地址: https://blog.csdn.net/mingjia1987/article/details/80679920
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞