2016-08-29 267 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()解析它看起來更整齊。 –