Java SimpleDateFormat返回时间为12小时前的5.30到6.30之间

Java SimpleDateFormat返回时间为12小时前的5.30到6.30之间,java,postgresql,Java,Postgresql,我们正在使用SimpleDateFormat将日期时间转换为以毫秒为单位的时间 下面是我们用于转换的代码 下面是我从数据库中获取的日期时间格式 "2019-04-04 12:24:53.754787+00" 代码: 它以毫秒为单位返回正确的时间戳。除了下午5点30分至6点30分,它返回12小时延迟为什么返回错误的时间戳?或者用其他方法进行转换?正如Jon Skeet提到的,简单的日期格式也有点不合适。我已将-M-更改为-MM-,hh更改为hh。有关SimpleDataFormat的更多信息,

我们正在使用
SimpleDateFormat
将日期时间转换为以毫秒为单位的时间 下面是我们用于转换的代码

下面是我从数据库中获取的日期时间格式

"2019-04-04 12:24:53.754787+00" 
代码:


它以毫秒为单位返回正确的时间戳。除了下午5点30分至6点30分,它返回12小时延迟为什么返回错误的时间戳?或者用其他方法进行转换?

正如Jon Skeet提到的,简单的日期格式也有点不合适。我已将
-M-
更改为
-MM-
hh
更改为
hh
。有关SimpleDataFormat的更多信息,请访问。而且,时区可能会影响它

您还可以使用日历返回长时间

例如:

    String date = "2019-04-04 12:24:53.754787+00";

    private long getTime(String _date) {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        cal.setTimeZone(TimeZone.getTimeZone("Europe/Vienna"));
        try {
            cal.setTime(format.parse(_date));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        // First .getTime() returns Date, second returns long in millis.
        return cal.getTime().getTime(); 
    }

首先,不要将日期时间存储为PostgreSQL中的字符串,也不要从数据库中检索所显示的字符串。存储适当的日期/时间类型;在您的情况下,可能是带有时区的时间戳。而不是检索字符串,而是获取相应的Java datetime类型。例如:

    PreparedStatement select = yourDatabaseConnection
            .prepareStatement("select ts from your_table where id = 4;");
    ResultSet rs = select.executeQuery();
    if (rs.next()) {
        OffsetDateTime dateTime = rs.getObject("ts", OffsetDateTime.class);
        long milliseconds = dateTime.toInstant().toEpochMilli();
        // Do something with milliseconds
    }
(我没有测试这个代码段,因为我还没有安装PostgreSQL。)

如果出于某种原因,您无法避免获取字符串:

    DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSx");
    String stringFromDatabase = "2019-04-04 12:24:53.754787+00";
    OffsetDateTime dateTime
            = OffsetDateTime.parse(stringFromDatabase, formatter);
    long milliseconds = dateTime.toInstant().toEpochMilli();
    System.out.println(milliseconds);
这段代码我试过运行。输出为:

1554380693754

由于PostgreSQL存储的是微秒精度,而millisconds自大纪元以来显然不存储,因此我们丢失了原始值的最后三位小数

我正在使用并推荐java.time,这是一种现代的java日期和时间API。您尝试使用的datetime类--
SimpleDateFormat
Date
——早已过时,而且设计得很糟糕。所以要避免这些

你的代码出了什么问题?
  • 其他人已经指出,要解析字符串,您需要在从00到23的一天中的一小时内使用大写字母
    HH
    。小写的
    hh
    表示从01到12的上午或下午的小时。因为12 AM表示00,所以解析12小时会给出您观察到的错误结果,而其他小时值会起作用
  • 另一方面,在本例中,单个
    M
    并不重要,它在解析时与
    MM
    的作用相同(对于格式化,如果始终需要两个数字,则需要
    MM
    ,如您的示例字符串)
  • 您既没有解析秒的分数,也没有解析
    +00
    的UTC偏移量。尽管如此,如果您得到了一个大致正确的结果,那么您是幸运的,不应该指望其他计算机或具有其他默认设置的JVM会出现这种情况
链接
  • PostgreSQL
  • 来自PostgreSQL JDBC驱动程序文档
  • 解释如何使用java.time
  • 相关问题:

您正在为小时值指定
hh
,但尚未指定am/pm说明符。您几乎肯定希望使用
HH
。将
M
dd
一起使用也很奇怪。使用
yyyy-MM-dd HH:MM:ss
更为常见。我怀疑Santosh的说法是正确的,因为它具体在5:30到6:30之间。(您当前正在使用默认时区进行解析,这几乎肯定是不合适的。)但格式是另一个问题。我强烈建议您无论如何都要使用
java.time
。@JonSkeet虽然总体上更好,但使用java.time对这个特定问题没有影响。@kumesana:是的,它会影响-因为您可能会解析为
Instant
,它隐式使用UTC,这可能是正确的做法。为什么要将时间戳作为字符串检索?您应该使用
ResultSet.getObject(…,LocalDateTime.class)
从数据库中读取它。或者至少
ResultSet.getTimestamp()
日历的使用在这里是不相关的-主要的问题是格式,你没有提到它就纠正了它。@Jon Skeet你完全正确,它是不相关的,你是对的,我甚至没有提到格式。。谢谢
    DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSx");
    String stringFromDatabase = "2019-04-04 12:24:53.754787+00";
    OffsetDateTime dateTime
            = OffsetDateTime.parse(stringFromDatabase, formatter);
    long milliseconds = dateTime.toInstant().toEpochMilli();
    System.out.println(milliseconds);