我的 xmlGregorianCalendar 带有偏移值..如何调整它?在 java

My xmlGregorianCalendar coming with offset value ..how to adjust it? in java

我的 xmlGregorianCalendar 值为 2020-10-02T13:07:38-06:00 ..我想传递这个 xmlGregorianCalendar 值并获得类似 2020-10-02T07:07:38 的输出(这减少了 6 小时从那时起)对此有什么建议吗?

下面这个方法我用过

return 新时间戳(xmlGregorianCalendar.toGregorianCalendar(TimeZone.getTimeZone("GMT"),null,null).getTimeInMillis())..

但它删除了偏移值但没有调整时间。我得到的输出是 2020-10-02T13:07:38..但我期待这样的 2020-10-02T07:07:38。

首先,我建议您从过时的 error-prone java.util date-time API 切换到 modern java.time date-time API. Learn more about the modern date-time API from Trail: Date Time

您对Zone-Offset的理解不正确

date-time 字符串,2020-10-02T13:07:38-06:00 告诉我们给定的日期和时间已经从 UTC 偏移了 -06:00 小时,即相应的 date-time 在 UTC 将是 2020-10-02T19:07:38Z,其中 Z 指定 Zone-Offset 的 00:00 小时。

这意味着如果您期望 2020-10-02T07:07:38 的 date-time,您需要将给定的 date-time 进一步偏移 -06:00 小时,即它将在与 UTC.

相差总计 -12:00 小时

以下示例说明了这一概念:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odtGiven = OffsetDateTime.parse("2020-10-02T13:07:38-06:00");
        System.out.println(odtGiven);

        // Date and time at Zone-Offset of 00:00 hours
        OffsetDateTime odtUTC = odtGiven.withOffsetSameInstant(ZoneOffset.UTC);
        System.out.println(odtUTC);

        // Date and time at Zone-Offset of -12:00 hours
        OffsetDateTime odtDerived = odtGiven.withOffsetSameInstant(ZoneOffset.of("-12:00"));
        System.out.println(odtDerived);

        // Get the date-time string in the format with Zone-Offset dropped
        String strDateTimeZoneOffsetDropped = odtDerived.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        System.out.println(strDateTimeZoneOffsetDropped);
    }
}

输出:

2020-10-02T13:07:38-06:00
2020-10-02T19:07:38Z
2020-10-02T07:07:38-12:00
2020-10-02T07:07:38

使用旧版 API:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class Main {
    public static void main(String[] args) throws DatatypeConfigurationException, ParseException {
        String givenDateTimeString = "2020-10-02T13:07:38-06:00";
        XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance()
                .newXMLGregorianCalendar(givenDateTimeString);
        System.out.println(xmlGregorianCalendar);

        // Derive the date-time string at Zone-Offset of UTC-12:00 hours
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT-12:00"));
        Date date = xmlGregorianCalendar.toGregorianCalendar().getTime();
        String derivedDateTimeString = sdf.format(date);
        System.out.println(derivedDateTimeString);
    }
}

输出:

2020-10-02T13:07:38-06:00
2020-10-02T07:07:38

JDBC 4.2 和 java.time

Arvind Kumar Avinash 已经很好地解释了偏移量的工作原理(XMLGregorianCalendar 误导性地称为时区)。他还已经推荐了 java.time,现代 Java 日期和时间 API。我想详细说明这项建议。假设您认为您想要 java.sql.Timestamp 用于您的 SQL 数据库,您不应该想要那个。从 JDBC 4.2 和 Hibernate 5 开始,我们可以将 java.time 的类型无缝传输到我们的 SQL 数据库。我建议您改为这样做。

如果在 SQL 中使用带时区的时间戳,请在 Java

中使用 UTC 中的 OffsetDateTime

如果SQL中的数据类型是timestamp with time zone(推荐用于时间戳),将OffsetDateTime从Java传输到它。对于大多数数据库引擎,timestamp with time zone 实际上意味着 UTC 时间戳,因此为了清楚起见,我更愿意传递 UTC 中的 OffsetDateTime。有几种转换方法,每种方法各有利弊。

1.通过 GregorianCalendar.

转换
    // For demonstration build an XMLGregorianCalenadr equivalent to yours
    XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar("2020-10-02T13:07:38-06:00");
    
    // Convert to OffsetDateTime for your SQL database
    OffsetDateTime dateTime = xmlGregorianCalendar.toGregorianCalendar()
            .toZonedDateTime()
            .toOffsetDateTime()
            .withOffsetSameInstant(ZoneOffset.UTC);

    // Show what we’ve got
    System.out.println(dateTime);

输出为:

2020-10-02T19:07:38Z

Pro: 官方转换

2。通过 String.

转换
    OffsetDateTime dateTime = OffsetDateTime.parse(xmlGregorianCalendar.toString())
            .withOffsetSameInstant(ZoneOffset.UTC);

亲:短小精悍,我觉得没什么惊喜。缺点:对我来说,格式化为字符串并再次解析回 date-time 对象感觉很浪费。

3。通过 int 转换。您可以通过从 XMLGregorianCalendar 中取出各个字段并从中构建 OffsetDateTime 来进行转换。越来越long-winded,处理小数秒有点复杂,而且有不小心调换字段的风险,所以不推荐

如何传递给SQL。这是将 OffsetDateTime 转移到 SQL.

的示例
    String sqlString = "insert into your_table(your_timestamp_column) values (?);";
    PreparedStatement ps = yourDatabaseConnection.prepareStatement(sqlString);
    ps.setObject(1, dateTime);
    int rowsInserted = ps.executeUpdate();

如果在 SQL 中使用没有时区的时间戳,而是从 Java

传递一个 LocalDateTime

如果SQL中的数据类型是timestamp没有时区(不推荐时间戳,但经常看到),你需要从Java传递一个LocalDateTime .同样,有几种转换方法。我只展示一个:

    LocalDateTime dateTime = xmlGregorianCalendar.toGregorianCalendar()
            .toZonedDateTime()
            .withZoneSameInstant(ZoneId.systemDefault())
            .toLocalDateTime();

我使用的是 JVM 的默认时区,与 old-fashioned Timestamp class 所做的一致,因此结果取决于时区。在我的时区 (Europe/Copenhagen) 当前 UTC 偏移 +02:00,结果是:

2020-10-02T21:07:38

你的代码出了什么问题?

您使用的 three-arg XMLGregorianCalendar.toGregorianCalendar​(TimeZone, Locale, XMLGregorianCalendar) 旨在引入与您观察到的错误类似的错误。它承诺使用指定时区(如果给定)和来自 XMLGregorianCalendar 的字段值(年、月、日、小时、分钟等)构造一个 GregorianCalendar。所以文档说得很清楚:如果您指定的时区与 XMLGregorianCalendar 的偏移量不一致,它会为您提供与 XMLGregorianCalendar 指定的时间点不同的时间点。如果 XMLGregorianCalendar 没有任何偏移并且我们知道要使用哪个时区,它偶尔可能会有用。但是你的XMLGregorianCalendar有偏移量,所以这个方法肯定不是你想用的

链接