Java英文日期格式解析

时间:2016-08-29 16:37:46

标签: java

我的问题如下。我正在读一个文件,它包含一堆CSV行。每行包含一些格式为22-mar-2010或类似的日期,即格式为dd-MMM-yyyy。我想将其转换为ISO格式,因此它变为2010-03-22

我的代码如下:

  private String convertDate(String date) {
    DateTimeFormatter oldFormat = DateTimeFormatter.ofPattern("dd-MMM-yyyy", new Locale("en"));
    LocalDate parsedDate = LocalDate.parse(date, oldFormat);

    DateTimeFormatter newFormat = DateTimeFormatter.ISO_DATE;
    String newDate = parsedDate.format(newFormat);
    return newDate;
  }

输入看起来像这样:

sdfdsfslk 28-mar-2007 dfdsljs
sdfdsfslk 20-apr-2014 dfdsljs
sdfdsfslk 13-oct-2005 dfdsljs
sdfdsfslk 20-may-2014 dfdsljs
sdfdsfslk 20-jan-2014 dfdsljs
sdfdsfslk 20-feb-2014 dfdsljs

如果包含上述语言环境或使用withLocale(Locale.ENGLISH),则在第一行日期字符串处失败。例外是:

java.time.format.DateTimeParseException: Text '28-mar-2007' could not be parsed at index 3

如果我删除了语言环境部分并且只有:

DateTimeFormatter.ofPattern("dd-MMM-yyyy");

然后它会工作,直到遇到13-oct-2005之类的日期。它不喜欢英语'oct'而在LocalDate.parse行失败。如果我将oct转换为okt(瑞典语,我在哪里),那么它会解析它。

我是否需要完全更改我的语言环境或这里出了什么问题?即使我在瑞典,我怎样才能用英语解析几个月的日期?

3 个答案:

答案 0 :(得分:6)

我认为问题是本月的第一个字母是小写。 当您为navigator.userAgent而不是28-Mar-2007运行相同的代码时,一切正常。

一个快速而肮脏的解决方案是:

28-mar-2007

答案 1 :(得分:4)

TL;博士

LocalDate.parse ( 
    "13-oct-2005" , 
    new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .appendPattern( "dd-MMM-uuuu" )
        .toFormatter( Locale.US ) 
)

详细

Answer by Plirkee是正确的:英语语言环境期望缩写的月份名称具有首字母大写字母(大写)。

DateTimeFormatterBuilder

鉴于这个错误的输入数据,一个更简单的解决方法是构建一个不区分大小写的格式化程序。 DateTimeFormatterBuilder类使您可以使用纯格式代码字符串模式构建更精细的自定义格式化程序。

包括DateTimeFormatterDateTimeFormatterBuilder的java.time类是线程安全的。因此,您可以保留一个实例以供重复使用。

Builder 模式

如果不熟悉,请阅读Builder design pattern。不是使用多个参数调用构造函数,而是使用各种方法的调用链构造一个Builder对象以满足您的需要。最后,要求Builder实例化您真正想要的对象,在这种情况下为DateTimeFormatter

.parseCaseInsensitive()

我们需要的技巧是调用.parseCaseInsensitive()。您可以通过使用省略此调用的注释掉的行进行交换来验证此调用是否是关键因素。

//  DateTimeFormatterBuilder fbuilder = new DateTimeFormatterBuilder ().appendPattern ( "dd-MMM-uuuu" );  // Case-sensitive by default.
DateTimeFormatterBuilder fbuilder = new DateTimeFormatterBuilder ().parseCaseInsensitive ().appendPattern ( "dd-MMM-uuuu" );  // Case-insensitive to handle improper English.

String input = "13-oct-2005"; // Incorrect English. Should be uppercase 'Oct'.
DateTimeFormatter f = fbuilder.toFormatter ( Locale.US );
LocalDate ld = LocalDate.parse ( input , f );
  

ld.toString()→2005-10-13

ISO 8601

提示:在将日期时间值作为文本进行交换时,请始终使用标准ISO 8601格式,而不是设计自己的时髦格式,例如问题中所示的格式。在解析/生成字符串时, java.time 类默认使用这些标准格式。

答案 2 :(得分:0)

private static String convertDate(String daterec) {
        String date = daterec;
        String firstLetter = date.substring(0,4).toUpperCase();
        String restLetters = date.substring(4).toLowerCase();
        date = firstLetter+restLetters;
        DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd-MMM-yyyy", new Locale("en"));
        LocalDate lds = LocalDate.parse((date), dTF);
    return lds.toString();
  }

输出与接受的答案相同:

2007-03-28
2014-04-20
2005-10-13
2007-03-28
2014-01-20
2014-02-20

正如已经说过的那样,我们需要保留格式,尽管可以避免的代码可以忽略不计2行,因为我们传递的是'dd-MMM-yyyy',这也意味着ISO标准,所以我很晚才发布少一点代码