时区的Java日期问题

时区的Java日期问题,java,spring,date,timezone,Java,Spring,Date,Timezone,我为此挣扎了好几天 我有一个日期字段,它以“yyyy-MM-dd”格式给出日期 我的对象有这样的字段 @Temporal(TemporalType.DATE) private Date finishdate; 我在UTC,这需要在世界各地工作,UTC-7或UTC+7也是如此 在数据库上,此值需要存储0小时 填写finishdate时,格式会给出时区,例如: 我想要2014-10-01,在我捕捉到的不同时区,零小时零分零秒: 2014-10-01 07:00:00:000 或 2014-09-0

我为此挣扎了好几天

我有一个日期字段,它以“yyyy-MM-dd”格式给出日期

我的对象有这样的字段

@Temporal(TemporalType.DATE)
private Date finishdate;
我在UTC,这需要在世界各地工作,UTC-7或UTC+7也是如此

在数据库上,此值需要存储0小时

填写finishdate时,格式会给出时区,例如:

我想要2014-10-01,在我捕捉到的不同时区,零小时零分零秒:

2014-10-01 07:00:00:000 或 2014-09-01 17:00:00:000

问题可能是因为日期限制,我已经找到了JODA Library的解决方案,但我被告知不要使用它,我需要找到另一个解决方案

因此,需要转换为UTC日期、所有日期或其他日期,但日期必须相同,如10月1日

有没有人经历过这个问题?

库修复了这样的问题,我相信这也是java 8中java.time包的基础,但是对于较旧的java版本,这种问题经常发生


在没有Joda time的情况下,我看到的唯一一致的处理方法是将纯日期视为字符串(“2014-10-01”)或整数类型(20141001),而不是日期。并且仅在计算中需要时转换为日期。但这确实是一件痛苦的事。

这个问题的解决方案

我们为Date类型的每个对象创建了自定义反序列化器

在我们序列化或反序列化的ObjectMapperFactory上,我映射到另一个类,如下所示:

 module.addDeserializer(Date.class, new DateDeserializerByDefault());
然后,在这节课上我们做了:

private static SimpleDateFormat dateFormatWithoutTimezome = new SimpleDateFormat("yyyy-MM-dd");
private static SimpleDateFormat dateFormatWithTimezone= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); 
private static Pattern pattern = Pattern.compile("([0-9]{4})-([0-9]{2})-([0-9]{2})");

@Override
public Date deserialize(JsonParser jparser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    String content = jparser.getValueAsString();
    DateFormat format=(pattern.matcher(content).matches()) ? dateFormatWithoutTimezome : dateFormatWithTimezone;        

try {
    return format.parse(content);
} catch (ParseException e) {
    throw new JsonParseException("Date parse failed", jparser.getCurrentLocation(),e);
}
}
有了这个,当我们收到不同格式的日期,或者时区为stor时,我们可以将其更改为我们想要的


我希望这个解决方案能有所帮助,我坚持了3,5天。约会是一件痛苦的事

不要忘记SimpleDataFormat不是线程安全的。saga56给出的答案可能有用,但如果同时使用反序列化程序,您将有一些非常奇怪的日期。您需要每次“更新”SimpleDataFormat,或者(不太有利地)执行其他操作,以确保SimpleDataFormat一次仅限于一个线程。

其他答案是正确的,但已过时

java.time 该框架内置于Java8及更高版本中。这些类取代了旧的麻烦的日期时间类,如
java.util.date
.Calendar
,&
java.text.SimpleDateFormat
。该团队还建议迁移到java.time

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释

大部分java.time功能都在中向后移植到Java6和Java7,并在中进一步适应Android

LocalDate
A表示仅日期的值,不含一天中的时间和时区

您的输入字符串采用标准ISO 8601格式,因此可以通过
LocalDate
直接解析。无需指定格式化模式

String input = "2014-10-01";
LocalDate localDate = LocalDate.parse( input );
ZoneDateTime
假设一天从时间
00:00:00
开始。但事实并非总是如此。在某些时区,夏令时(DST)或其他异常可能意味着一天从时钟上的其他时间开始,如
01:00:00
。让java.time确定一天中第一个时刻的开始时间。指定一个时区,并假设捆绑的Java是最新的,那么对的调用将为您的日期和第一个时刻生成一个

ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = localDate.atStartOfDay( zoneId );
如果希望一天中的第一个时刻在中,请指定常量(
ZoneOffset
ZoneId
的子类)

或者,使用更合适的
OffsetDateTime
类。这适用于仅具有一组规则的值,但缺少一组规则来处理异常,例如在完整的数据集中发现的DST。在UTC中,一天总是从存储在常数中的
00:00:00
开始

数据库 对于数据库工作,如果您希望存储一个仅限日期的值,则应该使用一个数据类型,该数据类型应与

对于日期时间值,几乎每个严肃的数据库都会将传入数据转换为UTC,以存储在带有时区的时间戳列中。您的JDBC驱动程序应该对此有所帮助。但是测试和实验,因为驱动程序和数据库的行为差异很大


使用JDBC4.2及更高版本,您可以通过
setObject
/
getObject
直接传递/获取java.time类型。如果没有,请通过添加到旧类中的新方法转换为java.sql类型。

对于所有与日期相关的字段,我总是使用joda库。时区之间的转换很简单,我相信线程安全。另外,joda格式化程序(与本机java DateFormatter不同)是线程安全的,所以boss允许您添加Spring,但不允许添加joda时间?你需要向老板解释捆绑的日期时间类有多糟糕,你有多需要Joda时间。Joda Time使用广泛、稳定且耐用。与Java8捆绑在一起的新java.time包也不错,它的灵感来源于Joda time,但经过了重新设计。Joda Time和java.Time都有各自的优势。我两者都用。
ZonedDateTime zdt = localDate.atStartOfDay( ZoneOffset.UTC );
OffsetTime ot = OffsetTime.of( LocalTime.MIN , ZoneOffset.UTC );
OffsetDateTime odt = localDate.atTime( offsetTime );