我们有一个从字母数字字符串获取日期的方法。假设字符串是
Y04051000547GF
,结果日期将是 Tue May 04 00:00:00 IST 2010
。
public static Date getDateFromGITID(String gitId) {
Date date = null;
try {
String dateInGit = nid.substring(1, 7); // six characters from the second character
DateFormat format = new SimpleDateFormat("ddMMyy", Locale.ENGLISH);
date = format.parse(dateInGit);
} catch (ParseException e) {
}
return date;
}
现在,这个日期被分配给一个类的属性
UserInfo
,当我们尝试将此类的对象转换为 JSON 时,日期会减少 1 天!
对象转JSON字符串
public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
用户信息Bean
public class UserInfo {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
Date date;
}
这是主要方法
public static void main(String[] args) {
UserInfo obj = new UserInfo();
obj.date = getDateFromGITID("Y04051000547GF");
System.out.println(obj.date);
System.out.println(asJsonString(obj));
}
这是控制台输出
Tue May 04 00:00:00 IST 2010
{"dob":"2010-05-03"}
您可以看到日期是 2010 年 5 月 4 日,但在 JSON 中它会减少 1 天。我们能够找出导致问题的原因,日期以 IST 打印,与 UST 相差 5 小时 30 分钟。所以我们在 JSON 转换之前添加了该时间,转换后的时间没有变化。
public static void main(String[] args) {
UserInfo obj = new UserInfo();
obj.dob = getDOBFromNID("Y04051000547GF");
System.out.println(obj.dob);
obj.dob.setHours(5);
obj.dob.setMinutes(30);
obj.dob.setSeconds(00);
System.out.println(asJsonString(obj));
}
输出
Tue May 04 00:00:00 IST 2010
{"dob":"2010-05-04"}
是的,我们使用了已弃用的方法,但它仅用于测试。即使我们尝试将时间减少 1 秒,问题也会出现。所以问题是
您正在使用有严重缺陷的日期时间类,这些类在几年前已被 JSR 310 中定义的现代 java.time 类取代。
具体来说,我预计您的问题是由于使用
java.util.Date#toString
方法生成文本造成的。这个方法对你来说是骗人的。 java.util.Date
值表示日期和时间,与 UTC 时间子午线的偏移量为零时-分-秒。 toString
方法在生成文本结果时应用 JVM 当前的默认时区。
虽然本意是好的,但这种反特性给 Java 开发人员带来了无尽的困惑和痛苦。避免这门课。避免所有遗留的日期时间类!
使用行业领先的 java.time 类完成所有日期时间工作。
String original = "Y04051000547GF" ;
String input = original.substring( 1 , 7 ) ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "ddMMuu" ) ;
LocalDate ld = LocalDate.parse( input , f ) ;
如果您必须与尚未更新到 java.time 的旧代码进行互操作,请使用添加到旧类中的新方法进行转换。
从一个日期到一个时刻,时间线上的一个特定点,需要一天中的某个时间,并且需要一个时区。我假设您想要该日期的第一个时刻,如 UTC 所示(偏移量为零)。
ZonedDateTime zdt = ld.atStartOfDay( ZoneOffset.UTC ) ;
Instant instant = zdt.toInstant() ;
java.util.Date d = java.util.Date.from( instant ) ;
或者,如 Ole V.V. 所评论,也许您的意思是获取特定时区中一天中的第一时刻。
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;