Java 使用SimpleDataFormat进行不正确的日期分析

Java 使用SimpleDataFormat进行不正确的日期分析,java,date,simpledateformat,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 (`

我有一个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(另外,我不能修改DB)

在我的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());

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

尝试
HH:mm:ss
hh
用于“上午/下午(1-12)的小时数”,时间部分请参见。

Try
hh:mm:ss
<代码>hh用于“上午/下午(1-12)时的小时数”,请参阅

  • 在数据库中使用
    时间戳
    数据类型,而不是日期和时间的单独列。MySQL时间戳是UTC格式的,因此应该避免数据库端的任何时区问题
  • 使用
    java.time
    ,现代java日期和时间API。像
    date
    这样的旧日期和时间类设计得很糟糕,尤其是
    SimpleDateFormat
    是出了名的麻烦,所以要避免它
  • 在Java程序和数据库之间传输日期时间对象,而不是字符串
  • 阅读更多。如果你不能做到这一切,就尽你所能去做

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

    Instant departVol = rs.getObject(DEPART_INSTANT_VOL, Instant.class);
    
    如果无法更改
    addon.setDateDeeption()
    接受的类型,请将其转换为
    Date
    ,如下所示:

    addon.setDateDepart(Date.from(departVol));
    
    或者在使用Three-Ten Backport的版本中,
    java.time
    到java 6和7的Backport:

    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);
    
    转换成老式的日期是不可靠的,因为正如你所说,可能存在时区问题。尝试:

    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我还没有测试我的代码片段。如果有错别字,您自己无法修复,请回复

    你的代码出了什么问题? 格式模式字符串中的小写字母
    hh
    表示从1到12的AM或PM的小时数。所以
    12:20:00
    的意思是
    00:20:00
    。要在24小时时钟上解释
    12
    ,请使用大写的
    HH
    表示从0到23的小时

    链接:

  • 在数据库中使用
    时间戳
    数据类型,而不是日期和时间的单独列。MySQL时间戳是UTC格式的,因此应该避免数据库端的任何时区问题
  • 使用
    java.time
    ,现代java日期和时间API。像
    date
    这样的旧日期和时间类设计得很糟糕,尤其是
    SimpleDateFormat
    是出了名的麻烦,所以要避免它
  • 在Java程序和数据库之间传输日期时间对象,而不是字符串
  • 阅读更多。如果你不能做到这一切,就尽你所能去做

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

    Instant departVol = rs.getObject(DEPART_INSTANT_VOL, Instant.class);
    
    如果无法更改
    addon.setDateDeeption()
    接受的类型,请将其转换为
    Date
    ,如下所示:

    addon.setDateDepart(Date.from(departVol));
    
    或者在使用Three-Ten Backport的版本中,
    java.time
    到java 6和7的Backport:

    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);
    
    转换成老式的日期是不可靠的,因为正如你所说,可能存在时区问题。尝试:

    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我还没有测试我的代码片段。如果有错别字,您自己无法修复,请回复

    你的代码出了什么问题? 格式模式字符串中的小写字母
    hh
    表示从1到12的AM或PM的小时数。所以
    12:20:00
    的意思是
    00:20:00
    。要在24小时时钟上解释
    12
    ,请使用大写的
    HH
    表示从0到23的小时


    链接:

    我建议您避免使用
    SimpleDataFormat
    类。它不仅早已过时,而且还出了名的麻烦。今天我们有了更好的功能。您使用的是
    hh
    ,这是一种基于12小时的时钟。使用
    kk
    代替24小时时钟。但是,是的,您应该尝试使用
    java.time
    。)在您的工作环境中,您使用的是来自Joda Time的
    LocalDateTime
    ?这已经比旧的Java日期和时间类好了,很难理解为什么会有这样的行为。我也很好奇。我想到的是同步,尽管代码中没有多个线程(应该怪DAO吗?)。日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一种格式,则必须在外部对其进行同步。我真的很想知道你的例子中是否有这种情况