我在生产中遇到了一个奇怪的问题:Java.util.Date字段完全随机地减少了一天。 它很少发生,但有时出现问题并且生产日期减少。
尝试创建自定义序列化程序和反序列化程序没有帮助。
这是代码:
// UserData class
package mypackage;
import myotherpackage.DataDefaultPatternDeserializer;
import myotherpackage.DataDefaultPatternSerializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;
import java.util.Date;
@Data
public class UserData {
//Random problems in production - date decreased by one day
@JsonSerialize(using = DataDefaultPatternSerializer.class)
@JsonDeserialize(using = DataDefaultPatternDeserializer.class)
private Date dateOfBirth;
}
// ----------------------------------------------------------------------------------------
// DataDefaultPatternSerializer class
package myotherpackage;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.Date;
import java.util.Locale;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class DataDefaultPatternSerializer extends JsonSerializer<Date> {
public DataDefaultPatternSerializer() {
}
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyyMMdd").withLocale(Locale.ITALY);
jsonGenerator.writeString(formatter.print(new DateTime(date)));
}
}
// ----------------------------------------------------------------------------------------
// DataDefaultPatternDeserializer class
package myotherpackage;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.util.Date;
import java.util.Locale;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class DataDefaultPatternDeserializer extends JsonDeserializer<Date> {
public DataDefaultPatternDeserializer() {
}
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyyMMdd").withLocale(Locale.ITALY);
String dateString = jsonParser.getText();
return formatter.parseDateTime(dateString).toDate();
}
}
有什么解决办法吗?
错误类型
切勿使用Date
类中的任何一个。这些糟糕的类在几年前就被JSR 310中定义的现代java.time类所取代。
此外,java.util.Date
表示一个时刻,一个日期,其时间以 UTC 表示,偏移量为零命中-分钟-秒。您尝试将仅日期值(出生日期)放入 UTC 中具有时间的日期类型中。
时区
日期和时间在java.util.Date
上似乎发生变化的原因是,该类在其众多设计缺陷中存在一个toString
方法,该方法在生成文本时动态应用 JVM 的当前默认时区。当将一个时刻调整到另一个时区时,一天中的时间甚至日期都可能会"改变"。现在,在我写这篇文章的时候,它是日本东京的"明天",同时在美国俄亥俄州托莱多是"昨天"。
日本东京 现在 05:53:08 上午 于 2022-03-19 星期六
美国俄亥俄州托莱多 现在 2022-03-18 星期五下午 04:53:08
此问题的最佳解决方案是 (a) 不使用旧版java.util.Date
类,以及 (b) 不使用 UTC 中具有时间的日期类型来表示仅日期值。
java.time.LocalDate
对于出生日期,请使用仅日期类型LocalDate
。
LocalDate ld = LocalDate.parse( "1969-01-23" ) ;
要生成标准 ISO 8601 格式的文本,请调用toString
。
String outputISO8601 = ld.toString() ;
序列 化
将日期时间值序列化为文本时,请使用 ISO 8601 格式。
Jackson 支持java.time类型。
数据库
在类似于 SQL 标准类型DATE
类型的列中写入数据库:
myPreparedStatement.setObject( … , ld ) ;
检索。
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;