[英]Java Calendar instance increments DAY_OF_MONTH as a side effect of decrementing (only) HOUR or MINUTE
我有一個未完成的Android應用程序 ,主要活動有TimePicker
( @+id/tyme
), DatePicker
( @+id/date
)和TextView
( @+id/dropTime
),用於顯示類似“DateTime”的數據由於某種原因,我需要指定兩個視圖。
因為Javadocs不贊成從Date
實例中提取DateTime-field-type值的所有嘗試,所以我想使用Calendar
類來表示用戶選擇的年,月,日,小時,分鍾,秒的組合。 我發現我經常(但不總是)不能減少小時或分鍾字段而不同時增加日期字段。 這是DatePicker
事件處理程序:
date = (DatePicker) findViewById(R.id.date);
// h/t O'one https://stackoverflow.com/a/34952495/948073
date.init(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH),
new DatePicker.OnDateChangedListener() {
@Override
public void onDateChanged(DatePicker datePicker, int y, int m, int d) {
System.out.println("onDateChanged(tp,"+y+","+m+","+d+")");
calendar.set(Calendar.YEAR, y);
calendar.set(Calendar.MONTH, m);
calendar.set(Calendar.DAY_OF_MONTH, d);
updateDropTime();
}
}
);
和TimePicker
。 注意y / m / d字段的顯式備份和恢復是徒勞的,試圖在h:m:s變化期間消除y:m:d的可疑交叉污染:
private TimePicker time;
dropTime = (TextView) findViewById(R.id.dropTime);
updateDropTime();
time = (TimePicker) findViewById(R.id.tyme);
time.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
public void onTimeChanged(TimePicker tp, int h, int m) {
System.out.println("onTimeChanged(tp,"+h+","+m+")");
// Save state of y/m/d portion of calendar
int y = calendar.get(Calendar.YEAR);
int mo = calendar.get(Calendar.MONTH);
int d = calendar.get(Calendar.DAY_OF_MONTH);
// Set h and m fields of calendar based on user input
calendar.set(Calendar.HOUR, h);
calendar.set(Calendar.MINUTE, m);
// Restore state of y/m/d fields
calendar.set(Calendar.YEAR, y);
calendar.set(Calendar.MONTH, mo);
calendar.set(Calendar.DAY_OF_MONTH, d);
// In theory y/m/d portion of datetime should be unchanged
updateDropTime();
}
});
這兩個事件處理程序都調用updateDropTime()
,如下所示:
private void updateDropTime() {
String disp = DateFormat.getDateTimeInstance().format(calendar.getTimeInMillis());
dropTime.setText(disp);
}
我懷疑方法鏈中導致disp
值的某些東西是看似混亂的行為發生的地方,我認為我已經系統地標記了對日期字段的任何更改,這些更改可能是時間字段更改的副作用。
這條線錯了:
calendar.set(Calendar.HOUR, h);
相反,你想要:
calendar.set(Calendar.HOUR_OF_DAY, h);
該h
你得到onTimeChanged()
是在24小時時鍾一天的小時。 Calendar.HOUR
表示AM或PM內的小時,即12小時制。
這怎么會導致你的問題? 示例:原始時間為20:25(如果您願意,則為8:25 PM)。 用戶將其更改為13:28(1:28 PM)。 您將Calendar.HOUR
設置為13.由於原始時間是在PM並且您不更改此項,因此您實際上將時間設置為下午13:28。 這是胡說八道,但Calendar
並不關心,它只是將其解釋為第二天凌晨1點1:28
分。 設置日期並沒有幫助,因為當你這樣做時,字段尚未計算,因此內部時間仍然是正確的一天下午13:28。 只有在最后調用getTimeInMillis()
,才會計算所有字段,檢測到溢出並增加日期。
Calendar
是默認的寬松 如果您希望收到有關此類錯誤的通知(我們不時制作的setLenient(false)
,請在創建Calendar
對象后調用setLenient(false)
。 這將導致它不接受超出范圍的值,如13 HOUR
。
如果您根本不想使用Calendar
類,那么您肯定遠離第一個,並且有一個更好,更程序友好的替代方案。 現代Java日期和時間API內置於Java 8及更高版本中,在Android上您可以在ThreeTenABP 中使用它,請參閱如何在Android項目中使用ThreeTenABP 。 我建議將日期保存在LocalDate
對象中,並將時間保存在LocalTime
這樣用戶可以獨立更新每個對象而不會有交叉污染的風險。 只有在updateDropTime()
才能使用LocalDate.atTime()
將兩者合並為LocalDateTime
,然后使用DateTimeFormatter
將其格式化為所需的顯示格式。
public void onTimeChanged(TimePicker tp, int h, int m) {
System.out.println("onTimeChanged(tp," + h + "," + m + ")");
time = LocalTime.of(h, m);
updateDropTime();
}
更新可能會像:
private void updateDropTime() {
String disp = date.atTime(time)
.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT));
dropTime.setText(disp);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.