Question

I have a time interval consisting of a beginning and an end date. I have a way of letting the user set these dates through DatePickerDialogs. Here is the code of the method that creates and shows the dialogs:

private void editInterval(boolean beginning) {
    DatePickerDialog dpd;
    Calendar cal = Calendar.getInstance();
    if (beginning) {
        dpd = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {             
            @Override
            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                someTimeDuringYear1 = year;
                someTimeDuringMonth1 = monthOfYear + 1;
                someTimeDuringDay1 = dayOfMonth;
                Calendar cal1 = Calendar.getInstance();
                cal1.set(Calendar.YEAR, year);
                cal1.set(Calendar.MONTH, monthOfYear);
                cal1.set(Calendar.DAY_OF_MONTH, dayOfMonth);
                Calendar cal2 = Calendar.getInstance();
                cal2.set(Calendar.YEAR, someTimeDuringYear2);
                cal2.set(Calendar.MONTH, someTimeDuringMonth2);
                cal2.set(Calendar.DAY_OF_MONTH, someTimeDuringDay2);
                if (cal1.getTimeInMillis() > cal2.getTimeInMillis()) {
                    someTimeDuringYear2 = someTimeDuringYear1;
                    someTimeDuringMonth2 = someTimeDuringMonth1;
                    someTimeDuringDay2 = someTimeDuringDay1;
                }
                updateSomeTimeDuring();
                editDepartureInterval();
            }
        }, someTimeDuringYear1, someTimeDuringMonth1 - 1, someTimeDuringDay1);
        dpd.setTitle(getString(R.string.beginning_of_interval));
        cal.add(Calendar.MONTH, 6);
        dpd.getDatePicker().setMaxDate(cal.getTimeInMillis());
        cal.add(Calendar.MONTH, -6);
        cal.add(Calendar.DATE, 2);
        dpd.getDatePicker().setMinDate(cal.getTimeInMillis());
    } else {
        dpd = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {             
            @Override
            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                someTimeDuringYear2 = year;
                someTimeDuringMonth2 = monthOfYear + 1;
                someTimeDuringDay2 = dayOfMonth;
                updateSomeTimeDuring();
                editDepartureInterval();
            }
        }, someTimeDuringYear2, someTimeDuringMonth2 - 1, someTimeDuringDay2);
        dpd.setTitle(getString(R.string.end_of_interval));
        cal.add(Calendar.MONTH, 6);
        dpd.getDatePicker().setMaxDate(cal.getTimeInMillis());
        cal.set(someTimeDuringYear1, someTimeDuringMonth1 - 1, someTimeDuringDay1);
        dpd.getDatePicker().setMinDate(cal.getTimeInMillis());
    }
    dpd.show();
    dpd.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
}

The value of the beginning variable determines whether the user has chosen to edit the beginning or end date of the interval. Those someTimeDuringYear1 and similar are member variables related to the beginning date, someTimeDuringYear2 and similar are related to the end date of the interval. All of them are pre-set before this dialog is ever created and shown.

The exception is thrown while editing both the beginning and the end interval. Let's say I choose to edit the interval's end date. Everything works perfectly until I set the date to the last date that I am allowed to. If I do that and confirm, everything still seems fine, but when I try to edit the interval's end date again, the application crashes and the exception is thrown. (The same thing happens if I set the interval's beginning date to the last allowed date and then try to edit it again.)

Here is the log from LogCat:

03-28 17:18:16.901: E/AndroidRuntime(6112): FATAL EXCEPTION: main
03-28 17:18:16.901: E/AndroidRuntime(6112): java.lang.IllegalArgumentException: Time not between Sat Mar 30 17:18:16 CET 2013 and Sat Sep 28 17:18:16 CEST 2013
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.widget.CalendarView.goTo(CalendarView.java:805)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.widget.CalendarView.setMinDate(CalendarView.java:487)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.widget.DatePicker.setMinDate(DatePicker.java:315)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at com.skypicker.android.MainActivity.editInterval(MainActivity.java:344)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at com.skypicker.android.MainActivity.access$10(MainActivity.java:296)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at com.skypicker.android.MainActivity$5.onClick(MainActivity.java:261)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:924)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.widget.AdapterView.performItemClick(AdapterView.java:292)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.widget.AbsListView.performItemClick(AbsListView.java:1063)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.widget.AbsListView$PerformClick.run(AbsListView.java:2519)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.widget.AbsListView$1.run(AbsListView.java:3173)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.os.Handler.handleCallback(Handler.java:605)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.os.Handler.dispatchMessage(Handler.java:92)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.os.Looper.loop(Looper.java:137)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at android.app.ActivityThread.main(ActivityThread.java:4424)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at java.lang.reflect.Method.invokeNative(Native Method)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at java.lang.reflect.Method.invoke(Method.java:511)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:787)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:554)
03-28 17:18:16.901: E/AndroidRuntime(6112):     at dalvik.system.NativeStart.main(Native Method)

I have been looking for answers and trying to come up with a solution all afternoon. Any help is appreciated.

Thank you.

PS: This is the first question I ever ask here, so I apologize if there is something wrong about it. I'll be happy to provide any missing information about what's happening.

EDIT: Strangely enough, even though the problem raises on the line when I try to set the minDate, it actually seems to be that the date is "bigger" than the maxDate. The reason that I have for believing this is that if I pass someTimeDuringDay2 - 1 instead of someTimeDuringDay2 to the DatePickerDialog's constructor, the problem is gone. But then "day" field in the DatePicker is really by one smaller than I want it to be. I need it to be set to someTimeDuringDay2 when the DatePickerDialog is shown, not to someTimeDuringDay2 - 1. But it seems to have a problem when the date is the same as its maxDate.

Was it helpful?

Solution

The problem was that hours, minutes, seconds and milliseconds of the calendars that I was using for setting the DatePicker's minDate and maxDate got set to the values correspondent to what time it was when Calendar.getInstance() was called. And when I passed the day, month and year to the constructor of DatePickerDialog, the dates were the same, but the milliseconds differed. So it could happen that the milliseconds set in maxDate were smaller than the milliseconds set in the DatePicker's current time, therefore the date the DatePicker was supposed to show was evaluated as bigger than maxDate (even though it was still the same day, just with some more milliseconds)... And similarly for minDate.

I hope it's understandable.

So what helped was to set the calendars to the last millisecond of the day when using them for setting maxDate and to the first millisecond of the day when using them for setting minDate. Like so:

(Just a piece of code from the else clause.)

        dpd.setTitle(getString(R.string.end_of_interval));
        cal.add(Calendar.MONTH, 6);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMaximum(Calendar.MILLISECOND));
        dpd.getDatePicker().setMaxDate(cal.getTimeInMillis());
        cal.set(someTimeDuringYear1, someTimeDuringMonth1 - 1, someTimeDuringDay1);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));
        dpd.getDatePicker().setMinDate(cal.getTimeInMillis());

Hope it will be helpful to someone.

Also if someone comes up with a more elegant solution, please let me know.

OTHER TIPS

I got the same exception when today is not in [minDate, maxDate]. But if I changed my code to call setMinDate() before setMaxDate(), it worked.

To enhance the above answer I decided to post this.

When calling setMaxDate() multiple times, let's say a dynamic change in onPrepareDialog(), you must make sure the new max year is not equal to the previous max year or the new max day is equal to the old max day.

Sounds strange but this is the source code from grep code

public void setMaxDate(long maxDate) {
    mTempDate.setTimeInMillis(maxDate);
        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
            return;
        }
        mMaxDate.setTimeInMillis(maxDate);
        mCalendarView.setMaxDate(maxDate);
        if (mCurrentDate.after(mMaxDate)) {
            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
            updateCalendarView();
        }
    updateSpinners();
}

So for me, I called setMaxDate() twice. Once with a dummy value where the years are offset by +100 and a second time for the actual fields I want.

Here is the combined result:

