我的 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
有偏移量,所以这个方法肯定不是你想用的
链接
我的 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
有偏移量,所以这个方法肯定不是你想用的