【问题标题】:Java Date problems with TIMEZONETIMEZONE 的 Java 日期问题
【发布时间】:2014-11-28 10:14:38
【问题描述】:

我为此苦苦挣扎了好几天。

我有一个日期字段,它给出了“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 图书馆的解决方案,但我被告知不要使用它,我需要找到另一个解决方案。

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

有人经过吗?

【问题讨论】:

  • 我总是将 joda 库用于所有与日期相关的字段。时区之间的转换很简单,我相信线程安全。此外,joda 格式化程序(与本机 java DateFormatter 不同)是线程安全的
  • 所以老大允许你加Spring而不加Joda-Time?您需要向老板解释捆绑的日期时间课程有多糟糕,以及您对 Joda-Time 的需求有多大。 Joda-Time 被广泛使用、稳定且经久耐用。与 Java 8 捆绑在一起的新 java.time 包也很好,它受到 Joda-Time 的启发,但经过重新设计。 Joda-Time 和 java.time 都有各自的优势。我两个都用。

标签: java spring date timezone


【解决方案1】:

Joda-Time 库修复了此类问题,我相信这也是 Java 8 中 java.time 包的基础,但对于较旧的 Java 版本,此类问题经常出现。

我见过的在没有 Joda 时间的情况下处理此问题的唯一一致方法是将纯日期视为字符串 ("2014-10-01") 或整数类型 (20141001) 而不是日期。并且仅在计算中需要时转换为日期。不过这真的很痛苦。

【讨论】:

    【解决方案2】:

    不要忘记 SimpleDateFormat 不是线程安全的。 saga56 给出的答案可能有效,但如果同时使用解串器,您会有一些非常奇怪的日期。您每次都需要“新建” SimpleDateFormats,或者(不太有利)执行其他操作以确保 SimpleDateFormat 一次严格限制为 1 个线程。

    【讨论】:

      【解决方案3】:

      此问题的解决方案。

      我们为每个 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);
      }
      }
      

      这样,当我们收到不同格式的日期时,或者要存储时区时,我们可以将其更改为我们想要的。

      我希望这个解决方案可以提供帮助,我被困在这个问题上 3.5 天。日期是一个痛苦的**。

      【讨论】:

        【解决方案4】:

        其他答案正确但已过时。

        java.time

        java.time 框架内置于 Java 8 及更高版本中。这些类取代了旧的麻烦的日期时间类,例如java.util.Date.Calendarjava.text.SimpleDateFormatJoda-Time 团队还建议迁移到 java.time。

        要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。

        大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 和 7,并在 ThreeTenABP 中进一步适应 Android。

        LocalDate

        LocalDate 表示没有时间和时区的仅日期值。

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

        String input = "2014-10-01";
        LocalDate localDate = LocalDate.parse( input );
        

        ZonedDateTime

        您假设一天从时间00:00:00 开始。但并非总是如此。在某些时区,夏令时 (DST) 或可能的其他异常可能意味着一天从时钟的其他时间开始,例如 01:00:00。让 java.time 确定一天中第一个时刻的开始时间。指定一个时区,并假设与 Java 捆绑在一起的 tz database 是最新的,那么对 LocalDate::atStartOfDay 的调用会为您的日期和第一时间生成一个 ZonedDateTime

        ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
        ZonedDateTime zdt = localDate.atStartOfDay( zoneId );
        

        如果您想要UTC 中的第一天,请指定常量ZoneOffset.UTCZoneOffsetZoneId 的子类)。

        ZonedDateTime zdt = localDate.atStartOfDay( ZoneOffset.UTC );
        

        或者,使用更合适的OffsetDateTime 类。这适用于只有offset-from-UTC 但缺少处理异常的规则集,例如完整的time zone 中的DST。在 UTC 中,一天总是从 00:00:00 开始,它存储在常量 LocalTime.MIN 中。

        OffsetTime ot = OffsetTime.of( LocalTime.MIN , ZoneOffset.UTC );
        OffsetDateTime odt = localDate.atTime( offsetTime );
        

        数据库

        对于数据库工作,如果您想要存储仅日期值,您应该使用类似于SQL Standard type of DATE 的数据类型。

        对于日期时间值,几乎每个重要的数据库都会将传入数据转换为 UTC 以存储在 TIMESTAMP WITH TIME ZONE 类型的列中。您的 JDBC 驱动程序应该对此有所帮助。但是随着驱动程序和数据库的行为变化而进行测试和实验巨大

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-02
          • 1970-01-01
          • 2018-08-24
          • 2010-10-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多