我们有一个从字母数字字符串中获取日期的方法。假设字符串是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天!
Object转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秒的时间,问题也会出现。
Edit-1(通过将时区设置为格式化程序找到另一个修复)
我们可以通过另一种方式解决这个问题,即在getDateFromGITID
方法中将DateFormat
的时区设置为GST(Java SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") gives timezone as IST)。
format.setTimeZone(TimeZone.getTimeZone("GMT"));
所以问题是
1.为什么会这样?
1.第二种方法是不是更好?
1.还有更好的解决办法吗?
1条答案
按热度按时间1dkrff031#
您正在使用有严重缺陷的日期-时间类,这些类在几年前就被JSR 310中定义的现代 java.time 类所取代。
具体来说,我希望你的问题是由于使用
java.util.Date#toString
方法来生成文本。这种方法对你撒谎。java.util.Date
值表示从UTC时间子午线偏移0小时-分钟-秒的日期和时间。toString
方法在生成文本结果时应用JVM的当前默认时区。虽然初衷是好的,但这个反特性给Java开发人员带来了无尽的困惑和痛苦。避开这门课。避免所有遗留的日期-时间类!
使用行业领先的 java.time 类完成所有的日期时间工作。
如果您必须与尚未更新到 java.time 的旧代码进行互操作,请使用添加到旧类的新方法进行转换。
从一个日期到一个时刻,时间轴上的一个特定点,需要一天中的时间,需要一个时区。我假设你想要的是UTC中日期的第一个时刻(偏移量为零)。
我必须指出,使用带有时间和偏移量的日期类型(如
java.util.Date
)来表示仅包含日期的值是多么不明智。如果可能的话,请考虑重写代码库以使用正确的类型。对于仅日期值,使用java.time.LocalDate
类。LocalDate
支持Java 8+、JDBC 4.2+、Hibernate、Jackson等。或者,正如Ole V. V.所评论的那样,也许你的意思是在一个特定的时区看到一天的第一个时刻。
最好的解决方案是教育数据的发布者使用标准的ISO 8601来交换日期-时间值,而不是发明自己的格式。