使用miliseconds时,Java SimpleDateFormat.format()返回不正确的日期

时间:2016-09-29 07:34:09

标签: java android date datetime

我想将“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(毫秒)”会导致错误的值。

Edit1:

即使“yyyy-MM-dd'T'kk:mm:ss.SSS”也会返回错误的值。

Edit2:

我在Android App中使用此代码。它在仿真器(API 23)上完美运行。对于某些设备,它显示错误的日期。它可以与Java版本相关吗?

5 个答案:

答案 0 :(得分:3)

TL; DR:

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

在Oracle 中更改日期格式,以包含FF3的秒数,以获得毫秒数。

说明

在Java中,日期格式中的S或更确切地说SSS代表毫秒,即数千秒。一秒钟内只有几毫秒。

Oracle中,日期格式不指定毫秒,而是指定秒数。

  

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

在Java中,如果需要三分之一秒,则无法获得超过333毫秒的精确度。但是在Oracle中,您可以将其表示为333333微秒,甚至可能是333333333纳秒。

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

实施例

让我们来看看你的第一个测试用例2016-09-23T09:14:52.555000000 555000000毫秒= 555000秒≈154小时≈6天10小时 在你的约会剩余时间里加上6天10小时,即2016-09-23 09:14:52,应该会让你大约在2016-09-26 19:00和一点点。更改输出格式(dateFormatToDisplay)以包含小时数,您将看到发生了什么。

修复

您的Java日期格式预计毫秒不超过3位数。指定Oracle中的小数位数。 FF使用该类型可用的最大精度,FF3仅输出3个小数位 - 毫秒。
如果您无法更改Oracle中使用的日期格式,请将其减少到Java中的三位小数。请注意,任何 less 小于3位的内容都应填充零,长度为三位数; 34.12被解释为34秒而 12 毫秒,而你可能正在寻找120毫秒。

答案 1 :(得分:3)

这个谜团保留在S说明符的正确解释中。

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

  

S毫秒

它在某种程度上会让你觉得奇怪吗?没有?!这也让我感到意外,所以让我以消极的方式说出来:

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

仍然没有得到它?我的意思是 literaly 毫秒数。

喜欢在:

  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));

将导致...等待它...繁荣 - 嗯......

  

" 2016-09-23--09:14:52的 001 "

那是对的人! "一毫秒"不是"和十分之一秒#34;。

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

  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分钟。

答案 2 :(得分:1)

当你添加' 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 :(得分:0)

毫秒应仅以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"));

答案 4 :(得分:-1)

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");