2015-01-13 115 views
3

在舊的Java解析從字符串年和週日期我能做到那樣:如何使用java.time

System.out.println(new SimpleDateFormat("yyyy w", Locale.UK).parse("2015 1")); 
// shows Mon Dec 29 00:00:00 CET 2014 

System.out.println(new SimpleDateFormat("yyyy w", Locale.US).parse("2015 1")); 
// shows Mon Dec 28 00:00:00 CET 2014 

我想在Java中8

使用java.time
System.out.println(LocalDate.parse("2015 1", DateTimeFormatter.ofPattern("yyyy w", Locale.US))); 

結果:

java.time.format.DateTimeParseException:文本 '2015 1' 無法解析:無法從TemporalAccessor獲得LOCALDATE:{WeekOfWeekBasedYear [WeekFields [星期日,1] = 1,年份= 2015},類型爲java.time.format的ISO .Parsed

如何在java.time中做到這一點?

此外,我不滿意我必須通過Locale來確定星期幾的第一天:星期一和星期日。這不是國家特色,而是日曆功能。我想用類似java.time.temporal.WeekFields.ISO世界週一顯示,本週開始

我發現了類似的情況:https://stackoverflow.com/questions/3941700/how-to-get-dates-of-a-week-i-know-week-number

但不是在Java 8 java.time此外,首先創建日期對象並稍後設置正確周的解決方案並不高雅。我想一次創建最終日期。

回答

5

直接回答和解決方案:

System.out.println( 
    LocalDate.parse("2015 1", 
    new DateTimeFormatterBuilder().appendPattern("YYYY w") 
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1) 
    .toFormatter())); 
// output: 2014-12-29 

說明:

a)你應該使用的Y代替y方法,因爲你在ISO-8601週日期有興趣,而不是在今年的時代。

b)一個日曆日期不能只是給一個(基於周)一年週數形成。星期幾重要的是確定指定日曆周內的一天。預定義的formatter for week-dates需要缺少星期幾。所以你需要使用builder-pattern構造一個專門的解析器。然後有必要通過方法parseDefaulting()告訴解析器需要哪一天。

三)我堅持(和上說,一個星期開始時的問題不是日曆的問題,而是國家相關問題捍衛JSR-310在這裏)。美國和法國(例如)使用相同的日曆,但對於如何定義一週有不同的看法。可以使用明確的ISO引用字段WeekFields.ISO.dayOfWeek()來應用ISO-8601標準。 注意:測試顯示,使用ChronoField.DAY_OF_WEEKLocale.ROOT一起並不總是似乎以保證ISO周的行爲,在我這個答案的第一個版本指示(原因尚不清楚,我 - 的來源近景似乎有必要啓發不直觀的行爲)。

d)的Java的時間包是否良好 - 與週一正好指定爲數字1的例外,我寧願枚舉。或者使用enum及其方法getValue()

E)方通知:SimpleDateFormat默認從輕行爲。 java-time-package更加嚴格,並且拒絕發明一個虛擬的星期幾 - 甚至在寬鬆模式下(這在我看來是一件好事)。軟件不應該這麼猜測,相反,程序員應該更多地考慮哪一天是正確的。同樣在這裏:美國和法國的應用要求可能會有所不同,正確的默認設置。

+0

廣告c)我不是精確的。我的意思是,當我想使用自定義的星期一/星期天設置時,我不應該使用Locale,其中星期定義爲我想要但明確定義什麼是星期幾。建議的回答(用Locale.ROOT)爲100%,我問 – michaldo

+0

我申請解決2016年: 的System.out.println( LocalDate.parse( 「2016 1」, 新DateTimeFormatterBuilder()appendPattern(」 YYYY w「) .parseDefaulting(ChronoField.DAY_OF_WEEK,1) .toFormatter()。withLocale(Locale.ROOT))); //輸出:2015-12-28 爲什麼我得到了2015-12-28?我期待2016-01-04,因爲2016年的第一週是1月4日至10日 – michaldo

+0

@michaldo非常感謝您的反饋。我改變了我的回答,寧願選擇第二種解決方案。它仍然適用於'2016-1'產生'2016-01-04'的結果。看來我們在JSR-310-API中遇到了一些奇怪的現象。 –

2

accepted Answer by Meno Hochschild是正確的。這是一條替代路線。

YearWeek

使用YearWeekThreeTen-Extra庫。這個庫擴展了java.time和附加功能。這個特殊的班級代表ISO 8601 week date system中的年份。

工廠方法YearWeek.of需要一對整數參數,基於爲期一週的年和週數。

YearWeek yw = YearWeek.of(2015 , 1); 

ISO 8601

理想情況下,你會使用標準的ISO 8601格式以表示日期時間值的字符串。對於year-week that would be yyyy-Www以周爲單位的年份數字,連字符,W和兩位數字(如果需要,填充零的週數)。

2015年-W01

的java.time類和ThreeTen-額外的課程,分析和生成字符串時默認使用標準ISO 8601名的格式。所以如果堅持標準,生活是更容易。

YearWeek yw = YearWeek.parse("2015-W01"); 
String output = yw.toString(); // 2015-W01 

解析整數。

你有一個非標準格式的數字。因此,讓我們將您的字符串解析爲兩部分,每部分一個數字,將其解釋爲整數。

String string = "2015 1"; 
String[] parts = string.split(" "); // SPACE character. 
String part1 = parts[0]; // 2015 
String part2 = parts[1]; // 1 

Integer類轉換這樣的字符串到int原始值。

int weekBasedYearNumber = Integer.parseInt(part1) ; 
int weekNumber = Integer.parseInt(part2) ; 

現在調用該工廠方法。

YearWeek yw = YearWeek.of(weekBasedYearNumber , weekNumber); 

LocalDate

至於周的第一天,在這裏我們一直在討論本週的標準ISO 8601的定義。在這個定義中,星期一始終是第一天,從星期一到星期天一週。第1周包含日曆年的第一個星期四。在2015年-W01的情況下週四將是1月1日,2015年

所以,沒有必要Locale

我不太清楚你的目標,但它似乎是提取你的星期內的特定日期。 YearWeek類和DayOfWeek枚舉類型非常簡單。

LocalDate monday = yw.atDay(DayOfWeek.MONDAY); // 2014-12-29 start-of-week. 
LocalDate friday = yw.atDay(DayOfWeek.FRIDAY); // 2015-01-02 
LocalDate sunday = yw.atDay(DayOfWeek.SUNDAY); // 2015-01-04 end-of-week. 

screen shot of calendar month January 2015 with ISO 8601 week number 1 running from 2014-12-29 Monday to 2015-01-04 Sunday

0

這也可以通過使用「ChronoField.Day_Of_Week」把默認的解析值工作周並將其值設置爲實現「1」的方法如下:

System.out.println("Date From Year and Week : "+ 
       LocalDate.parse("2015 1", 
       new DateTimeFormatterBuilder().appendPattern("YYYY w") 
       .parseDefaulting(ChronoField.DAY_OF_WEEK, 1) 
       .toFormatter())); 
+0

這是接受的答案恕我直言的重複 – michaldo