Java 如何使用XMLGregorianCalendar处理CST到CDT或反之亦然

Java 如何使用XMLGregorianCalendar处理CST到CDT或反之亦然,java,date,websphere-8,websphere-7,xmlgregoriancalendar,Java,Date,Websphere 8,Websphere 7,Xmlgregoriancalendar,我在日光变化CST-CDT重置期间出现以下问题 我按预期从Was8.5服务器2018-03-11-05.00(UTC-5)获取输入,但当涉及到WAS7服务器时,以下方法返回Sun Mar 10 00.00.00 CST 2018,而不是Sun Mar 11 00.00.00 CDT 2018 /* * Converts XMLGregorianCalendar to java.util.Date */ public static Date toDate(XMLGregorianCalenda

我在日光变化CST-CDT重置期间出现以下问题

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

/*
 * 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(XMLGregoriacalendar日历)返回CDT(UTC-5)。然后我希望toDate()应该返回CST(UTC-6)

同样地


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

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

您看到的(
Sun Mar 10 00.00.00 CST 2018
)是
toString()
方法的结果,它使用JVM默认时区将
long
值转换为该时区中的日期和时间。有关更多详细信息,请参阅本文:

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

long millis = calendar.toGregorianCalendar().getTimeInMillis();
然后可以在UTC中打印此值:

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:

System.out.println(Instant.ofEpochMilli(millis));
这将告诉您
日期
对应的UTC时间,因此您可以比依赖
日期::toString()
方法更好地调试代码,因为该方法容易混淆和误导

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

// March 11th 2018, midnight, UTC-05:00
OffsetDateTime odt = OffsetDateTime.parse("2018-03-11T00:00-05:00");
然后我将其转换为
美国/芝加哥
时区,这是一个:

然后我打印了这个:

// 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
请注意,结果是UTC-06:00的2018-03-10 23:00-06:00 CST:3月10日

那是因为2018年。午夜,DST尚未开始,因此偏移量仍然是UTC-06:00

无论如何,您的转换代码是正确的,因为
Date
只表示一个时间点(自历元以来经过的时间计数),并且没有附加时区。也许问题出在某个地方,检查毫秒值可能有助于您了解发生了什么(我的猜测是,
xmlgoriiancalendar
将不存在的时间设置为午夜,这可以解释Sun Mar 10 00.00.00 CST 2018的结果)


如果这有帮助,则DST转换发生的准确UTC瞬间(2018年3月11日UTC-06:00凌晨2点)对应于毫秒值
1520755200000
。如果您在2018年3月的日期值低于该值,则表示它们在DST开始之前,并且将在CST中。

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

您看到的(
Sun Mar 10 00.00.00 CST 2018
)是
toString()
方法的结果,它使用JVM默认时区将
long
值转换为该时区中的日期和时间。有关更多详细信息,请参阅本文:

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

long millis = calendar.toGregorianCalendar().getTimeInMillis();
然后可以在UTC中打印此值:

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:

System.out.println(Instant.ofEpochMilli(millis));
这将告诉您
日期
对应的UTC时间,因此您可以比依赖
日期::toString()
方法更好地调试代码,因为该方法容易混淆和误导

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

// March 11th 2018, midnight, UTC-05:00
OffsetDateTime odt = OffsetDateTime.parse("2018-03-11T00:00-05:00");
然后我将其转换为
美国/芝加哥
时区,这是一个:

然后我打印了这个:

// 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
请注意,结果是UTC-06:00的2018-03-10 23:00-06:00 CST:3月10日

那是因为2018年。午夜,DST尚未开始,因此偏移量仍然是UTC-06:00

无论如何,您的转换代码是正确的,因为
Date
只表示一个时间点(自历元以来经过的时间计数),并且没有附加时区。也许问题出在某个地方,检查毫秒值可能有助于您了解发生了什么(我的猜测是,
xmlgoriiancalendar
将不存在的时间设置为午夜,这可以解释Sun Mar 10 00.00.00 CST 2018的结果)


如果这有帮助,则DST转换发生的准确UTC瞬间(2018年3月11日UTC-06:00凌晨2点)对应于毫秒值
1520755200000
。如果您2018年3月的日期值低于此值,则意味着它们在DST开始之前,并且将在CST中。

我的第一个建议是,您不需要您所要求的。在我看来,你已经有了一个日期和UTC偏移量,我真的看不到偏移量添加了任何有用的信息。就记下日期吧。我相信发生的事情是,3月11日过渡到夏季时间后的某个时间点被剥夺了一天中的时间,但是UTC偏移量被保留了,无论出于何种原因,或者可能根本没有任何原因。当在一天的开始(00:00)给出时间时,偏移量与您所在的美国/芝加哥时区(或中央时区,但区域/城市格式的ID是明确的,建议使用)

不要在约会中使用
java.util.Date
。那门课早就过时了。今天,我们在
java.time
中有了更好的表现