Friday, 18 November 2005

Java quiz

What do you think will be the outcome for this code? This is something that I ran into today and wasted an hour (or 30 minutes, don't remember) on.

Date now = new Date();
// gets a calendar instance of the current time
Calendar cal = Calendar.getInstance();

// let's change the cal time to last year.
cal.add(Calendar.YEAR, -1);

System.out.println("Is " + cal.getTime() + " before " + now + " ???");
System.out.println(cal.before(now));


10 comments:

  1. Apart from the 3 question marks, one would have been sufficient, the code looks pretty confusing just looking at it. And not knowing any of the code that goes around it makes it quite difficult to figure out. But assuming the "now" variable holds the current date, and according to the comments, the calendar starts out with the current date, and then subtracts a year. So, at the end, it will print out true always, because 1 year ago, is always before now. Although, times like this is when a debugger is priceless.

    ReplyDelete
  2. Yes, you are right that both "new Date()" and "Calendar.getInstance()" return objects with the current date / time.
    Yes, subtracting one year from the calendar object would make it last year.
    Yes, it *looks* like it will always return true.
    Now run it. You don't need a debugger.
    I didn't post trivial looking code just for the fun of it.

    ReplyDelete
  3. OK, I'll tell you what is wrong with innocently "correct" piece of code. Calendar is using comparator to check this kind of stuff and the first thing it does is to check if the object passed in is Calendar type, if not it returns false. You have to pass in the calendar to use before and after methods.

    ReplyDelete
  4. Yes, you're right that it will always return false if the object isn't a Calendar. But why wouldn't you just 1) throw an exception or 2) have the method accept a "Calendar" instead of "Object"?
    I'm just frustrated with it 'cause I had to waste time tracking this down and I don't understand the design decision behind it.
    When you implement compareTo(Object) you are supposed to throw a class cast exception if what's passed in is the wrong type.
    I just don't like the "fail silently" idea.
    Fail early, fail hard. ;-)

    ReplyDelete
  5. First, now and cal are both defined in the code we see, so we can always be sure what type they are. I don't see how cal could not be a Calendar. I don't see a function, or where any variables may have been passed in.

    ReplyDelete
  6. Jim:
    In my opinion I would limit after() and before() method to accept calendar only in that case, since they only allow calendar to be passed in anyway.
    Kibbee:
    What the hell are you talking about?

    ReplyDelete
  7. Oh, so we're talking about the before function? well, theoretically, you could have the before function accept both a calendar and a date. As long as you write the proper functions, there's no reason why you couldn't check the date of the calendar, and compare it to the date stored in a date variable. It's something that might be very useful. There's nothing in the code that I see that says the before function can't be used to compare a date to the calendar. This is why I assumed that it always returned true, because I was assuming that Calendar.before actually was supposed to accept a date parameter, and there was nothing in the code that I saw to make me think otherwise.

    ReplyDelete
  8. hahaha... that's the whole point Kibbee!
    The Date and Calendar classes are both part of Java 1.4 (at least) so I can't change them. The "before" method will accept a Date object, well, any "Object" at all, but it only seems to work with other Calendar objects.
    There IS nothing in the code to make you think otherwise, that's why I spent time tracking it down and why I said I "wasted an hour [on it]". It's weird non-intuitive behaviour and that's the whole point of the post: to make others aware of it.

    ReplyDelete
  9. You could (maybe) make another class called Calendar which inherits from the Java Calendar, and if it's in the same namespace as the rest of your code could probably be referenced as Calendar. You could then add another function to accept date objects, so that this code would work. Since I don't use Java on a day-to-day basis, I don't really know that Date and Calendar are part of Java, nor is there anything in the code to point to this. It seems that Java is a little broken if it can accept any object for the "before" function, but only works correctly if you pass in a calendar. If you look at the API docs, it does exactly what you describe, but I think this function is still bad. If it's only valid for calendar objects, why would it even accept anything else?

    ReplyDelete