【问题标题】:Parsing both dd-MM-yyyy and yyyy-MM-dd to Date type in Java?将 dd-MM-yyyy 和 yyyy-MM-dd 解析为 Java 中的日期类型?
【发布时间】:2020-06-22 00:14:03
【问题描述】:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;

public class demo {
    public static void main(String args[]) throws ParseException {
        
      DateFormat date=new SimpleDateFormat("yyyy-MM-dd",Locale.ENGLISH);
      System.out.println(date.parse("18-09-2017")); //Doesn't give an error but output is incorrect
      System.out.println(date.parse("2017-09-18"));  //Output is correct.
    }
}

如何以不同的方式解析两个包含日期的字符串。 注意:我需要 java.util.Date 类型的 parse 输出。

【问题讨论】:

  • 所以你需要单独的格式化程序,你可以尝试用一个解析然后输入字符串,它失败了,使用另一个
  • date.parse(...) 对两者都适用。它不会给出任何错误,但输出不正确。问题是这个解析器不会失败。如果是这样,我可以用 catch 块中的其他格式化程序解析它,但它不会失败。但是输出不正确。
  • 如果您“绝对,必须,毫无疑问”使用 Java 7 或更低版本,那么您可以使用 date.setLenient(false); 强制格式化程序对其解析过程更加严格

标签: java datetime simpledateformat date-format date


【解决方案1】:

tl;博士

getting a LocalDate 之后,转换为一个java.util.Date 对象,以UTC 格式表示该日期当天的第一个时刻,以满足您对java.util.Date 对象作为最终结果的要求。

java.util.Date
.from( 
    myLocalDate
    .atStartOfDay( ZoneOffset.UTC )
    .toInstant() 
)

详情

Answer by MadProgrammer 是正确的,您应该使用 java.time 类来处理所有新代码进行日期时间处理。这些现代类是对与 Java 的最早版本捆绑在一起的糟糕的日期时间类的巨大改进。随着 JSR 310 的采用,旧的类已经过时了 legacy

从现代 java.time 类转换为旧类

因此,您的问题需要java.util.Date。为了与尚未更新到 java.time 的旧代码进行互操作,旧类已通过转换方法进行了改造。

java.time.LocalDate 替换的旧类型是 java.sql.Date - 请注意中间的 sql 与您要求的 util

java.sql.Date javaSqlDate = java.sql.Date.valueOf( myLocalDate ) ;

不幸的是,您想要的 java.util.Date 对象不是直接合适的。该类代表一个时刻,一个以 UTC 格式显示的带有时间的日期。仅日期就没有时间,也没有时区或与 UTC 的偏移量。所以,方钉,圆孔。

一种解决方法是使用 UTC 中该日期的第一刻。

Instant instant = myLocalDate.atStartOfDay( ZoneOffset.UTC ).toInstant() ; // First moment of the day on that date as seen in UTC. 
java.util.Date d = java.util.Date.from( instant ) ;


关于java.time

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

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

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

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

从哪里获取 java.time 类?

