更新时间:2022-01-10 22:22:51
A java.util.Date
没有任何时区信息.一旦将 String
反序列化为 Date
,偏移量 +0300
就会丢失:日期只保留时间戳值,它不能知道它来自哪个原始时区.
A java.util.Date
doesn't have any timezone information. Once you deserialize a String
to a Date
, the offset +0300
is lost: the date keeps just the timestamp value, and it can't know what's the original timezone it came from.
如果输出必须始终在 +03:00
偏移量中,您可以使用 com.fasterxml.jackson.annotation.JsonFormat
在各自的字段中直接设置它> 注释:
If the output must always be in +03:00
offset, you can set it directly in the respective fields, using the com.fasterxml.jackson.annotation.JsonFormat
annotation:
@JsonFormat(timezone = "GMT+03:00")
private Date startDateTime;
@JsonFormat(timezone = "GMT+03:00")
private Date endDateTime;
这样,日期字段将始终序列化为 +03:00
偏移量:
With this, the date fields will always be serialized to +03:00
offset:
{
"startDateTime":"2017-10-09T22:43:07.109+0300",
"endDateTime":"2017-10-09T21:40:07.109+0300"
}
如果输入可以在任何其他偏移量中(不仅是 +03:00
)并且您想保留它,java.util.Date
不是理想的类型.一种替代方法是使用 Jackson Modules Java 8,如果您使用的是 Java >= 8.
If the inputs can be in any other offset (not only +03:00
) and you want to preserve it, the java.util.Date
isn't the ideal type. One alternative is to use Jackson Modules Java 8, if you're using Java >= 8.
对于 Java 6 和 7,有 ThreeTen Backport 和相应的 Jackson 模块 - 不过我还没有测试过,但代码可能相似,因为 ThreeTen Backport 包含相同的类和方法,只有包不同 - (在 Java 8 中是 java.time
,而在 ThreeTen Backport 中是 org.threeten.bp
).
For Java 6 and 7, there's the ThreeTen Backport and the corresponding Jackson module - I haven't tested, though, but the code might be similar, as the ThreeTen Backport contains the same classes and methods, only the package is different - (in Java 8 is java.time
and in ThreeTen Backport is org.threeten.bp
).
要保留日期、时间和偏移量,***的替代方法是 OffsetDateTime
类.所以你只需要改变字段类型并为其设置相应的格式即可:
To preserve the date, time and offset, the best alternative is the OffsetDateTime
class. So you just need to change the fields type and set the corresponding format to it:
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX")
private OffsetDateTime startDateTime;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX")
private OffsetDateTime endDateTime;
在对象映射器中,您还必须注册 JavaTimeModule
并禁用 ADJUST_DATES_TO_CONTEXT_TIME_ZONE
功能,因此保留偏移量(默认行为是转换为 Jackson 上下文的时区,这可能与输入中使用的不同 - 通过禁用此功能,偏移量将被保留).
In the object mapper, you must also register the JavaTimeModule
and disable the ADJUST_DATES_TO_CONTEXT_TIME_ZONE
feature, so the offsets are preserved (the default behaviour is to convert to Jackson context's timezone, which might not be the same used in the inputs - by disabling this, the offset is preserved).
您可以使用 JacksonConfigurator
(如在本答案中解释)并进行这些配置:
You can use a JacksonConfigurator
(as explained in this answer) and do these configurations:
ObjectMapper om = new ObjectMapper();
om.registerModule(new JavaTimeModule());
om.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
这个配置通常就足够了,但您也可以将SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
设置为false
,以防万一.
This configuration is usually enough, but you can also set SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
to false
as well, just in case.
如果您仍然需要使用 java.util.Date
,您可以使用 API 进行相互转换.在 Java 8 中,有新的 Date.from
方法:
If you still need to work with java.util.Date
, you can use the API to convert from/to it. In Java 8, there's the new Date.from
method:
// convert to java.util.Date
public Date getStartAsJavaUtilDate() {
return Date.from(startDateTime.toInstant());
}
在 ThreeTen Backport 中,有 org.threeten.bp.DateTimeUtils
类:
And in ThreeTen Backport, there's the org.threeten.bp.DateTimeUtils
class:
// convert to java.util.Date
DateTimeUtils.toDate(startDateTime.toInstant());
将 Date
转换回 OffsetDateTime
,不过,这更棘手.Date
对象没有时区信息,因此无法知道原始偏移量.一种替代方法是将原始偏移量保留在单独的变量中:
To convert a Date
back to OffsetDateTime
, though, it's more tricky. The Date
object has no timezone information, so it can't know the original offset. One alternative is to keep the original offset in a separate variable:
// keep the original offset
ZoneOffset startDateOffset = startDateTime.getOffset();
然后,您可以将Date
转换为Instant
,然后再转换为原始偏移量:
Then, you can convert the Date
to Instant
, and then convert it to the original offset:
// convert java.util.Date to original offset (Java 8)
startDateTime = date.toInstant().atOffset(startDateOffset);
// ThreeTen Backport
startDateTime = DateTimeUtils.toInstant(date).atOffset(startDateOffset);