像Oliver Drotbohm自己在DATAMONGO-2106中所说的那样,Spring Data MongoDB从未支持使用时区保留日期时间类型。
这些是已知的解决方法:
- 使用不带时区的日期时间类型,例如java.time.Instant。(通常建议仅在后端使用UTC,但是我不得不扩展采用不同方法的现有代码库。)
- 编写一个自定义转换器,并通过扩展AbstractMongoConfiguration对其进行注册。有关运行示例,请参见我的测试库中的分支转换器。
@Component@WritingConverterpublic class ZonedDateTimeTodocumentConverter implements Converter<ZonedDateTime, document> { static final String DATE_TIME = "dateTime"; static final String ZONE = "zone"; @Override public document convert(@Nullable ZonedDateTime zonedDateTime) { if (zonedDateTime == null) return null; document document = new document(); document.put(DATE_TIME, Date.from(zonedDateTime.toInstant())); document.put(ZONE, zonedDateTime.getZone().getId()); document.put("offset", zonedDateTime.getOffset().toString()); return document; }}@Component@ReadingConverterpublic class documentToZonedDateTimeConverter implements Converter<document, ZonedDateTime> { @Override public ZonedDateTime convert(@Nullable document document) { if (document == null) return null; Date dateTime = document.getDate(DATE_TIME); String zoneId = document.getString(ZONE); ZoneId zone = ZoneId.of(zoneId); return ZonedDateTime.ofInstant(dateTime.toInstant(), zone); }}@Configurationpublic class MongoConfiguration extends AbstractMongoConfiguration { @Value("${spring.data.mongodb.database}") private String database; @Value("${spring.data.mongodb.host}") private String host; @Value("${spring.data.mongodb.port}") private int port; @Override public MongoClient mongoClient() { return new MongoClient(host, port); } @Override protected String getDatabaseName() { return database; } @Bean public CustomConversions customConversions() { return new MongoCustomConversions(asList( new ZonedDateTimeTodocumentConverter(), new documentToZonedDateTimeConverter() )); }}- 编写自定义编解码器。至少在理论上。使用Spring Boot 2.0.5时,我的编解码器测试分支无法解组数据,同时与Spring Boot 2.0.1正常工作。
public class ZonedDateTimeCodec implements Codec<ZonedDateTime> { public static final String DATE_TIME = "dateTime"; public static final String ZONE = "zone"; @Override public void enpre(final BsonWriter writer, final ZonedDateTime value, final EnprerContext enprerContext) { writer.writeStartdocument(); writer.writeDateTime(DATE_TIME, value.toInstant().getEpochSecond() * 1_000); writer.writeString(ZONE, value.getZone().getId()); writer.writeEnddocument(); } @Override public ZonedDateTime depre(final BsonReader reader, final DeprerContext deprerContext) { reader.readStartdocument(); long epochSecond = reader.readDateTime(DATE_TIME); String zoneId = reader.readString(ZONE); reader.readEnddocument(); return ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSecond / 1_000), ZoneId.of(zoneId)); } @Override public Class<ZonedDateTime> getEnprerClass() { return ZonedDateTime.class; }}@Configurationpublic class MongoConfiguration extends AbstractMongoConfiguration { @Value("${spring.data.mongodb.database}") private String database; @Value("${spring.data.mongodb.host}") private String host; @Value("${spring.data.mongodb.port}") private int port; @Override public MongoClient mongoClient() { return new MongoClient(host + ":" + port, createOptions()); } private MongoClientOptions createOptions() { CodecProvider pojoCodecProvider = PojoCodecProvider.builder() .automatic(true) .build(); CodecRegistry registry = CodecRegistries.fromRegistries( createCustomCodecRegistry(), MongoClient.getDefaultCodecRegistry(), CodecRegistries.fromProviders(pojoCodecProvider) ); return MongoClientOptions.builder() .precRegistry(registry) .build(); } private CodecRegistry createCustomCodecRegistry() { return CodecRegistries.fromCodecs( new ZonedDateTimeCodec() ); } @Override protected String getDatabaseName() { return database; }}


