xsd:dateTime 到 Java 偏移日期时间
xsd:dateTime to Java OffsetDateTime
为了妥善处理xs:dateTime with JAXB, I have to write my own converter from String
->java.time.OffsetDateTime
.
如 XML 架构定义中所述,dateTime 的灵感来自 ISO 8601。我使用 OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME)
来解析 xs:dateTime
,它适用于例如
"2007-12-03T10:15:30+01:00" //or
"2007-12-03T10:15:30Z"
可悲的是,在xs:dateTime
偏移部分is declared optional,所以解析有效
"2016-03-02T17:09:55"
抛出 DateTimeParseException
.
是否有 OffsetDateTime 的 DateTimeFormatter
,它也处理未分区的 xs:dateTime
s(可能有默认时区)?
我认为没有内置的,但您可以在 DateTimeFormatterBuilder
class.
的帮助下制作自己的
您可以在方括号中指定一个可选的偏移量,即 [XXXXX]
(以匹配 "+HH:MM:ss"
),然后,您可以在这种情况下提供默认偏移量(parseDefaulting
)它不存在的地方。如果想默认UTC,可以设置0指定不偏移;如果您想默认为 VM 的当前偏移量,您可以使用 OffsetDateTime.now().getLong(ChronoField.OFFSET_SECONDS)
.
获取它
public static void main(String[] args) {
String[] dates = {
"2007-12-03T10:15:30+01:00",
"2007-12-03T10:15:30Z",
"2016-03-02T17:09:55",
"2016-03-02T17:09:55Z"
};
DateTimeFormatter formatter =
new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd'T'HH:mm:ss[XXXXX]")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
// or OffsetDateTime.now().getLong(ChronoField.OFFSET_SECONDS)
.toFormatter();
for (String date : dates) {
System.out.println(OffsetDateTime.parse(date, formatter));
}
}
只是为了展示我当前的解决方案,该解决方案将未分区格式解析为系统默认 offset 在当前解析 dateTime.
public static OffsetDateTime parseDateTime(String s) {
if (s == null) {
return null;
}
try {
return OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
} catch (DateTimeParseException e) {
try { // try to handle zoneless xml dateTime
LocalDateTime localDateTime = LocalDateTime.parse(s, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
ZoneOffset offset = ZoneId.systemDefault().getRules().getOffset(localDateTime);
return OffsetDateTime.of(localDateTime.toLocalDate(), localDateTime.toLocalTime(), offset);
} catch (Exception fallbackTryException) {
throw e;
}
}
}
jTextTime 库解决了这个问题。这是 Maven Central 提供的最小 no-dep 库。它处理缺少时区偏移量的情况。
该库包含预构建 XmlAdapters
,因此您只需使用以下示例中的那些注释您的 classes:
public class Customer {
@XmlElement
@XmlJavaTypeAdapter(OffsetDateTimeXmlAdapter.class)
@XmlSchemaType(name="dateTime")
public OffsetDateTime getLastOrderTime() {
....
}
@XmlElement
@XmlJavaTypeAdapter(OffsetDateXmlAdapter.class)
@XmlSchemaType(name="date")
public OffsetDateTime getDateOfBirth() { // returns a date-only value
....
}
}
或者,您可以在包级别进行注释,这样您就不必为每个 class 和每个属性都进行注释。
如果您对库对缺少时区偏移情况的默认处理不满意,那么您可以 customize。
完全披露:我是 jTextTime 的作者。
正如我在评论中提到的那样添加到@Tunaki 的回答中,因为xs:dateTime
不允许基于秒的区域偏移。根据 appendPattern:
的文档,正确的模式应该只包含 [XXX]
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss[XXX]")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
其中列出了以下 table 时区格式:
Pattern Count Equivalent builder methods
------- ----- --------------------------
O 1 appendLocalizedOffset(TextStyle.SHORT)
OOOO 4 appendLocalizedOffset(TextStyle.FULL)
X 1 appendOffset("+HHmm","Z")
XX 2 appendOffset("+HHMM","Z")
XXX 3 appendOffset("+HH:MM","Z")
XXXX 4 appendOffset("+HHMMss","Z")
XXXXX 5 appendOffset("+HH:MM:ss","Z")
x 1 appendOffset("+HHmm","+00")
xx 2 appendOffset("+HHMM","+0000")
xxx 3 appendOffset("+HH:MM","+00:00")
xxxx 4 appendOffset("+HHMMss","+0000")
xxxxx 5 appendOffset("+HH:MM:ss","+00:00")
Z 1 appendOffset("+HHMM","+0000")
ZZ 2 appendOffset("+HHMM","+0000")
ZZZ 3 appendOffset("+HHMM","+0000")
ZZZZ 4 appendLocalizedOffset(TextStyle.FULL)
ZZZZZ 5 appendOffset("+HH:MM:ss","Z")
为了妥善处理xs:dateTime with JAXB, I have to write my own converter from String
->java.time.OffsetDateTime
.
如 XML 架构定义中所述,dateTime 的灵感来自 ISO 8601。我使用 OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME)
来解析 xs:dateTime
,它适用于例如
"2007-12-03T10:15:30+01:00" //or
"2007-12-03T10:15:30Z"
可悲的是,在xs:dateTime
偏移部分is declared optional,所以解析有效
"2016-03-02T17:09:55"
抛出 DateTimeParseException
.
是否有 OffsetDateTime 的 DateTimeFormatter
,它也处理未分区的 xs:dateTime
s(可能有默认时区)?
我认为没有内置的,但您可以在 DateTimeFormatterBuilder
class.
您可以在方括号中指定一个可选的偏移量,即 [XXXXX]
(以匹配 "+HH:MM:ss"
),然后,您可以在这种情况下提供默认偏移量(parseDefaulting
)它不存在的地方。如果想默认UTC,可以设置0指定不偏移;如果您想默认为 VM 的当前偏移量,您可以使用 OffsetDateTime.now().getLong(ChronoField.OFFSET_SECONDS)
.
public static void main(String[] args) {
String[] dates = {
"2007-12-03T10:15:30+01:00",
"2007-12-03T10:15:30Z",
"2016-03-02T17:09:55",
"2016-03-02T17:09:55Z"
};
DateTimeFormatter formatter =
new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd'T'HH:mm:ss[XXXXX]")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
// or OffsetDateTime.now().getLong(ChronoField.OFFSET_SECONDS)
.toFormatter();
for (String date : dates) {
System.out.println(OffsetDateTime.parse(date, formatter));
}
}
只是为了展示我当前的解决方案,该解决方案将未分区格式解析为系统默认 offset 在当前解析 dateTime.
public static OffsetDateTime parseDateTime(String s) {
if (s == null) {
return null;
}
try {
return OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
} catch (DateTimeParseException e) {
try { // try to handle zoneless xml dateTime
LocalDateTime localDateTime = LocalDateTime.parse(s, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
ZoneOffset offset = ZoneId.systemDefault().getRules().getOffset(localDateTime);
return OffsetDateTime.of(localDateTime.toLocalDate(), localDateTime.toLocalTime(), offset);
} catch (Exception fallbackTryException) {
throw e;
}
}
}
jTextTime 库解决了这个问题。这是 Maven Central 提供的最小 no-dep 库。它处理缺少时区偏移量的情况。
该库包含预构建 XmlAdapters
,因此您只需使用以下示例中的那些注释您的 classes:
public class Customer {
@XmlElement
@XmlJavaTypeAdapter(OffsetDateTimeXmlAdapter.class)
@XmlSchemaType(name="dateTime")
public OffsetDateTime getLastOrderTime() {
....
}
@XmlElement
@XmlJavaTypeAdapter(OffsetDateXmlAdapter.class)
@XmlSchemaType(name="date")
public OffsetDateTime getDateOfBirth() { // returns a date-only value
....
}
}
或者,您可以在包级别进行注释,这样您就不必为每个 class 和每个属性都进行注释。
如果您对库对缺少时区偏移情况的默认处理不满意,那么您可以 customize。
完全披露:我是 jTextTime 的作者。
正如我在评论中提到的那样添加到@Tunaki 的回答中,因为xs:dateTime
不允许基于秒的区域偏移。根据 appendPattern:
[XXX]
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss[XXX]")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
其中列出了以下 table 时区格式:
Pattern Count Equivalent builder methods
------- ----- --------------------------
O 1 appendLocalizedOffset(TextStyle.SHORT)
OOOO 4 appendLocalizedOffset(TextStyle.FULL)
X 1 appendOffset("+HHmm","Z")
XX 2 appendOffset("+HHMM","Z")
XXX 3 appendOffset("+HH:MM","Z")
XXXX 4 appendOffset("+HHMMss","Z")
XXXXX 5 appendOffset("+HH:MM:ss","Z")
x 1 appendOffset("+HHmm","+00")
xx 2 appendOffset("+HHMM","+0000")
xxx 3 appendOffset("+HH:MM","+00:00")
xxxx 4 appendOffset("+HHMMss","+0000")
xxxxx 5 appendOffset("+HH:MM:ss","+00:00")
Z 1 appendOffset("+HHMM","+0000")
ZZ 2 appendOffset("+HHMM","+0000")
ZZZ 3 appendOffset("+HHMM","+0000")
ZZZZ 4 appendLocalizedOffset(TextStyle.FULL)
ZZZZZ 5 appendOffset("+HH:MM:ss","Z")