繁体   English   中英

Java SimpleDateFormat.format() 在使用毫秒时返回错误的日期

[英]Java SimpleDateFormat.format() returns incorrect date when using miliseconds

我想将日期字符串从“2016-09-23T09:14:52.555000000”格式解析为“23-SEP-2016”格式。

这是我的代码:

public class Tester {

    public static void main(String[] args) {
        System.out.println(displayDate("2016-09-23T09:14:52.555000000"));
        System.out.println(displayDate("2016-09-28T11:56:24.552000000"));
        System.out.println(displayDate("2016-09-23T09:29:12.507000000"));
        System.out.println(displayDate("2016-09-26T14:55:02.702000000"));
        System.out.println(displayDate("2016-09-26T09:50:24.880000000"));
        System.out.println(displayDate("2016-09-26T15:20:49.397000000"));
        System.out.println(displayDate("2016-09-26T15:21:21.559000000"));
    }

    public static String displayDate(String dateString) {
        String formattedDateString = "NA";

        if(dateString == null) {
            return formattedDateString;
        }

        SimpleDateFormat oracleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'kk:mm:ss.S");
        SimpleDateFormat dateFormatToDisplay = new SimpleDateFormat("dd-MMM-yyyy");

        try {
            Date date = oracleDateFormat.parse(dateString);
            formattedDateString = dateFormatToDisplay.format(date).toUpperCase();
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return formattedDateString;
    }

}

问题是如果我使用这条线

SimpleDateFormat oracleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'kk:mm:ss.S");

输出是(不正确的日期值):

29-SEP-2016
04-OCT-2016
29-SEP-2016
04-OCT-2016
06-OCT-2016
01-OCT-2016
03-OCT-2016

而如果使用这条线

SimpleDateFormat oracleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'kk:mm:ss");

输出是(正确的日期值

23-SEP-2016
28-SEP-2016
23-SEP-2016
26-SEP-2016
26-SEP-2016
26-SEP-2016
26-SEP-2016

我想知道为什么在格式字符串中添加“S(毫秒)”会导致不正确的值。

编辑1:

甚至"yyyy-MM-dd'T'kk:mm:ss.SSS" 也会返回不正确的值。

编辑2:

我在 Android 应用程序中使用此代码。 它在模拟器(API 23)上完美运行。 对于某些设备,它显示不正确的日期。 它会与Java版本有关吗?

特尔;博士:

在 Java 中,它不是几分之一秒,而是几毫秒。 不要让它大于 999。

更改Oracle 中的日期格式以包含FF3以表示秒的小数部分以产生毫秒。

说明

在 Java 中,日期格式中的SSSS代表毫秒,即数千秒。 一秒只有一千毫秒。

Oracle 中,日期格式不指定毫秒,而是指定几分之一秒。

FF [1..9]
小数秒; 不打印基数字符。 使用 X 格式元素添加基数字符。 使用 FF 后的数字 1 到 9 指定返回的日期时间值的小数秒部分中的位数。 如果不指定数字,则 Oracle 数据库使用为日期时间数据类型指定的精度或数据类型的默认精度。 在时间戳和间隔格式中有效,但在 DATE 格式中无效。

在 Java 中,如果您需要三分之一秒,则不能比 333 毫秒更精确。 但是,在 Oracle 中,您可以将其表示为 333333 微秒,甚至可能是 333333333 纳秒。

Oracle 允许您指定所需的小数位数,但如果不指定,您将获得该类型允许的精度。 在你的情况下,这似乎是 9。
然后您在 Java 中的日期格式将其解释为毫秒数。 其中数以百万计。 这些将添加到您约会的其余时间。 由于一天只有 86,400,000 毫秒,任何超过这一天的时间都会被添加到您的日期中。

示例

让我们看一下您的第一个测试用例2016-09-23T09:14:52.555000000
555000000 毫秒 = 555000 秒 ≈ 154 小时 ≈ 6 天 10 小时。
将日期的剩余时间(即 2016-09-23 09:14:52)增加 6 天 10 小时,应该会让您回到 2016-09-29 19:00 左右。 更改您的输出格式 ( dateFormatToDisplay ) 以包含小时数,您将看到发生了什么。

修复

您的 Java 日期格式要求毫秒数不超过 3 位。 指定 Oracle 中的小数位数。 FF使用该类型可用的最大精度, FF3仅输出 3 个小数位 - 毫秒。
如果您无法更改 Oracle 中使用的日期格式,请在 Java 中将其修剪为三位十进制数字。 请注意,任何小于3 位的数字都应用零填充至 3 位长度; 34.12 被解释为 34 秒和12毫秒,而您可能正在寻找 120 毫秒。

谜底在于对S说明符的正确解释。

SimpleDateFormat 中,在日期和时间模式部分, S的定义指出:

S毫秒

它在某些方面让你觉得很奇怪吗? 没有?! 这也让我感到惊讶,所以让我用消极的方式来形容它:

不是秒的小数部分,而是毫秒

还是不明白? 我的意思是字面上的毫秒数。

就像在:

  SimpleDateFormat oracleDateFormat = 
    new SimpleDateFormat("yyyy-MM-dd'T'kk:mm:ss.S");
  SimpleDateFormat dateFormatToDisplay = 
    new SimpleDateFormat("dd-MMM-yyyy--HH:mm:ss.SSS");

  Date d=oracleDateFormat.parse("2016-09-23T09:14:52.1");
  System.out.println(dateFormatToDisplay.format(d));

将导致...... waaait for it...... boom-tshhh ...

“2016-09-23--09:14:52. 001

对的人! “一毫秒”而不是“十分之一秒”。

那么,如果我们增加点后的位数,结果会不会一样呢? 当然可以。

  d=oracleDateFormat.parse("2016-09-23T09:14:52.1000");
  System.out.println(dateFormatToDisplay.format(d));

“2016-09-23--09:14:5 3.000

因此,如果您输入T09:14:53.555000000您只需将555 millions of milliseconds添加到您的基准时间或555000整秒。 这意味着比您的基准时间多出 6 天 10 小时 11 分钟。

似乎当您添加“S”时,解析器会添加所有毫秒,例如“555000000”至今。 当您进行计算(555000000 ms ~ 6,4d)时,它会匹配结果(日期不正确)。

您应该使用“yyyy-MM-dd HH:mm:ss.SSS”,但也要将“2016-09-23T09:14:52.555000000”修剪为“2016-09-23T09:14:52.555”,例如:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
sdf.parse("2016-09-23T09:14:52.555000000".substring(0,23));

毫秒应仅以 3 位数字表示。 将代码更改为:

    System.out.println(displayDate("2016-09-23T09:14:52.555"));
    System.out.println(displayDate("2016-09-28T11:56:24.552"));
    System.out.println(displayDate("2016-09-23T09:29:12.507"));
    System.out.println(displayDate("2016-09-26T14:55:02.702"));
    System.out.println(displayDate("2016-09-26T09:50:24.880"));
    System.out.println(displayDate("2016-09-26T15:20:49.397"));
    System.out.println(displayDate("2016-09-26T15:21:21.559"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM