Java does certainly have the reputation of the worst date manipulation features. This all comes with the bad designed Calendar API. Hopefully, there are better third-party APIs and if you have to manipulate dates, moment, times… You certainly prefer JodaTime. From my point of view, it’s a no brainer.

I was working on a date picker for an Android project and found that the SDK provided a set of convenient methods and interfaces. But this lead to a little bug in the interface, a little shift in the displayed date. Of course, this comes from the old Java Calendar API curse and from a lack of precision in the documentation.

If you need to ask your user to pick a date on Android, there is a nice convenient class, the DatePickerDialog. The constructor is straightforward, you provide the context, a callback implementing OnDateSetListener and the information on the date to display. Once chosen, the dialog will call the callback, providing the selected date information.

In the constructor and the callback, the date information are provided by 3 integers, the year, the month and the day of month. First, this is a sample code in a DialogFragment where refDate is a JodaTime DateTime object:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {

    return new DatePickerDialog(getActivity(), mDateSetListener, refDate.getYear(), refDate.getMonthOfYear(), refDate.getDayOfMonth());
}

The calling activity or fragment implements the OnDataSetListener so lets say that you have this code sample:

@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
    DateTime eventDate = new DateTime(year, monthOfYear, dayOfMonth, 0, 0);
    Log.d("debug_tag", DateUtils.getRelativeTimeSpanString(this.eventDate.getMillis(), System.currentTimeMillis(), DateUtils.DAY_IN_MILLIS));
}

The date information you provide to the dialog is, of course, the displayed information. So, if I have defined a date being January 8th 2014 using a DateTime object, this is what Android will display :

Android DatePockerDialog sample

Displayed date for january 8th 2014 DateTime object

If I confirm, the log will show January 8th 2014… How comes ?

All the problem is in the monthOfYear parameter. Remember that Android is Java-based. So, it relies on the old Java APIs and yes, on the Calendar way of seeing dates and time.

For the month of January, if you use JodaTime, date.getMonthOfYear() will give 1. In Pyhton, date.month will give 1. In Objective-C, [date month] will give 1.

In Java’s Calendar, date.get(Calendar.MONTH) will give 0. As Android is Java based, the DatePickerDialog is expecting values based on the Calendar API.

The Java Calendar documentation is clear, January is a constant set to 0. Reading the Calendar API page is good enough as the MONTH constant is defined to start at 0. Why is January set to 0 ? This is part of the mysteries of some Java implementations and an old question. Maybe As mysterious and oldest than the name of the Doctor…

The Android API is not very helpful as it lacks of information. The constructor documentation is not giving an hint on the value to provide. You have to look for the OnDateSetListener onDateSet method definition to see what are the values expected because the month compatibility with the Calendar has been kept.

It is unclear why Java have kept this way to code months. I can understand that the Android team preferred to keep a compatibility with the native API. But if you are dealing with dates in a modern way on Android, remember to take care of that time shift.

About Darko Stankovski

Darko Stankovski is the founder and editor of Dad 3.0. You can find more about him trough the following links.