Here’s a puzzler for you: someone has written bad date handling code, but honestly, the bad date handling isn’t the real WTF. I mean, it’s bad, but it highlights something worse.
Ned inherited this method, along with a few others which we’ll probably look at in the future. It’s Java, so let’s just start with the method signature.
public static void checkTimestamp(String timestamp, String name)
throws IOException
Honestly, that pretty much covers it. What, you don’t see it? Well, let’s break out the whole method:
public static void checkTimestamp(String timestamp, String name)
throws IOException {
if (timestamp == null) {
return;
}
String msg = new String(
"Wrong date or time. (" + name + "=\"" + timestamp + "\")");
int len = timestamp.length();
if (len != 15) {
throw new IOException(msg);
}
for (int i = 0; i < (len - 1); i++) {
if (! Character.isDigit(timestamp.charAt(i))) {
throw new IOException(msg);
}
}
if (timestamp.charAt(len - 1) != 'Z') {
throw new IOException(msg);
}
int year = Integer.parseInt(timestamp.substring(0,4));
int month = Integer.parseInt(timestamp.substring(4,6));
int day = Integer.parseInt(timestamp.substring(6,8));
int hour = Integer.parseInt(timestamp.substring(8,10));
int minute = Integer.parseInt(timestamp.substring(10,12));
int second = Integer.parseInt(timestamp.substring(12,14));
if (day < 1) {
throw new IOException(msg);
}
if ((month < 1) || (month > 12)) {
throw new IOException(msg);
}
if (month == 2) {
if ((year %4 == 0 && year%100 != 0) || year%400 == 0) {
if (day > 29) {
throw new IOException(msg);
}
}
else {
if (day > 28) {
throw new IOException(msg);
}
}
}
if (month == 1 || month == 3 || month == 5 || month == 7
|| month == 8 || month == 10 || month == 12) {
if (day > 31) {
throw new IOException(msg);
}
}
if (month == 4 || month == 6 || month == 9 || month == 11) {
if (day > 30) {
throw new IOException(msg);
}
}
if ((hour < 0) || (hour > 24)) {
throw new IOException(msg);
}
if ((minute < 0) || (minute > 59)) {
throw new IOException(msg);
}
if ((second < 0) || (second > 59)) {
throw new IOException(msg);
}
}
Now, one of Java’s “interesting” ideas was adding checked exceptions to the language. If a method could throw an exception, it needs to announce what that exception is. This lets the compiler check and make sure that any exception which might be thrown is caught.
It’s also a pain for developers.
This developer felt that pain, and spent about three seconds think about it. "Well, something gave this method a timestamp as input, and if that input is wrong… we should throw an IOException
.
Which is a choice, I guess. Better than Exception
.
To “help” the calling code decide what to do, the exception helpfully sets the same exact message regardless of what went wrong: “Wrong date or time”.
But the real icing on this particular soggy pie is really the method name: checkTimestamp
. From that name, we know that we don’t expect it to have a valid timestamp, we need to check, so “an incorrectly formatted timestamp” isn’t an exceptional condition, it’s an expected behavior. This method should return a boolean value.
Oh, and also, it should just use built-in date handling, but that really seems secondary to this abuse of exceptions.