【问题标题】:SimpleDateFormat adds random milliseconds while formatting to string [duplicate]SimpleDateFormat 在格式化字符串时添加随机毫秒 [重复]
【发布时间】:2020-06-24 19:35:51
【问题描述】:

我正在尝试使用 SimpleDateFormat 将日期格式化为 ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),但格式化的字符串似乎在毫秒位置。

import java.text.DateFormat;
import java.text.SimpleDateFormat;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;


public class DemoApplication {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
        calendar.set(2020, 5 , 22, 17, 30, 00);
        Date date = calendar.getTime();

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
        String s = df.format(date);
        System.out.println(s);
    }

}

多次运行的输出:

2020-06-22T17:30:00.886+0530

2020-06-22T17:30:00.049+0530

2020-06-22T17:30:00.799+0530

在上面的输出中,除了点(。)之后的毫秒之外,一切都是一致的,有人可以解释一下吗?

【问题讨论】:

  • 您使用 Java 的旧旧日期 API 而不是更好的 java.time,是否有特定原因?
  • @Zabuzard 没有具体原因,这是一个旧代码库,它试图通过在杰克逊的对象映射器中设置 dateFormat 来序列化日期字段。在编写测试用例时遇到了这个问题。
  • @ArvindKumarAvinash - 不同意。此问题的根本原因是 OP 使用了 Calendarset 方法,而没有清除/显式设置其 MILLISECOND 字段。
  • @AlexRudenko 一个(也许不是唯一的)根本原因是Calendar 有一个令人困惑的 API。我建议(至少在 java.time,2014 年 3 月之后)我们不再使用该类。我知道这个最小的例子是从旧代码派生的,可能是在 java.time 出现之前。 PS您链接到的原件是正确的。
  • @OleV.V.我很清楚并且完全同意 Date/Calendar 已经过时并且根本不需要使用。但是,当人们遇到遗留代码问题(OP 明确指出这一点)或一些学校教授过时的技术堆栈时,会有不同的情况。而且我相信在这种情况下提及/提及显然过时的解决方案来解决过时的问题并不是一种罪过,它比仅仅建议切换到新的和闪亮的东西要好:)

标签: java date


【解决方案1】:

在上面的输出中,除了毫秒之外,一切都是一致的 在点(。)之后,有人可以解释一下吗?

原因是你的格式有毫秒但你没有在Calendar实例中设置毫秒;因此,它会为您提供运行代码时的毫秒数。

您可以使用以下代码进行验证:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
        calendar.set(2020, 5, 22, 17, 30, 00);
        Date date = calendar.getTime();

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
        String s = df.format(date);
        System.out.println(s);
        System.out.println(date.toInstant().getNano()); // Added this line
    }
}

输出:

2020-06-22T17:30:00.425+0100
425000000

附带说明,我建议您停止使用过时的日期时间 API 并开始使用 modern date-time API

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        ZonedDateTime zdt = LocalDateTime.of(2020, 5, 22, 17, 30, 00).atZone(ZoneId.systemDefault());
        System.out.println(zdt);
    }
}

【讨论】:

    【解决方案2】:

    毫秒不包含在

    calendar.set(2020, 5 , 22, 17, 30, 00);
    

    你可以额外的 Line 将它们设置为 0:

    calendar.set(Calendar.MILLISECOND, 0);
    

    让你的程序看起来像这样:

    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    
    import java.util.Calendar;
    import java.util.Date;
    import java.util.TimeZone;
    
    
    public class DemoApplication {
    
        public static void main(String[] args) {
            Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
            calendar.set(2020, 5 , 22, 17, 30, 00);
            calendar.set(Calendar.MILLISECOND, 0);
            Date date = calendar.getTime();
    
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            String s = df.format(date);
            System.out.println(s);
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      JavaDocs of java.util.Calendar 为方法 getInstance() 声明以下内容:

      获取使用指定时区和默认语言环境的日历。返回的日历基于给定时区的当前时间,具有默认语言环境。

      这意味着您正在获取实际时刻,然后通过 calendar.set(2020, 5 , 22, 17, 30, 00); 您设置年、月、日、小时、分钟和秒,但您不会更改较小的时间单位,这些时间单位将保持与您调用 @ 时相同的状态987654325@。这不是随机的,而是在调用getInstance() 的那一刻的当前毫秒。

      有关将Calendar 的毫秒数设置为任何特定值的可能性,请查看@Norwort 给出的答案。

      我认为您不应该使用来自java.util 的过时日期时间类。相反,使用java.time,可能是这样的:

      public static void main(String[] args) throws ParseException {
          ZonedDateTime zonedDateTime = ZonedDateTime.of(2020, 5, 22, 17, 30, 0, 0,
                                                          ZoneId.systemDefault());
          DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
          String s = zonedDateTime.format(dtf);
          System.out.println(s);
      }
      

      打印出来的

      2020-05-22T17:30:00.000+0200
      

      在我的系统上执行时,此时偏移量为+02:00
      您系统上的输出可能会有所不同,但会将毫秒和更小的时间单位设置为 0。

      【讨论】:

        猜你喜欢
        • 2011-09-26
        • 2017-12-24
        • 2020-03-30
        • 2017-04-10
        • 2014-12-17
        • 2015-07-24
        • 2018-06-21
        • 2013-01-27
        • 2022-11-23
        相关资源
        最近更新 更多