【问题标题】:Convert date string from ISO 8601 format to another将日期字符串从 ISO 8601 格式转换为另一种格式
【发布时间】:2014-04-09 18:32:43
【问题描述】:

我有这段代码,我试图将日期字符串从一种格式转换为另一种格式,最后我再次想要日期对象。

            String dateString = "2014-10-04";
    SimpleDateFormat oldFormatter = new SimpleDateFormat("yyyy-MM-dd");
    Date parsedDate = oldFormatter.parse(dateString);
    SimpleDateFormat newFormatter = new SimpleDateFormat("dd-MMM-yyyy");
    String convertDateStr = newFormatter.format(parsedDate);
    Date convertedDate = newFormatter.parse(convertDateStr);

当我使用 dateString 值为“2014-10-04”测试上面的代码时,上面的代码可以正确执行,但 convertDate 格式更改为“Sat Oct 04 00:00:00 IST 2014”而不是“dd-MMM -yyyy" 格式。

我的功能就像我有两个不同格式的日期,并且需要在比较时获得剩余天数的差异,所以我需要在获得天数差异之前将一种日期格式转换为另一种日期。

编辑 - 是否有替代选项将日期字符串转换为指定格式并返回转换格式的日期对象

【问题讨论】:

  • 你应该先看清楚我的问题,不是解析日期,而是解析后如何保留日期格式
  • 实际上你问了多个问题:如何将字符串解析为日期时间,如何将日期时间格式化为字符串,为什么 j.u.Date 以替代格式打印,如何计算日期时间值之间的天数。所有这些都是重复的,在 StackOverflow 上被多次询问和回答。尽管如此,我还是发布了一个答案,作为几个不同事物的地图,以检查程序员何时不熟悉日期时间。

标签: java simpledateformat


【解决方案1】:

tl;博士

LocalDate.parse(            // Represent a date-only value with a date-only class.
    "2014-10-04"            // Inputs in standard ISO 8601 format are parsed by default. No need to specify a formatting pattern.
)                           // Returns a `LocalDate` object. Do not conflate a date-time object with a String that represents its value. A `LocalDate` has no “format”.
.format(                    // Generate a String representing the `LocalDate` object’s value. 
    DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US )  // Define your custom formatting pattern. Specify `Locale` for human language and cultural norms used in localization.
)                           // Return a String.

java.time

现代方法使用 java.time 类取代了麻烦的旧旧日期时间类,例如 Date/Calendar/SimpleDateFormat

对仅日期值使用仅日期类,而不是日期+时间类。 LocalDate 类表示没有时间和时区的仅日期值。

您的输入字符串恰好符合标准 ISO 8601 格式。 java.time 类在解析/生成字符串时默认使用 ISO 8601 格式。所以不需要指定格式模式。

String input  = "2014-10-04" ;
LocalDate ld = LocalDate.parse( input ) ;  // No need to specify a formatting pattern for ISO 8601 inputs.

要以特定格式生成表示 LocalDate 对象值的字符串,请定义格式化模式。指定 Locale 对象以确定本地化中使用的人类语言和文化规范。

Locale locale = Locale.US ; 
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , locale ) ;
String output = ld.format( f ) ;

