谁能解释为什么 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.

打印出来的原因

我无法重现 beforeafter 的报告行为,但假设它们在 get 或一个之前也无法正常工作似乎是合理的提到的 getXxx 个方法被调用。

这只是 Calendar class 设计中非常令人困惑的方面之一。好的解决方案是切换到使用 java.time, the modern Java date and time API.