首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用XMLGregorianCalendar处理CST到CDT,反之亦然

如何使用XMLGregorianCalendar处理CST到CDT,反之亦然
EN

Stack Overflow用户
提问于 2018-04-03 07:38:40
回答 2查看 2.3K关注 0票数 0

我有以下问题,在日光变化CST-CDT重置.

我正在按预期从Was8.5 server 2018-03- 11 -05.00 (UTC-5)获取输入,但是当涉及到WAS7服务器时,下面的方法返回Sun Mar 10 00.00.00 CST 2018而不是Sun Mar 11 00.00.00 CDT 2018。

代码语言:javascript
复制
/*
 * Converts XMLGregorianCalendar to java.util.Date
 */
public static Date toDate(XMLGregorianCalendar calendar){
    if(calendar == null) {
        return null;
    }
    return calendar.toGregorianCalendar().getTime();
}

我知道服务器日期/时区重置没有正确进行,但如果我想得到正确的时间,当CST更改CDT或反之亦然。如何用Java重写代码将XMLGregorianCalendar转换为java.util.Date

类似于,如果传入请求是CST(UTC-6),则toDate(XMLGregorianCalendar日历)返回CDT (UTC-5)。然后我希望toDate()返回CST (UTC-6)。

同样的方式,

如果传入的请求是CST(UTC-5),则toDate(XMLGregorianCalendar日历)返回CST(UTC-6)。然后,我希望toDate()应该返回CDT(UTC-5)。

EN

回答 2

Stack Overflow用户

发布于 2018-04-03 12:23:50

java.util.Date没有时区。它只有一个long值,表示自unix时代以来的毫秒数。

您看到的(Sun Mar 10 00.00.00 CST 2018)是toString()方法的结果,它使用JVM默认时区将long值转换为该时区中的日期和时间。有关更多详细信息,请参阅本文:https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/

无论如何,真正知道发生了什么的一种方法是检查这个long值:

代码语言:javascript
复制
long millis = calendar.toGregorianCalendar().getTimeInMillis();

然后可以在UTC中打印此值:

代码语言:javascript
复制
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss XXX");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(sdf.format(new Date(millis)));

或者,如果您使用Java 8:

代码语言:javascript
复制
System.out.println(Instant.ofEpochMilli(millis));

这将告诉您Date对应的UTC瞬间,因此您可以比依赖Date::toString()方法更好地调试代码,这是令人困惑和误导的。

关于您的主要问题,我尝试复制(我使用的是Java8,因为它比使用Date更容易操作)。首先,我在UTC-05:00中创建了一个与2018-03-11相对应的日期/时间,并假设时间为午夜:

代码语言:javascript
复制
// March 11th 2018, midnight, UTC-05:00
OffsetDateTime odt = OffsetDateTime.parse("2018-03-11T00:00-05:00");

然后我将其转换为America/Chicago时区,这是一个使用CST/CDT的区域

代码语言:javascript
复制
// get the same instant in Central Time
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("America/Chicago"));

然后我打印了这个:

代码语言:javascript
复制
// print the date/time with timezone abbreviation
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm xxx z", Locale.US);
System.out.println(zdt.format(fmt)); // 2018-03-10 23:00 -06:00 CST

请注意,结果是2018-03-10 23:00-06:00 CST:3月10日在UTC-06:00。

这是因为2018年,3月11日。午夜时分,DST还没有启动,所以偏移量仍然是UTC-06:00。

不管怎么说,您的转换代码是正确的,因为Date只是表示一个时间点(从时代以来经过的时间的计数),并且没有附加时区。也许问题就在某个地方,检查millis值可能会帮助您了解正在发生的事情(我猜XmlGregorianCalendar将时间设置为午夜,当它不存在时,这将解释Sun Mar1000.00.00 CST 2018年的结果)。

如果这有帮助的话,DST转换发生的确切的UTC瞬间(2018年3月11日凌晨2点,UTC-06:00)对应于millis值1520755200000。如果你2018年3月的约会值低于这个值,那就意味着它们在DST开始之前,它们就会在CST中。

票数 2
EN

Stack Overflow用户

发布于 2018-04-03 19:34:16

我的第一个建议是你不需要你想要的东西。在我看来,您有一个日期和一个UTC偏移量,而我并不认为偏移量增加了任何有用的信息。去约会吧。我相信所发生的事情是,在3月11日向夏季时间过渡之后的某个时间点被剥夺了一天的时间,但UTC的抵消是出于任何原因,或者根本没有任何原因。当在一天开始时(00:00)给出时间时,偏移量与您的美国/芝加哥时区(或中央时区)不一致,但区域/城市格式的ID是明确和推荐的。

不要在约会时使用java.util.Date。那门课早就过时了。今天,我们在java.time (现代Java和time )中有了很多改进。此外,它的LocalDate类更适合于没有时间的日期,因为这正是它的特性,而Date实际上是一个时间点,也就是说,一个完全不同的故事。根据味觉转换从XMLGregorianCalendar可以有两种方式。

直接法

代码语言:javascript
复制
    return LocalDate.of(calendar.getYear(), calendar.getMonth(), calendar.getDay());

对于您的XMLGregorianCalendar of 2018-03-11-05:00,结果是LocalDate of 2018-03-11

通过GregorianCalendarZonedDateTime的间接途径

代码语言:javascript
复制
    return calendar.toGregorianCalendar().toZonedDateTime().toLocalDate();

结果是一样的。后者的优点是,你不需要关心自己的个别领域的年,月和日。除其他外,这意味着您不会冒险将它们置于错误的顺序中。

如果您坚持保持时区或UTC偏移,至少采取偏移。2018年3月11日00.00.00 CDT没有意义,因为3月11日00时DST还没有生效(从02:00开始)。这样一个不存在的时间只会让每个人感到困惑。将日历对象转换为OffsetDateTime

代码语言:javascript
复制
    return calendar.toGregorianCalendar().toZonedDateTime().toOffsetDateTime();

结果:2018-03-11T00:00-05:00。这个时间点是存在的。

由于您的calendar来自外部系统,您可能希望验证它,因为任何字段都可能未定义并返回DatatypeConstants.FIELD_UNDEFINED。在使用LocalDate.of()时,您可以确定它的参数验证足够了,因为它将反对将DatatypeConstants.FIELD_UNDEFINED作为参数传递。另一方面,toGregorianCalendar()将默认使用默认值,因此在使用它时,我会认为验证是必不可少的。

你的代码出了什么问题?

我运行了您的代码,类似于iolus (请参阅另一个答案),我得到了Sat Mar 10 23:00:00 CST 2018。这是正确的时间点。正如尤勒斯所解释的,这是Date.toString以这种方式呈现时间点。Date对象本身没有时区或UTC偏移量。所以我应该说你的代码是正确的。只是你被toString方法弄糊涂了。前面已经有很多了,最好的解决方案是完全避免使用Date类。另外,我认为你的观察与WAS 7和WAS 8.5之间的任何差异无关。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49624705

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档