【讨论】:

    【解决方案2】:

    如何以不同的方式解析两个包含日期的字符串。

    您确实应该为您需要的每种模式使用单独的格式化程序。既然是 2020 年,你真的应该使用 Java 8 中引入的java.time.* API,如果你不能使用 Java 8,你应该使用 back port 项目。

    例如:

    import java.time.LocalDate;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeParseException;
    
    public class Test {
    
        public static void main(String[] args) {
            String input1 = "18-09-2017";
            String input2 = "2017-09-18";
    
            System.out.println(QuickFormatter.parseDate(input1));
            System.out.println(QuickFormatter.parseDate(input2));
        }
    
        public static class QuickFormatter {
    
            static DateTimeFormatter pattern1 = DateTimeFormatter.ofPattern("dd-MM-yyyy");
            static DateTimeFormatter pattern2 = DateTimeFormatter.ISO_LOCAL_DATE; // yyyy-MM-dd
    
            public static LocalDate parseDate(String input) {
                try {
                    LocalDate ld = LocalDate.parse(input, pattern1);
                    return ld;
                } catch (DateTimeParseException exp) {
                    System.err.println("Failed to parse input using firstpattern");
                    try {
                        LocalDate ld = LocalDate.parse(input, pattern2);
                    return ld;
                    } catch (DateTimeParseException exp2) {
                        System.err.println("Failed to parse input using second pattern");
                    }
                }
                return null;
            }
        }
    }
    

    可以轻松修改它以使用数组或 List 来维护您支持的模式或将它们作为参数传递给 parseDate 方法 - 这只是这个想法的一个示例

    【讨论】:

    • 但我需要 java.util.Date 类型的日期。实现这一点意味着我必须对我的项目进行大量更改。
    • @HARSHITDANG 了解java.util.Date 及其支持类(包括Calendar)被视为“软性弃用” - 强烈建议您停止使用它们并开始进行更改以支持@ 987654328@ API - 自 Java 8 于 2014 年发布以来 - 真的没有理由不这样做 - 只是说
    • @HARSHITDANG 为了解决您问题的java.util.Date 部分,我添加了my Answer 作为此正确答案的续集。
    【解决方案3】:

    java.time.LocalDate

    您可以使用 Java 8+ Time API 轻松完成此操作,因为 DateTimeFormatter 支持在模式中使用 [...] 的可选部分。

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[dd-MM-yyyy][yyyy-MM-dd]");
    System.out.println(LocalDate.parse("21-06-2020", formatter));
    System.out.println(LocalDate.parse("2020-06-21", formatter));
    

    输出

    2020-06-21
    2020-06-21
    

    java.util.Date 使用 java.sql.Date

    如果需要java.util.Date,可以使用java.sql.Date子类中valueOf(LocalDate)方法中的helper方法:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[dd-MM-yyyy][yyyy-MM-dd]");
    java.util.Date date1 = java.sql.Date.valueOf(LocalDate.parse("21-06-2020", formatter));
    java.util.Date date2 = java.sql.Date.valueOf(LocalDate.parse("2020-06-21", formatter));
    System.out.println(date1);
    System.out.println(date2);
    

    同样的输出。


    普通 java.util.Date

    如果你不喜欢使用java.sql.Date,逻辑会变得有点复杂,所以我建议使用辅助方法。

    static java.util.Date parseDate(String date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[dd-MM-yyyy][yyyy-MM-dd]");
        LocalDate localDate = LocalDate.parse(date, formatter);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return java.util.Date.from(zonedDateTime.toInstant());
    }
    

    或作为单个语句:

    static Date parseDate(String date) {
        return Date.from(LocalDate.parse(date, DateTimeFormatter.ofPattern("[dd-MM-yyyy][yyyy-MM-dd]"))
                                  .atStartOfDay(ZoneId.systemDefault())
                                  .toInstant());
    }
    

    测试

    System.out.println(parseDate("21-06-2020"));
    System.out.println(parseDate("2020-06-21"));
    

    输出

    Sun Jun 21 00:00:00 EDT 2020
    Sun Jun 21 00:00:00 EDT 2020
    

    【讨论】:

    • 因为当您预先知道格式时,这很整洁
    • 我希望在最后一部分有所不同:如果您需要 java.util.Date 用于旧版 API,则不应选择 java.sql.Date。它可能有效,但这不是该类的用途。否则一个很好的答案。
    • @OleV.V.好的,我会答应你的。添加了替代答案。
    【解决方案4】:

    您不需要为每个模式定义单独的格式化程序。您可以使用DateTimeFormatterBuilder 将两种模式包含在一个格式化程序中。

    import java.time.LocalDate;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeFormatterBuilder;
    
    public class Main {
        public static void main(String[] args) {
            DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                                        .appendPattern("[yyyy-MM-dd]")
                                        .appendPattern("[dd-MM-yyyy]")
                                        .toFormatter();
    
            LocalDate date1 = LocalDate.parse("18-09-2017", formatter);
            LocalDate date2 = LocalDate.parse("2017-09-18", formatter);
    
            System.out.println(date1);
            System.out.println(date2);
        }
    }
    

    输出:

    2017-09-18
    2017-09-18
    

    您应该停止使用 java.util 包中过时且容易出错的日期时间 API,并开始使用 java.time 包及其子包中的 modern date-time API

    【讨论】:

      猜你喜欢
      • 2017-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-02
      • 1970-01-01
      • 2018-03-31
      • 2014-05-30
      • 2023-03-26
      相关资源
      最近更新 更多