如果设置了非默认的最小日期,我正在调试CalendarView
中DatePicker
移至1964年10月的问题。这至少在API17 Nexus7仿真器上重现,但在其他设备上有关于此问题的报告,其中平台样式包括日期选择器中的微调器和日历视图。
以下是演示此问题的代码段:
class DatePickerDialog1964 extends DatePickerDialog {
DatePickerDialog1964(Context c) {
super(c, null, 2013, 4, 21);
@SuppressWarnings("deprecation")
Date min = new Date(2013-1900, 4, 21);
DatePicker p = getDatePicker();
p.setMinDate(min.getTime());
}
}
...
new DatePickerDialog1964(context).show();
屏幕截图:
当然,期望旋转器和日历视图显示相同的日期。
我将继续对此进行调试,但如果有任何SO用户有经验或其他见解,请分享。
相关:
答案 0 :(得分:19)
这不是1964年,但2100格式严重。 CalendarView
有错误。 formatDateRange()
在2038年之后无效。
class DatePickerDialog1964 extends DatePickerDialog {
DatePickerDialog1964(Context c) {
super(c, null, 2013, 4, 21);
@SuppressWarnings("deprecation")
Date min = new Date(2013-1900, 4, 21);
DatePicker p = getDatePicker();
CalendarView cv = p.getCalendarView(); // should check for null
long cur = cv.getDate();
int d = cv.getFirstDayOfWeek();
p.setMinDate(min.getTime());
cv.setDate(cur + 1000L*60*60*24*40);
cv.setFirstDayOfWeek((d + 1) % 7);
cv.setDate(cur);
cv.setFirstDayOfWeek(d);
}
}
// Calendar view is a cascade of bugs.
// Work around that by explicitly disabling it.
datePicker.setCalendarViewShown(false);
CalendarView
使用android.text.format.DateUtils.formatDateRange()
在标头中生成月份/年份名称。日历视图仅在月份数更改时更新标题。例如,如果月份数相同但年份更改,则不更新标题。
在布局阶段的某个地方,基础ListView
会在日历视图上调用OnScrollListener
,就好像列表已滚动到最后一样。如果更改了月份数,则使用上面的测试代码更新标题,传递给formatDateRange()
的毫秒值为4131043200000
,这是2100年末的某个地方,2100是{{1的默认最大值}}
DatePicker
反过来使用formatDateRange()
作为其内部日历表示,特别是使用其android.text.format.Time
方法设置millis。我没有检查底层的本机代码,但我的有根据的猜测是,传入的毫秒值被截断为32位set()
秒值与固有Year 2038 problem,包装到一个更多的值超过62年。 time_t
本身正在使用Time
,它代表自1900年以来的struct tm
年,因此在20世纪60年代导致int
,然后在标题中进行格式化。
这可以使用Time
与DatePicker
进行复制,而无需设置最小日期。只需使用微调器将年份移动到2038或更高版本,更改月份(触发标题更新),您将看到标题换行中的年份为1902。
现在,问题仍然是为什么设置最小日期会使日历视图滚动到最大日期。答案似乎是日历视图的周CalendarView
适配器。它从最小日期开始索引周数,但是当最小日期更改时,不会调用适配器的ListView
。所以上面的解决方法#1有效,因为:
答案 1 :(得分:12)
以上答案是关于此错误的来源。对于我的应用程序,我正在使用此解决方法:
每次更改DatePicker的日期或minDate时,请使用应在选择器/日历中选择的日期调用以下例程:
private void fixUpDatePickerCalendarView(Calendar date) {
// Workaround for CalendarView bug relating to setMinDate():
// https://code.google.com/p/android/issues/detail?id=42750
// Set then reset the date on the calendar so that it properly
// shows today's date. The choice of 24 months is arbitrary.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
final CalendarView cal = datePicker.getDatePicker().getCalendarView();
if (cal != null) {
date.add(Calendar.MONTH, 24);
cal.setDate(date.getTimeInMillis(), false, true);
date.add(Calendar.MONTH, -24);
cal.setDate(date.getTimeInMillis(), false, true);
}
}
}
答案 2 :(得分:2)
我最终使用的解决方案:
private void fixBuggyCalendarview(CalendarView cv) {
long current = cv.getDate();
cv.setDate(cv.getMaxDate(), false, true);
cv.setDate(current, false, true);
}
当您设置CalendarView的最小/最大日期
时,这也适用答案 3 :(得分:0)
我同意@laalto。最初的CalendarView
是一团糟。我也遇到了语言环境,Android 4.1.2上的字体大小问题(哦,是的,它已经向下移动),缺少可访问性功能等等。所以我决定复制the source code并实现我自己的日历。例如,现在正确显示标题文本。
/**
* The source code has the Year 2038 problem and doesn't honor CalendarView's mCurrentLocale.
*/
private void setMonthDisplayed(Calendar calendar) {
mMonthName.setText(DateFormat.format("MMMM, yyyy", calendar));
mMonthName.invalidate();
mCurrentMonthDisplayed = calendar.get(Calendar.MONTH);
mAdapter.setFocusMonth(mCurrentMonthDisplayed);
}
/**
* This imlementation formats the date correctly and uses the stand-alone form of a month (for the languages where it's important).
*/
private void setMonthDisplayed(Calendar calendar) {
mMonthName.setText(new SimpleDateFormat("LLLL yyyy", mCurrentLocale).format(calendar.getTime()));
mMonthName.invalidate();
mCurrentMonthDisplayed = calendar.get(Calendar.MONTH);
mAdapter.setFocusMonth(mCurrentMonthDisplayed);
}
答案 4 :(得分:0)
在实施上述任何建议之前,请检查以确保您的模拟器在今天的日期和时间运行。如果打开一段时间,可能会滞后几天。我只是通过重启模拟器来修复我的问题。