在Android上使用java.util.Calendar
时,我偶然发现了一个有趣的错误:在API级别23或更低级别Calendar.set(...)
设置的某些字段在调用Calendar.get(...)
之前不会应用(因为get方法在内部调用complete()
?)
发生此问题,多次设置Calendar.DAY_OF_MONTH
时,请查看以下代码:
DateHelper.kt
class DateHelper{
companion object {
fun getStartOfWeek(yearInformation : Date, weekNumber: Int, applyFix: Boolean = false): Date {
val cal = Calendar.getInstance()
cal.time = yearInformation
cal.set(Calendar.WEEK_OF_YEAR, weekNumber)
if(applyFix) cal.get(Calendar.WEEK_OF_YEAR)
cal.set(Calendar.DAY_OF_WEEK, cal.firstDayOfWeek)
return cal.time
}
}
}
DateHelperTest.kt
@RunWith(AndroidJUnit4::class)
class DateHelperTest{
/** setting the week of month only once works */
@Test
fun shouldReturnCorrectStartOfWeek(){
val cal = Calendar.getInstance()
cal.set(Calendar.YEAR, 2018)
val yearInformation = cal.time
val weeknumber = 8 //Sunday = 18.02, Monday = 19.02
val result = DateHelper.getStartOfWeek(yearInformation, weeknumber)
cal.time = result
val acualDay = cal.get(Calendar.DAY_OF_MONTH)
assertThat(acualDay, anyOf(equalTo(18), equalTo(19)))
}
/**
* setting the week of month twice (calling DateHelper.getStartOfWeek multiple times)
* doesn't work (for API level <= 23)
*/
@Test
fun shouldChangeStartOfWeekCorrectly(){
val cal = Calendar.getInstance()
cal.set(Calendar.YEAR, 2018)
val yearInformation = cal.time
var weeknumber = 8 //Sunday = 18.02, Monday = 19.02
DateHelper.getStartOfWeek(yearInformation, weeknumber) //initial call
weeknumber = 9 //incremented, Sunday = 25, Monday = 26 now
val result = DateHelper.getStartOfWeek(yearInformation, weeknumber) //second, tested call
cal.time = result
val actualDay = cal.get(Calendar.DAY_OF_MONTH)
assertThat(actualDay, anyOf(equalTo(25), equalTo(26)))
}
/**
* same as shouldChangeStartOfWeekCorrectly() but with workaround
* (internally calling cal.get())
* */
@Test
fun shouldChangeStartOfWeekCorrectly_WithWorkaround(){
val cal = Calendar.getInstance()
cal.set(Calendar.YEAR, 2018)
val yearInformation = cal.time
var weeknumber = 8 //Sunday = 18.02, Monday = 19.02
DateHelper.getStartOfWeek(yearInformation, weeknumber) //initial call
weeknumber = 9 //incremented, Sunday = 25, Monday = 26 now
/* date helper call changed */
val result = DateHelper.getStartOfWeek(yearInformation, weeknumber, applyFix = true) //second, tested call
/* date helper call changed */
cal.time = result
val actualDay = cal.get(Calendar.DAY_OF_MONTH)
assertThat(actualDay, anyOf(equalTo(25), equalTo(26)))
}
}
Example Project on GitHub with executable instrumentation tests
提供的解决方法(if(applyFix) cal.get(Calendar.WEEK_OF_YEAR)
)相当不愉快:如何以正确的方式解决此问题?