2016-08-29 222 views
7

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

我的代码看起来是这样的:

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(瑞典语,我在哪里),那么它会解析它。

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

+0

总是涉及'Locale'。如果您没有明确指定'Locale',那么隐式应用您的JVM的当前默认语言环境。因此'okt'已成功解析,因为您的JVM的当前默认瑞典语区域设置是以您的名义应用的。 –

+0

是的,但问题是我提供了一个语言环境,但没有批准小写月份。因此,转换为大写到3月 –

+0

不,实际上问题是使用的传入日期(a)本月名称的英文不当,&(b)日期值的格式选择不当。作为解决方法,请参阅[我的答案](http://stackoverflow.com/a/39213129/642706),以制作不区分大小写的解析器来适应不正确的英语。并教育程序员关于[ISO 8601]的源数据(https://en.wikipedia.org/wiki/ISO_8601)。我上面的评论是为了解释为什么你删除'Locale'然后用瑞典语文本成功。隐含的瑞典语“Locale”期望小写月份名称,而英语期望初始上限。 –

回答

6

我觉得问题是这个月的第一个字母是小写字母。 当你运行28-Mar-2007而不是28-mar-2007的代码时,一切正常。

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

private String convertDate(String mydate) { 

     String date = mydate; 
     String firstLetter = date.substring(0,4).toUpperCase(); 
     String restLetters = date.substring(4).toLowerCase(); 
     date = firstLetter+restLetters; 

     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; 
    } 
+0

正确的答案。这是为什么我们应该始终使用标准[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)格式(如YYYY-MM-DD)将日期时间值保留为文本的一个示例。 –

+0

@Plirkee,确实有效,正如您所说,可能是由大写/小写问题引起的。不幸的是,它是一个传统的后端,很难改变那里的内部格式。 –

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标准,我有点晚了,所以只是张贴少一点c颂

4

TL;博士

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

详细

Answer by Plirkee是正确的:在英语语言环境中指望缩写月份名有一个初步的大写字母(大写)。

DateTimeFormatterBuilder

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

java.time类包括DateTimeFormatterDateTimeFormatterBuilder是线程安全的。所以你可以保留一个实例来重复使用。

生成器模式

阅读上的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.times类在解析/生成字符串时默认使用这些标准格式。

+0

感谢您使用DateTimeFormatterBuilder的提示。这看起来很方便。我在java文档中看到这些示例是Jun,但我不认为它是区分大小写的。但肯定是用.parseCaseInsensitive()解析它看起来更整齐。 –