2017-06-30 36 views
1

我們在Android 7(API 24/25)中使用Calendar有一些奇怪的行爲。Android 7.x(API24)WEEK_OF_MONTH日曆錯誤?

鑑於這種非常簡單的代碼:

SimpleDateFormat month_date = new SimpleDateFormat("dd.MM.YYYY"); 
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY); 
cal.setFirstDayOfWeek(Calendar.MONDAY); 

for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) { 
    Calendar start = ((Calendar) cal.clone()); 
    start.set(2017, month, 1); 

    Calendar end = ((Calendar) start.clone()); 
    end.set(Calendar.DAY_OF_MONTH, end.getActualMaximum(Calendar.DAY_OF_MONTH)); 

    Log.d("CAL", "\n Date Start: " + month_date.format(start.getTime()) + " " + 
     " WEEK_OF_MONTH: " + start.get(Calendar.WEEK_OF_MONTH) 
    ); 
    Log.d("CAL", "\n Date End: " + month_date.format(end.getTime()) + 
     " WEEK_OF_MONTH: " + end.get(Calendar.WEEK_OF_MONTH) 
     ); 
} 

運行在Android 4.0倍,5.x和6.x顯示正確的價值爲WEEK_OF_MONTH

Date Start: 01.01.2016 WEEK_OF_MONTH: 1 
Date End: 31.01.2017 WEEK_OF_MONTH: 6 
Date Start: 01.02.2017 WEEK_OF_MONTH: 1 
Date End: 28.02.2017 WEEK_OF_MONTH: 5 
Date Start: 01.03.2017 WEEK_OF_MONTH: 1 
Date End: 31.03.2017 WEEK_OF_MONTH: 5 
Date Start: 01.04.2017 WEEK_OF_MONTH: 1 
Date End: 30.04.2017 WEEK_OF_MONTH: 5 
Date Start: 01.05.2017 WEEK_OF_MONTH: 1 
Date End: 31.05.2017 WEEK_OF_MONTH: 5 
Date Start: 01.06.2017 WEEK_OF_MONTH: 1 
Date End: 30.06.2017 WEEK_OF_MONTH: 5 
Date Start: 01.07.2017 WEEK_OF_MONTH: 1 
Date End: 31.07.2017 WEEK_OF_MONTH: 6 
Date Start: 01.08.2017 WEEK_OF_MONTH: 1 
Date End: 31.08.2017 WEEK_OF_MONTH: 5 
Date Start: 01.09.2017 WEEK_OF_MONTH: 1 
Date End: 30.09.2017 WEEK_OF_MONTH: 5 
Date Start: 01.10.2017 WEEK_OF_MONTH: 1 
Date End: 31.10.2017 WEEK_OF_MONTH: 6 
Date Start: 01.11.2017 WEEK_OF_MONTH: 1 
Date End: 30.11.2017 WEEK_OF_MONTH: 5 
Date Start: 01.12.2017 WEEK_OF_MONTH: 1 
Date End: 31.12.2017 WEEK_OF_MONTH: 5 

運行在Android 7.x版破損WEEK_OF_MONTH

Date Start: 01.01.2016 WEEK_OF_MONTH: 0 
Date End: 31.01.2017 WEEK_OF_MONTH: 5 
Date Start: 01.02.2017 WEEK_OF_MONTH: 1 
Date End: 28.02.2017 WEEK_OF_MONTH: 5 
Date Start: 01.03.2017 WEEK_OF_MONTH: 1 
Date End: 31.03.2017 WEEK_OF_MONTH: 5 
Date Start: 01.04.2017 WEEK_OF_MONTH: 0 
Date End: 30.04.2017 WEEK_OF_MONTH: 4 
Date Start: 01.05.2017 WEEK_OF_MONTH: 1 
Date End: 31.05.2017 WEEK_OF_MONTH: 5 
Date Start: 01.06.2017 WEEK_OF_MONTH: 1 
Date End: 30.06.2017 WEEK_OF_MONTH: 5 
Date Start: 01.07.2017 WEEK_OF_MONTH: 0 
Date End: 31.07.2017 WEEK_OF_MONTH: 5 
Date Start: 01.08.2017 WEEK_OF_MONTH: 1 
Date End: 31.08.2017 WEEK_OF_MONTH: 5 
Date Start: 01.09.2017 WEEK_OF_MONTH: 0 
Date End: 30.09.2017 WEEK_OF_MONTH: 4 
Date Start: 01.10.2017 WEEK_OF_MONTH: 0 
Date End: 31.10.2017 WEEK_OF_MONTH: 5 
Date Start: 01.11.2017 WEEK_OF_MONTH: 1 
Date End: 30.11.2017 WEEK_OF_MONTH: 5 
Date Start: 01.12.2017 WEEK_OF_MONTH: 0 
Date End: 31.12.2017 WEEK_OF_MONTH: 4 

