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

在Java开发中,使用Joda Time处理日期时间时,遇到特定日期转换异常,如1986-05-04等,导致报错或相差一小时。这与时区和夏令时有关。解决方案包括理解时区转换规则,并在转换时正确处理夏令时变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    日期操作的时候经常会在字符串、毫秒和日期对象间转换,而且很多人都使用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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值