使用SimpleDateFormat解析日期不正确

时间:2018-02-14 14:27:58

标签: java date simpledateformat

我有一个MySQL表,其中包含date()和time()列,如

CREATE TABLE `vol` (
  `ID` bigint(20) unsigned NOT NULL,
  `DEPART_DATE_VOL` date NOT NULL,
  `DEPART_HEURE_VOL` time NOT NULL,
  `ARRIVEE_DATE_VOL` date NOT NULL,
  `ARRIVEE_HEURE_VOL` time NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我需要使用WHERE子句中的date()查询行,所以我没有datetime()或timestamp(也是,我无法修改数据库)

在我的DAO中获取信息时,我会将日期和时间列连接起来解析Java日期,如:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
addon.setDateDepart(sdf.parse(rs.getString(DEPART_DATE_VOL) + " " + rs.getString(DEPART_HEURE_VOL)));
addon.setDateArrivee(sdf.parse(rs.getString(ARRIVEE_DATE_VOL) + " " + rs.getString(ARRIVEE_HEURE_VOL)));

对于出发日期的行:

  • 2018-02-26 10:50:00生成的Java日期是正确的

但是到达日期:

  • 2018-02-26 12:20:00生成的Java日期设置为 2018-02-26T00:20:00

TMP解决方案

现在,我会坚持

addon.setDateDepart(new LocalDateTime(rs.getString(DEPART_DATE_VOL) + "T" + rs.getString(DEPART_HEURE_VOL)).toDate());

addon.setDateArrivee(new LocalDateTime(rs.getString(ARRIVEE_DATE_VOL) + "T" + rs.getString(ARRIVEE_HEURE_VOL)).toDate());

这似乎有效,尽管我不确定我是否会遇到时区问题......

2 个答案:

答案 0 :(得分:2)

请尝试HH:mm:ss作为时间部分。 hh用于“上午/下午(1-12)”,请参阅javadoc

答案 1 :(得分:2)

  1. 在数据库中使用timestamp数据类型而不是日期和时间的单独列。 MySQL timestamp采用UTC格式,因此应避免数据库端存在任何时区问题。
  2. 使用现代Java日期和时间API java.time。像Date这样的旧日期和时间类设计很差,特别是SimpleDateFormat非常麻烦,所以请避免使用它。
  3. 在Java程序和数据库之间传输日期时间对象,而不是字符串。
  4. 了解更多in this question: Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users。如果你不能做到这一切,尽可能多地做。

    详细

    如果您可以在数据库中存储时间戳,则可以将其检索为java.time.Instant

    Instant departVol = rs.getObject(DEPART_INSTANT_VOL, Instant.class);
    

    如果您无法更改addon.setDateDepart()接受的类型,请转换为Date,如下所示:

    addon.setDateDepart(Date.from(departVol));
    

    或者在使用ThreeTen Backport的版本中,java.time的后端到Java 6和7:

    addon.setDateDepart(DateTimeUtils.toDate(departVol));
    

    如果无法更改数据库设计,仍可以从中检索java.time个对象:

    LocalDate departDateVol = rs.getObject(DEPART_DATE_VOL, LocalDate.class);
    LocalTime departHeureVol = rs.getObject(DEPART_HEURE_VOL, LocalTime.class);
    LocalDateTime departDateHeureVol = LocalDateTime.of(departDateVol, departHeureVol);
    

    转换为老式的Date是不稳定的,因为正如您所说,可能存在时区问题。尝试:

    addon.setDateDepart(
            Date.from(departDateHeureVol.atZone(ZoneId.systemDefault()).toInstant()));
    

    如果此处似乎存在时区问题,则需要指定正确的时区而不是ZoneId.systemDefault()

    如果您的Java版本或JDBC驱动程序不支持从结果集中获取正确的日期时间对象,那么使用现代类解析字符串非常简单:

    LocalDate departDateVol = LocalDate.parse(rs.getString(DEPART_DATE_VOL);
    LocalTime departHeureVol = LocalTime.parse(rs.getString(DEPART_HEURE_VOL);
    

    这些对象继续如上所述。

    PS我还没有测试过我的代码片段。如果有拼写错误且您无法自行修复,请恢复。

    您的代码出了什么问题?

    kevmo314 is correct格式模式字符串中的小写hh是针对AM或PM的小时,从1到12.所以12:20:00 意味着{{ 1}}。要在24小时制时解释00:20:00,请使用大写12表示从0到23的小时。

    链接: ThreeTen backport Home