谁能解释为什么 4 个日历中有 1 个显示 Time=?
Can anyone explain why 1 of 4 calendars shows Time=?
我有 4 个日历,startCal、endCal、reminderCal 和今天。今天只是为当前 date/time 获取 Calendar.getInstance(),而其他 3 个使用 Android date/time 选择器通过相同的方法选择日期和时间。
startCal 和 endCal 工作正常
if(startCal.after(endCal)){ // 处理错误 }
然而,reminderCal.before(今天)并不 return 正确,即使我故意在当前日期之前设置 reminderCal。
另外,一直打印的时候,reminderCal没有任何时间(Time=?)和areFieldsSet=false,但是如果我第二次提交时间就会更新,虽然before()方法仍然不起作用!
似乎一切正常,除了 else if (reminderCal.before(today))
public boolean validInput(){
if(startCal.after(endCal)){
//THIS WORKS
timeError.setText(getString(R.string.error_event_end_early));
isOk = false;
Log.e(TAG, "validInput: Event ends before it starts");
}
if(hasReminder.isChecked()){
if(reminderDate.getText().toString().matches("")) {
// THIS WORKS
reminderError.setText(R.string.error_no_reminder);
isOk = false;
Log.e(TAG, "validInput: No reminder set");
} else if (reminderCal.before(today)){
// THIS DOESN'T WORK. Why?
reminderError.setText(R.string.error_reminder_early);
isOk = false;
Log.e(TAG, "validInput: Reminder too early " + reminderCal.toString());
} else if(reminderCal.after(startCal)){
//THIS WORKS
reminderError.setText(R.string.error_reminder_late);
isOk = false;
Log.e(TAG, "validInput: Reminder too late");
}
return isOk;
}
Log.e(TAG, "Debugging: \n" +
"strCalandar: " + startCal.toString() + "\n" +
"endCalandar: " + endCal.toString() + "\n" +
"remCalandar: " + reminderCal.toString() + "\n" +
"todCalandar: " + today.toString() + "\n");
}
今天=Calander.getInstance();没有进一步的调整。其他日历从这些方法中获取 date/time。
public void showDatePickerDialog(final EditText text, final Calendar cal){
Log.d(TAG, "showDatePickerDialog: Open");
DialogFragment datePicker = new DatePickerFragment();
((DatePickerFragment) datePicker).setOnDateChosenListener(new DatePickerFragment.OnDateChosenListener() {
@Override
public void onDateChosen(int year, int month, int day) {
text.setText(String.format("%02d/%02d/%04d", day, month, year));
cal.set(year, month, day);
}
});
datePicker.show(getSupportFragmentManager(), "DatePicker");
}
public void showTimePickerDialog(final EditText text, final Calendar cal){
Log.d(TAG, "showTimePickerDialog: Open");
DialogFragment timePicker = new TimePickerFragment();
((TimePickerFragment) timePicker).setOnTimeChosenListener(new TimePickerFragment.OnTimeChosenListener() {
@Override
public void onTimeChosen(int hour, int min) {
text.setText(String.format("%02d:%02d", hour, min));
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, min);
}
});
timePicker.show(getSupportFragmentManager(), "TimePicker");
}
Logcat中的输出:
strCalandar: java.util.GregorianCalendar[time=1566152201478,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=libcore.util.ZoneInfo[id="Europe/London",mRawOffset=0,mEarliestRawOffset=0,mUseDst=true,mDstSavings=3600000,transitions=242],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2019,MONTH=7,WEEK_OF_YEAR=33,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=230,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=7,HOUR_OF_DAY=19,MINUTE=16,SECOND=41,MILLISECOND=478,ZONE_OFFSET=0,DST_OFFSET=3600000]
endCalandar: java.util.GregorianCalendar[time=1566152201478,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=libcore.util.ZoneInfo[id="Europe/London",mRawOffset=0,mEarliestRawOffset=0,mUseDst=true,mDstSavings=3600000,transitions=242],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2019,MONTH=7,WEEK_OF_YEAR=33,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=230,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=7,HOUR_OF_DAY=19,MINUTE=16,SECOND=41,MILLISECOND=478,ZONE_OFFSET=0,DST_OFFSET=3600000]
remCalandar: java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=libcore.util.ZoneInfo[id="Europe/London",mRawOffset=0,mEarliestRawOffset=0,mUseDst=true,mDstSavings=3600000,transitions=242],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2019,MONTH=7,WEEK_OF_YEAR=31,WEEK_OF_MONTH=1,DAY_OF_MONTH=2,DAY_OF_YEAR=214,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=18,SECOND=41,MILLISECOND=478,ZONE_OFFSET=0,DST_OFFSET=3600000]
todCalandar: java.util.GregorianCalendar[time=1562775401478,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=libcore.util.ZoneInfo[id="Europe/London",mRawOffset=0,mEarliestRawOffset=0,mUseDst=true,mDstSavings=3600000,transitions=242],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2019,MONTH=6,WEEK_OF_YEAR=28,WEEK_OF_MONTH=2,DAY_OF_MONTH=10,DAY_OF_YEAR=191,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=16,SECOND=41,MILLISECOND=478,ZONE_OFFSET=0,DST_OFFSET=3600000]
如果提醒日期设置在当前日期之前,reminderCal.before(今天)应该 return 为真
他们试图在文档的这一部分对其进行解释:
set(f, value)
changes calendar field f
to value
. In addition, it sets an internal member variable to indicate that
calendar field f
has been changed. Although calendar field f
is
changed immediately, the calendar's time value in milliseconds is not
recomputed until the next call to get()
, getTime()
,
getTimeInMillis()
, add()
, or roll()
is made. Thus, multiple
calls to set()
do not trigger multiple, unnecessary computations. As
a result of changing a calendar field using set()
, other calendar
fields may also change, depending on the calendar field, the calendar
field value, and the calendar system. In addition, get(f)
will not
necessarily return value set by the call to the set
method after the
calendar fields have been recomputed. The specifics are determined by
the concrete calendar class.
Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling set(Calendar.MONTH, Calendar.SEPTEMBER) sets the date to September 31, 1999. This is a temporary internal representation that
resolves to October 1, 1999 if getTime()is then called. However, a
call to set(Calendar.DAY_OF_MONTH, 30) before the call to getTime()
sets the date to September 30, 1999, since no recomputation occurs
after set() itself.
因此,由于您调用了 cal.set(Calendar.HOUR_OF_DAY, hour);
和 cal.set(Calendar.MINUTE, min);
,时间暂时未定义,这就是问号从 toString
.
打印出来的原因
我无法重现 before
和 after
的报告行为,但假设它们在 get
或一个之前也无法正常工作似乎是合理的提到的 getXxx
个方法被调用。
这只是 Calendar
class 设计中非常令人困惑的方面之一。好的解决方案是切换到使用 java.time, the modern Java date and time API.
我有 4 个日历,startCal、endCal、reminderCal 和今天。今天只是为当前 date/time 获取 Calendar.getInstance(),而其他 3 个使用 Android date/time 选择器通过相同的方法选择日期和时间。
startCal 和 endCal 工作正常 if(startCal.after(endCal)){ // 处理错误 }
然而,reminderCal.before(今天)并不 return 正确,即使我故意在当前日期之前设置 reminderCal。
另外,一直打印的时候,reminderCal没有任何时间(Time=?)和areFieldsSet=false,但是如果我第二次提交时间就会更新,虽然before()方法仍然不起作用!
似乎一切正常,除了 else if (reminderCal.before(today))
public boolean validInput(){
if(startCal.after(endCal)){
//THIS WORKS
timeError.setText(getString(R.string.error_event_end_early));
isOk = false;
Log.e(TAG, "validInput: Event ends before it starts");
}
if(hasReminder.isChecked()){
if(reminderDate.getText().toString().matches("")) {
// THIS WORKS
reminderError.setText(R.string.error_no_reminder);
isOk = false;
Log.e(TAG, "validInput: No reminder set");
} else if (reminderCal.before(today)){
// THIS DOESN'T WORK. Why?
reminderError.setText(R.string.error_reminder_early);
isOk = false;
Log.e(TAG, "validInput: Reminder too early " + reminderCal.toString());
} else if(reminderCal.after(startCal)){
//THIS WORKS
reminderError.setText(R.string.error_reminder_late);
isOk = false;
Log.e(TAG, "validInput: Reminder too late");
}
return isOk;
}
Log.e(TAG, "Debugging: \n" +
"strCalandar: " + startCal.toString() + "\n" +
"endCalandar: " + endCal.toString() + "\n" +
"remCalandar: " + reminderCal.toString() + "\n" +
"todCalandar: " + today.toString() + "\n");
}
今天=Calander.getInstance();没有进一步的调整。其他日历从这些方法中获取 date/time。
public void showDatePickerDialog(final EditText text, final Calendar cal){
Log.d(TAG, "showDatePickerDialog: Open");
DialogFragment datePicker = new DatePickerFragment();
((DatePickerFragment) datePicker).setOnDateChosenListener(new DatePickerFragment.OnDateChosenListener() {
@Override
public void onDateChosen(int year, int month, int day) {
text.setText(String.format("%02d/%02d/%04d", day, month, year));
cal.set(year, month, day);
}
});
datePicker.show(getSupportFragmentManager(), "DatePicker");
}
public void showTimePickerDialog(final EditText text, final Calendar cal){
Log.d(TAG, "showTimePickerDialog: Open");
DialogFragment timePicker = new TimePickerFragment();
((TimePickerFragment) timePicker).setOnTimeChosenListener(new TimePickerFragment.OnTimeChosenListener() {
@Override
public void onTimeChosen(int hour, int min) {
text.setText(String.format("%02d:%02d", hour, min));
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, min);
}
});
timePicker.show(getSupportFragmentManager(), "TimePicker");
}
Logcat中的输出:
strCalandar: java.util.GregorianCalendar[time=1566152201478,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=libcore.util.ZoneInfo[id="Europe/London",mRawOffset=0,mEarliestRawOffset=0,mUseDst=true,mDstSavings=3600000,transitions=242],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2019,MONTH=7,WEEK_OF_YEAR=33,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=230,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=7,HOUR_OF_DAY=19,MINUTE=16,SECOND=41,MILLISECOND=478,ZONE_OFFSET=0,DST_OFFSET=3600000]
endCalandar: java.util.GregorianCalendar[time=1566152201478,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=libcore.util.ZoneInfo[id="Europe/London",mRawOffset=0,mEarliestRawOffset=0,mUseDst=true,mDstSavings=3600000,transitions=242],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2019,MONTH=7,WEEK_OF_YEAR=33,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=230,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=7,HOUR_OF_DAY=19,MINUTE=16,SECOND=41,MILLISECOND=478,ZONE_OFFSET=0,DST_OFFSET=3600000]
remCalandar: java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=libcore.util.ZoneInfo[id="Europe/London",mRawOffset=0,mEarliestRawOffset=0,mUseDst=true,mDstSavings=3600000,transitions=242],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2019,MONTH=7,WEEK_OF_YEAR=31,WEEK_OF_MONTH=1,DAY_OF_MONTH=2,DAY_OF_YEAR=214,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=18,SECOND=41,MILLISECOND=478,ZONE_OFFSET=0,DST_OFFSET=3600000]
todCalandar: java.util.GregorianCalendar[time=1562775401478,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=libcore.util.ZoneInfo[id="Europe/London",mRawOffset=0,mEarliestRawOffset=0,mUseDst=true,mDstSavings=3600000,transitions=242],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2019,MONTH=6,WEEK_OF_YEAR=28,WEEK_OF_MONTH=2,DAY_OF_MONTH=10,DAY_OF_YEAR=191,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=16,SECOND=41,MILLISECOND=478,ZONE_OFFSET=0,DST_OFFSET=3600000]
如果提醒日期设置在当前日期之前,reminderCal.before(今天)应该 return 为真
他们试图在文档的这一部分对其进行解释:
set(f, value)
changes calendar fieldf
tovalue
. In addition, it sets an internal member variable to indicate that calendar fieldf
has been changed. Although calendar fieldf
is changed immediately, the calendar's time value in milliseconds is not recomputed until the next call toget()
,getTime()
,getTimeInMillis()
,add()
, orroll()
is made. Thus, multiple calls toset()
do not trigger multiple, unnecessary computations. As a result of changing a calendar field usingset()
, other calendar fields may also change, depending on the calendar field, the calendar field value, and the calendar system. In addition,get(f)
will not necessarily return value set by the call to theset
method after the calendar fields have been recomputed. The specifics are determined by the concrete calendar class.Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling set(Calendar.MONTH, Calendar.SEPTEMBER) sets the date to September 31, 1999. This is a temporary internal representation that resolves to October 1, 1999 if getTime()is then called. However, a call to set(Calendar.DAY_OF_MONTH, 30) before the call to getTime() sets the date to September 30, 1999, since no recomputation occurs after set() itself.
因此,由于您调用了 cal.set(Calendar.HOUR_OF_DAY, hour);
和 cal.set(Calendar.MINUTE, min);
,时间暂时未定义,这就是问号从 toString
.
我无法重现 before
和 after
的报告行为,但假设它们在 get
或一个之前也无法正常工作似乎是合理的提到的 getXxx
个方法被调用。
这只是 Calendar
class 设计中非常令人困惑的方面之一。好的解决方案是切换到使用 java.time, the modern Java date and time API.