使用apache.commons.lang3.time.DateUtils.parseDate解析日期时出现时区相关的时间偏差问题
使用apache.commons.lang3.time.DateUtils.parseDate解析日期时出现时区相关的时间偏差问题
嘿,我来帮你拆解下这个问题的核心原因和解决办法~
问题根源:CST时区标识的歧义性
你碰到的时间偏差本质是Date.toString()输出的CST时区缩写不是唯一的:
- 你所在的中国标准时间(China Standard Time)是
GMT+8 - 但
CST同时也代表美国中部标准时间(Central Standard Time,GMT-6)、澳大利亚中部标准时间(GMT+9:30)等
当DateUtils.parseDate解析这个字符串时,它默认把CST识别成了美国中部标准时间(GMT-6)。这样一来:
原字符串的Wed Jan 10 00:00:00 CST 2024(美国中部时间)转换为中国标准时间(GMT+8)时,需要加上8 - (-6) = 14小时,最终就变成了你看到的Wed Jan 10 14:00:00 CST 2024。
解决方案
方案1:避免用Date.toString()作为解析输入(推荐)
Date.toString()的输出格式本身就不适合用于日期解析,因为时区标识有歧义。如果一定要做字符串转换,建议用SimpleDateFormat明确指定时区和格式:
import java.util.Date; import java.util.Calendar; import java.text.SimpleDateFormat; import java.util.TimeZone; public class ClassTest { private static final String PATTERN = "EEE MMM dd HH:mm:ss zzz yyyy"; // 明确指定中国时区 private static final TimeZone CHINA_TZ = TimeZone.getTimeZone("GMT+8"); public void methodTest() throws Exception { Calendar calendar = Calendar.getInstance(); calendar.set(2024, Calendar.JANUARY, 10, 0, 0, 0); Date date = calendar.getTime(); System.out.println(date); // Wed Jan 10 00:00:00 CST 2024 // 用指定时区格式化日期为字符串 SimpleDateFormat sdf = new SimpleDateFormat(PATTERN); sdf.setTimeZone(CHINA_TZ); String dateStr = sdf.format(date); // 解析时同样指定时区 Date date2 = org.apache.commons.lang3.time.DateUtils.parseDate(dateStr, CHINA_TZ, PATTERN); System.out.println(date2); // Wed Jan 10 00:00:00 CST 2024 } public static void main(String[] args) { ClassTest ct = new ClassTest(); try { ct.methodTest(); } catch (Exception e) { e.printStackTrace(); } } }
方案2:改用Java 8+的日期时间API(更推荐)
Java 8引入的java.time包(比如ZonedDateTime、DateTimeFormatter)专门解决了旧Date/Calendar的时区、格式化缺陷,用法更清晰:
import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; public class ClassTest { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"); // 明确指定中国时区 private static final ZoneId CHINA_ZONE = ZoneId.of("Asia/Shanghai"); public void methodTest() { ZonedDateTime date = ZonedDateTime.of(2024, 1, 10, 0, 0, 0, 0, CHINA_ZONE); System.out.println(date); // 2024-01-10T00:00+08:00[Asia/Shanghai] // 格式化字符串 String dateStr = date.format(FORMATTER); // 解析字符串,指定时区 ZonedDateTime date2 = ZonedDateTime.parse(dateStr, FORMATTER.withZone(CHINA_ZONE)); System.out.println(date2); // 2024-01-10T00:00+08:00[Asia/Shanghai] } public static void main(String[] args) { ClassTest ct = new ClassTest(); ct.methodTest(); } }
方案3:直接跳过字符串转换(最简便)
如果你的需求只是复制一个Date对象,完全不需要转成字符串再解析,直接复制时间戳即可:
Date date2 = new Date(date.getTime()); // 直接复制时间戳,结果完全一致
备注:内容来源于stack exchange,提问作者dmjy
相关产品推荐
相关产品推荐

