java.time
String birth = "1939-11-19+01:00";
LocalDate date = LocalDate.parse(birth, DateTimeFormatter.ISO_OFFSET_DATE);
System.out.println(date);
打印出来
1939-11-19
java.time.LocalDate 是一个没有时间的日期,因此这完全符合您的要求。同时java.util.Date 和朋友们早已过时并且被证明设计不佳。 java.time,现代 Java 日期和时间 API,使用起来非常好用。所以我的第一个建议是你到此为止。
如果您确实需要 Date,例如对于旧版 API,请首先意识到尽管名称不代表日期。它代表一个时间点,在那个时间点,日期不会在任何地方都相同。如您所知,这可能会导致您的问题:parseDate 和 parseDateTime 将您的字符串解析为 00:00 在相关日期与 UTC 的指定偏移量处。此时,您所在时区的日期可能并不相同,因此当您打印得到的Date,从而调用其toString 方法时,您可能会得到不同的日期。我知道您希望在您自己的时区中使用 0:00 的时间(CET,可能是中欧时间,这又是几个不同时区的名称,这些时区可能在 1939 年该日期的偏移量为 0 或 +01;您观察到的结果在欧洲/巴黎、非洲/休达、欧洲/安道尔、欧洲/马德里和欧洲/摩纳哥时区是有意义的,所有这些时区的偏移量都为 0)。转换:
Date oldfashionedDateObject
= Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
System.out.println(oldfashionedDateObject);
这个打印出来的
Sun Nov 19 00:00:00 CET 1939
我将我的时区设置为 America/New_York 和 Europe/Moscow 进行测试,始终得到Sun Nov 19 00:00:00,仅在不同的时区EST 和MSK。
Java 6 和 ThreeTen 向后移植
我知道您必须使用 Java 6。java.time 已在 ThreeTen Backport 中向后移植到 Java 6 和 7。所以从底部的链接中获取它并将其添加到您的项目中,上面的代码将起作用,只是转换发生的方式略有不同:
Date oldfashionedDateObject
= DateTimeUtils.toDate(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
您无需重写所有代码即可使用 ThreeTen Backport,尤其是在某些部分您不信任现代 API 以您想要的方式运行时。上面的 sn-p 可以和你已有的代码很好的共存。
真正的老式方式
如果您真的坚持,我可以找到使用DatatypeConverter 和Calendar 获得您想要的Date 的方法:
Calendar calWithParsedOffset = DatatypeConverter.parseDate(birth);
Calendar calWithMyTimeZone = Calendar.getInstance(TimeZone.getDefault());
calWithMyTimeZone.clear();
calWithMyTimeZone.set(calWithParsedOffset.get(Calendar.YEAR),
calWithParsedOffset.get(Calendar.MONTH),
calWithParsedOffset.get(Calendar.DAY_OF_MONTH));
Date oldfashionedDateObject = calWithMyTimeZone.getTime();
System.out.println(oldfashionedDateObject);
我们不能只改变解析得到的Calendar 的偏移量或时区,因为这不会改变它的时间点,因此也不会改变我们得到的Date 对象。相反,我们需要将不同的Calendar 对象设置为第一个Calendar 的年、月和日。对 clear() 的调用将小时、分钟、秒和毫秒设置为 0。这个 sn-p 也已经在我的 JVM 的时区设置为 America/New_York 和 Europe/Moscow 的情况下进行了测试。
链接