我們找不到任何記錄的c在API 24中有Calendar的變更。

任何線索如何解決此問題?

我們已經實現了我們自己的方法WEEK_OF_MONTH返回與Android 6.x相同的值,但通過它的外觀set(WEEK_OF_MONTH)也被打破。 使用Joda重寫代碼不是一種選擇。

回答

0

可以使用setMinimalDaysInFirstWeek()方法change how the weeks are counted

Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY); 
cal.setFirstDayOfWeek(Calendar.MONDAY); 
cal.setMinimalDaysInFirstWeek(1); 

這將產生正確的值星期月的。


你說過用Joda-Time重寫代碼不是一種選擇,但其他API呢?

在Android中,您可以使用ThreeTen Backport,這是用於Java 8的新日期/時間類的一個很好的後端,以及ThreeTenABP(更多關於如何使用它的here)。

順便說一句,Joda-Time處於維護模式,正在被新的API取代,所以我不建議用它開始一個新的項目。即使在joda's website中也寫道:「請注意,Joda-Time被認爲是一個大部分已完成的項目,沒有計劃任何重大改進,如果使用Java SE 8,請遷移到java.time(JSR-310)。

下面的類是在org.threeten.bp包下。該代碼將是這樣的:

import java.util.Locale; 
import org.threeten.bp.DayOfWeek; 
import org.threeten.bp.LocalDate; 
import org.threeten.bp.Month; 
import org.threeten.bp.format.DateTimeFormatter; 
import org.threeten.bp.format.DateTimeFormatterBuilder; 
import org.threeten.bp.temporal.TemporalAdjusters; 
import org.threeten.bp.temporal.WeekFields; 

DateTimeFormatter fmt = new DateTimeFormatterBuilder() 
    // day and month 
    .appendPattern("dd.MM.") 
    // week based year (equivalent to YYYY in SimpleDateFormat) 
    .appendValue(WeekFields.ISO.weekBasedYear()) 
    // create formatter 
    .toFormatter(Locale.GERMANY); 

// week starting at monday, consider week=1 even if it has 1 day (default is 4) 
WeekFields wf = WeekFields.of(DayOfWeek.MONDAY, 1); 
for (Month month : Month.values()) { 
    LocalDate start = LocalDate.of(2017, month, 1); 
    LocalDate end = start.with(TemporalAdjusters.lastDayOfMonth()); 

    System.out.println("Date Start: " + fmt.format(start) + " " + " WEEK_OF_MONTH: " + start.get(wf.weekOfMonth())); 
    System.out.println("Date End: " + fmt.format(end) + " WEEK_OF_MONTH: " + end.get(wf.weekOfMonth())); 
} 

輸出將是:

Date Start: 01.01.2016 WEEK_OF_MONTH: 1 
Date End: 31.01.2017 WEEK_OF_MONTH: 6 
Date Start: 01.02.2017 WEEK_OF_MONTH: 1 
Date End: 28.02.2017 WEEK_OF_MONTH: 5 
Date Start: 01.03.2017 WEEK_OF_MONTH: 1 
Date End: 31.03.2017 WEEK_OF_MONTH: 5 
Date Start: 01.04.2017 WEEK_OF_MONTH: 1 
Date End: 30.04.2017 WEEK_OF_MONTH: 5 
Date Start: 01.05.2017 WEEK_OF_MONTH: 1 
Date End: 31.05.2017 WEEK_OF_MONTH: 5 
Date Start: 01.06.2017 WEEK_OF_MONTH: 1 
Date End: 30.06.2017 WEEK_OF_MONTH: 5 
Date Start: 01.07.2017 WEEK_OF_MONTH: 1 
Date End: 31.07.2017 WEEK_OF_MONTH: 6 
Date Start: 01.08.2017 WEEK_OF_MONTH: 1 
Date End: 31.08.2017 WEEK_OF_MONTH: 5 
Date Start: 01.09.2017 WEEK_OF_MONTH: 1 
Date End: 30.09.2017 WEEK_OF_MONTH: 5 
Date Start: 01.10.2017 WEEK_OF_MONTH: 1 
Date End: 31.10.2017 WEEK_OF_MONTH: 6 
Date Start: 01.11.2017 WEEK_OF_MONTH: 1 
Date End: 30.11.2017 WEEK_OF_MONTH: 5 
Date Start: 01.12.2017 WEEK_OF_MONTH: 1 
Date End: 31.12.2017 WEEK_OF_MONTH: 5 
+1

這個固定我的問題,太棒了!謝謝 :) – TheMenace