maxDate.set(Calendar.HOUR_OF_DAY, maxDate.getMaximum(Calendar.HOUR_OF_DAY));      
maxDate.set(Calendar.MINUTE, maxDate.getMaximum(Calendar.MINUTE));                
maxDate.set(Calendar.SECOND, maxDate.getMaximum(Calendar.SECOND));                
maxDate.set(Calendar.MILLISECOND, maxDate.getMaximum(Calendar.MILLISECOND));      
maxDateDummy.set(Calendar.HOUR_OF_DAY, maxDate.getMaximum(Calendar.HOUR_OF_DAY)); 
maxDateDummy.set(Calendar.MINUTE, maxDate.getMaximum(Calendar.MINUTE));           
maxDateDummy.set(Calendar.SECOND, maxDate.getMaximum(Calendar.SECOND));           
maxDateDummy.set(Calendar.MILLISECOND, maxDate.getMaximum(Calendar.MILLISECOND)); 

//update the dummy date by 100 years to force android OS to change max time.      
maxDateDummy.set(Calendar.YEAR, maxDateDummy.get(Calendar.YEAR) + 100);           

datePicker.setMaxDate(maxDateDummy.getTimeInMillis());                            
datePicker.setMaxDate(maxDate.getTimeInMillis());  

Had similar problem with setMinDate, this solved it:

int year=2017, month=1, day=1; // for min. date: 1. feb. 2017
Calendar cal = Calendar.getInstance();
cal.set( year, month, day, 0, 0, 0 ); //hour=0 min=0 sec=0
datePickerDialog.getDatePicker().setMinDate(cal.getTimeInMillis());

I was getting the same error , I fix it by setting

dialog.getDatePicker().setCalendarViewShown(false); 

in the app any was calenderview not required, This is what I did

Calendar tempDate =Calendar.getInstance(); 
dialog.getDatePicker().setMaxDate(Calendar.getInstance().getTimeInMillis();
dialog.getDatePicker().setCalendarViewShown(false);
tempDate.add(Calendar.YEAR, -120);
dialog.getDatePicker().setMinDate(tempDate.getTimeInMillis());

This is what I did for the same error that I was getting on DatePicker. So by the time I was setting MaxDate and MinDate on DatePicker the milliseconds were changing. For my application it did not matter if the date was one second off. I needed the difference between min and maxdates as two days.

        final Calendar c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getDefault());
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);

        DatePickerDialog datePickerDialog = new DatePickerDialog(getActivity(), this, year, month, day);
        long OFFSET = 1000 ; //milli seconds offset for your date.
        datePickerDialog.getDatePicker().setMaxDate(c.getTimeInMillis() + 1 * OFFSET);
        c.add(Calendar.DAY_OF_MONTH, -1);
        datePickerDialog.getDatePicker().setMinDate(c.getTimeInMillis() - 1 * OFFSET);

Hope this helps someone. This will keep the date set to be in between the bounds. You might have to change the offset based on your application.

I solved the similar problem by setting the limit of calendar to a year (from today's date)

    long A_YEAR_MILLISECOND = 12 * 30 * 24 * 60 * 60 * 1000L;

    datePickerDialog.getDatePicker().setMaxDate(Calendar.getInstance().getTimeInMillis() + A_YEAR_MILLISECOND);
    datePickerDialog.getDatePicker().setMinDate(Calendar.getInstance().getTimeInMillis());

In my case, i set min date after setting max date. It cause the crash.

Before :

if (!currentDateandTimeSampai.equalsIgnoreCase("")) {
    datePickerDialog.getDatePicker().setMaxDate(end.getTime());
} 

datePickerDialog.getDatePicker().setMinDate(System.currentTimeMillis() - 1000);

After :

datePickerDialog.getDatePicker().setMinDate(System.currentTimeMillis() - 1000);

if (!currentDateandTimeSampai.equalsIgnoreCase("")) {
     if (isSameDate(new Date(), end)){
          datePickerDialog.getDatePicker().setMaxDate(new Date().getTime());
     }else {
          datePickerDialog.getDatePicker().setMaxDate(end.getTime());
     }
 }

You can add this function to check your maxDate is the same day with current day :

public boolean isSameDate(Date date1, Date date2) {
    Calendar cal1 = Calendar.getInstance();
    Calendar cal2 = Calendar.getInstance();
    cal1.setTime(date1);
    cal2.setTime(date2);
    return cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) &&
            cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top