【问题标题】:Parsing dates of the format "January 10th, 2010" in Java? (with ordinal indicators, st|nd|rd|th)在 Java 中解析格式“2010 年 1 月 10 日”的日期? (带序号指示符,st|nd|rd|th)
【发布时间】:2011-01-18 09:10:00
【问题描述】:

我需要在 Java 中解析格式为“2010 年 1 月 10 日”的日期。我该怎么做?

如何处理日期编号后面的ordinal indicatorsstndrdth

【问题讨论】:

  • 问题是“th”(大概是“rd”和“nd”),对吧?
  • 谢谢大家...它通过转义字符来工作。

标签: java date


【解决方案1】:

这行得通:

String s = "January 10th, 2010";
DateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy");
System.out.println("" + dateFormat.parse(s.replaceAll("(?:st|nd|rd|th),", "")));

但您需要确保使用正确的Locale 来正确解析月份名称。

我知道您可以在 SimpleDateFormat 模式中包含一般文本。但是在这种情况下,文本取决于信息,实际上与解析过程无关。

这实际上是我能想到的最简单的解决方案。但我很想被证明是错误的。

您可以通过执行类似以下操作来避免其中一个 cmets 中暴露的陷阱:

String s = "January 10th, 2010";
DateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy");
System.out.println("" + dateFormat.parse(s.replaceAll("(?<= \\d+)(?:st|nd|rd|th),(?= \\d+$)", "")));

这将允许您不匹配 Jath,uary 10 2010 例如。

【讨论】:

  • 我知道您可以在 SimpleDataFormat 模式中包含一般文本。但是在这种情况下,文本取决于信息,实际上与解析过程无关。我知道的最简单的解决方案是这个。但我很想被错误地展示出来。
  • 但也会接受"January th,10 2010","Janth,uary th,10 2010" 等,这可能不是我们想要的行为。
  • @michael 好吧。如果你想学究气,你可以稍微调整一下正则表达式来解决这个问题。这取决于您对输入数据的信任程度。
  • replaceAll 表达式的第二个版本略有损坏。首先,它在表达式的开头缺少一个括号,并且 \d 字符需要一个额外的反斜杠。我在上面修复了这个问题,但它仍然失败,因为通配符导致后视长度不固定。我的特殊情况是格式略有不同,所以我只用了一个前面的数字:dateStr.replaceAll("(?&lt;=\\d)(?:st|nd|rd|th)", "")
  • 仅供参考,诸如 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 等非常麻烦的日期时间类现在是 legacy,被 Java 8 及更高版本中内置的 java.time 类所取代.见Tutorial by Oracle
【解决方案2】:

我想提供现代答案。而不是今天两个投票最多的答案中使用的 SimpleDateFormat 类,您应该使用 java.time,现代 Java 日期和时间 API。它提供了几个不错的解决方案。

简单的解决方案

我们首先定义一个用于解析的格式化程序:

private static final DateTimeFormatter PARSING_FORMATTER = DateTimeFormatter.ofPattern(
        "MMMM d['st']['nd']['rd']['th'], uuuu", Locale.ENGLISH);

然后我们这样使用它:

    String dateString = "January 10th, 2010";
    LocalDate date = LocalDate.parse(dateString, PARSING_FORMATTER);
    System.out.println("Parsed date: " + date);

输出是:

解析日期:2010-01-10

格式模式字符串中的方括号[] 包含可选部分,单引号包含文字文本。所以d['st']['nd']['rd']['th'] 意味着在一个月的某一天之后可能有stndrd 和/或th

更多固溶体

上述方法的一些限制是

  1. 它接受任何序数指示符,例如10st 甚至10stndrdth
  2. 虽然格式化程序可用于解析,但您不能将其用于格式化(它会给出January 10stndrdth, 2010)。

如果您想要更好地验证序数指示符,或者您希望将日期格式化回字符串,您可以通过这种方式构建格式化程序:

private static final DateTimeFormatter FORMATTING_AND_PARSING_FORMATTER;
static {
    Map<Long, String> ordinalNumbers = new HashMap<>(42);
    ordinalNumbers.put(1L, "1st");
    ordinalNumbers.put(2L, "2nd");
    ordinalNumbers.put(3L, "3rd");
    ordinalNumbers.put(21L, "21st");
    ordinalNumbers.put(22L, "22nd");
    ordinalNumbers.put(23L, "23rd");
    ordinalNumbers.put(31L, "31st");
    for (long d = 1; d <= 31; d++) {
        ordinalNumbers.putIfAbsent(d, "" + d + "th");
    }

    FORMATTING_AND_PARSING_FORMATTER = new DateTimeFormatterBuilder()
            .appendPattern("MMMM ")
            .appendText(ChronoField.DAY_OF_MONTH, ordinalNumbers)
            .appendPattern(", uuuu")
            .toFormatter(Locale.ENGLISH);
}

这将解析与上面相同的日期字符串。让我们也试试它的格式:

    System.out.println("Formatted back using the same formatter: "
            + date.format(FORMATTING_AND_PARSING_FORMATTER));

使用相同的格式化程序重新格式化:2010 年 1 月 10 日

链接

【讨论】:

    【解决方案3】:

    您可以将nd 等设置为SimpleDateFormat 中的文字。您可以定义四种需要的格式并尝试它们。首先从th 开始,因为我猜这会更频繁地发生。如果 ParseException 失败,请尝试下一个。如果全部失败,则抛出 ParseException。这里的代码只是一个概念。在现实生活中,您可能不会每次都生成新的格式,并且可能会考虑线程安全。

    public static Date hoolaHoop(final String dateText) throws ParseException
            {
            ParseException pe=null;
            String[] sss={"th","nd","rd","st"};
            for (String special:sss)
            {
            SimpleDateFormat sdf=new SimpleDateFormat("MMMM d'"+special+",' yyyy");
            
            try{
            return sdf.parse(dateText);
            }
            catch (ParseException e)
            {
            // remember for throwing later 
            pe=e;
            }
            }
            throw pe;
            }
            public static void main (String[] args) throws java.lang.Exception
            {
             String[] dateText={"January 10th, 2010","January 1st, 2010","January 2nd, 2010",""};
             for (String dt:dateText) {System.out.println(hoolaHoop(dt))};
            }
    

    输出:

    2010 年 1 月 10 日星期日 00:00:00 GMT

    格林威治标准时间 2010 年 1 月 1 日星期五 00:00:00

    2010 年 1 月 2 日星期六 00:00:00 GMT

    线程“main”java.text.ParseException 中的异常:无法解析的日期:“”

    "th","nd","rd","st" 当然只适用于使用英语的语言环境。记在脑子里。在法国,我猜是"re","nd" 等等。

    【讨论】:

      【解决方案4】:

      这是另一种简单的方法,但需要包含 apache commons jar

      import org.apache.commons.lang.time.*;
      
      String s = "January 10th, 2010";
      String[] freakyFormat = {"MMM dd'st,' yyyy","MMM dd'nd,' yyyy","MMM dd'th,' yyyy","MMM dd'rd,' yyyy"};
      DateUtils du = new DateUtils();
      System.out.println("" + du.parseDate(s,freakyFormat));
      

      【讨论】:

        猜你喜欢
        • 2015-10-11
        • 1970-01-01
        • 1970-01-01
        • 2014-02-25
        • 2017-01-07
        • 1970-01-01
        • 2016-10-19
        • 2011-04-08
        • 2011-01-30
        相关资源
        最近更新 更多