2014 年 10 月 4 日


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

  • Java SE 8Java SE 9 及更高版本
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实现。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6Java SE 7
  • Android
    • java.time 类的 Android 捆绑包实现的更高版本。
    • 对于早期的 Android (ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案2】:

    Date 对象没有内置格式,SimpleDateFormat 就是这样做的。 当您将 convertDateStr 转换回 Date 对象时,您已经丢失了格式。

    在你的代码块之后运行这些,你就会明白我的意思了。

        System.out.println(convertedDate);
        System.out.println(newFormatter.format(convertedDate));
    

    【讨论】:

      【解决方案3】:

      Date 对象不存储日期格式。您看到的输出只是其toString 方法的结果。如果您想要特定格式的日期,则必须始终使用格式化程序以您想要的格式获取日期的字符串版本。

      【讨论】:

        【解决方案4】:
        You can use this
        
            public static Date getDateFromString(String format, String dateStr) {
        
                DateFormat formatter = new SimpleDateFormat(format);
                Date date = null;
                try {
                    date = (Date) formatter.parse(dateStr);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
        
                return date;
            }
        
            public static String getDate(Date date, String dateFormat) {
                DateFormat formatter = new SimpleDateFormat(dateFormat);
                return formatter.format(date);
            }
        

        【讨论】:

          【解决方案5】:

          乔达时间

          更新:Joda-Time 项目现在位于maintenance mode,团队建议迁移到java.time 类。这个答案原封不动地留给历史。

          正如correct answer by forgivenson许多中所解释的,通过在 StackOverflow 中搜索“java 日期格式”或“java 日期解析”等找到的其他问题和答案:

          • java.util.Date 对象没有格式。 j.u.Date 不是文本。 j.u.Date 不包含字符串。 j.u.Date 对象包含自 Unix 纪元以来的毫秒数(忽略闰秒)。
          • 您可以通过调用 toString 实现或使用格式化程序生成 java.util.Date 的日期时间值的字符串表示形式。
          • java.util.Date 的toString 方法令人困惑,因为它应用了JVM 的默认时区。结果表明 j.u.Date 有一个时区,而实际上它没有。
          • java.util.Date 和 .Calendar 类是出了名的麻烦。避开他们。使用不错的日期时间库,例如 Joda-Time 或 Java 8 中捆绑的新 java.time 包。
          • 您的代码忽略了时区的关键问题。 java.util.Date 有日期和时间,因此您需要注意时区。
          • Joda-Time 和 java.time 都使用ISO 8601 标准定义的格式作为默认格式。您也可以定义自己的格式,或使用本地化格式。

          因此,您的短语“使用转换后的格式返回日期对象”是矛盾的。日期时间对象(无论是 java.util.Date 还是 Joda-Time 还是 java.time)没有格式。您将 from 日期时间对象与日期时间对象本身生成的字符串表示混淆了。

          使用 Joda-Time 2.3 的示例代码…

          String input = "2014-10-04";
          
          DateTimeZone timeZoneIndia = DateTimeZone.forID( "Asia/Kolkata" );
          DateTime dateTimeIndia = new DateTime( input, timeZoneIndia ); // Defaults to beginning of the day.
          DateTime dateTimeUtc = dateTimeIndia.withZone( DateTimeZone.UTC );
          DateTime octoberSecond = new DateTime( 2014, 10, 2, 1, 2, 3, timeZoneIndia ).withTimeAtStartOfDay();
          
          DateTimeFormatter formatter_Iso = ISODateTimeFormat.date();
          String dateTimeIndiaAsStringIso = formatter_Iso.print( dateTimeIndia );
          
          DateTimeFormatter formatter_Dmy = DateTimeFormat.forPattern( "dd-MM-yyyy" );
          String dateTimeIndiaAsStringDmy = formatter_Dmy.print( dateTimeIndia );
          DateTime dateTimeAgain = formatter_Dmy.withZone( timeZoneIndia ).parseDateTime( dateTimeIndiaAsStringDmy ); // Defaults to beginning of the day.
          
          DateTimeFormatter formatter_Québécois = DateTimeFormat.forStyle( "FF" ).withLocale( Locale.CANADA_FRENCH );
          String dateTimeIndiaAsStringQuébécois = formatter_Québécois.print( dateTimeIndia );
          
          int daysBetween = Days.daysBetween( octoberSecond, dateTimeIndia ).getDays();
          Interval interval = new Interval( octoberSecond, dateTimeIndia );
          Period period = interval.toPeriod();
          
          java.util.Date date = dateTimeIndia.toDate();
          
          input: 2014-10-04
          dateTimeIndia: 2014-10-04T00:00:00.000+05:30
          dateTimeUtc: 2014-10-03T18:30:00.000Z
          octoberSecond: 2014-10-02T00:00:00.000+05:30
          dateTimeIndiaAsStringIso: 2014-10-04
          dateTimeIndiaAsStringDmy: 04-10-2014
          dateTimeAgain: 2014-10-04T00:00:00.000+05:30
          dateTimeIndiaAsStringQuébécois: samedi 4 octobre 2014 0 h 00 IST
          daysBetween: 2
          interval: 2014-10-02T00:00:00.000+05:30/2014-10-04T00:00:00.000+05:30
          period: P2D
          date: Fri Oct 03 11:30:00 PDT 2014
          

          转储到控制台...

          System.out.println( "input: " + input );
          System.out.println( "dateTimeIndia: " + dateTimeIndia );
          System.out.println( "dateTimeUtc: " + dateTimeUtc );
          System.out.println( "octoberSecond: " + octoberSecond );
          System.out.println( "dateTimeIndiaAsStringIso: " + dateTimeIndiaAsStringIso );
          System.out.println( "dateTimeIndiaAsStringDmy: " + dateTimeIndiaAsStringDmy );
          System.out.println( "dateTimeAgain: " + dateTimeAgain );
          System.out.println( "dateTimeIndiaAsStringQuébécois: " + dateTimeIndiaAsStringQuébécois );
          System.out.println( "daysBetween: " + daysBetween );
          System.out.println( "interval: " + interval );
          System.out.println( "period: " + period );
          System.out.println( "date: " + date );  // Applies JVM's default time zone. North America west coast time zone in my case.
          

          运行时……

          input: 2014-10-04
          dateTimeIndia: 2014-10-04T00:00:00.000+05:30
          dateTimeUtc: 2014-10-03T18:30:00.000Z
          octoberSecond: 2014-10-02T00:00:00.000+05:30
          dateTimeIndiaAsStringIso: 2014-10-04
          dateTimeIndiaAsStringDmy: 04-10-2014
          dateTimeAgain: 2014-10-04T00:00:00.000+05:30
          dateTimeIndiaAsStringQuébécois: samedi 4 octobre 2014 0 h 00 IST
          daysBetween: 2
          interval: 2014-10-02T00:00:00.000+05:30/2014-10-04T00:00:00.000+05:30
          period: P2D
          date: Fri Oct 03 11:30:00 PDT 2014
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-07-27
            • 1970-01-01
            • 1970-01-01
            • 2015-11-16
            • 1970-01-01
            相关资源
            最近更新 更多