|The Day of the Integer|
Page 2 of 2
The problem with the code is that the programmer looked at the parseInt function and assumed that it was just a string to integer conversion facility. If you read the documentation you will find that it is also able to convert a string in other bases than 10 to an integer. To make use of this you have to specify the radix (i.e. base) as the second parameter.
displays 5 because 101 is 5 in binary and
displays 175 because AF is 175 in hex.
You can even do very strange base conversions that aren't normally encountered.
which displays 186 because AG is 186 in base 17. You can use letters to represent numerals - A is 10, B is 11 and so on.
This is, of course, all very useful. Unfortunately there is a small problem. If you omit the radix then base ten is assumed unless the string starts with 0x when hexadecimal is used or 0 when octal is used. Both of these conventions go back a long way into computing's history but the octal convention is dangerous because dates and other fixed format numbers are often written with leading zeros.
What this means is using ParseInt without a radix specified is dangerous.
For example, if the day string is "01" this is parsed as octal 01 which is just the same as decimal 1. Things doesn't work out quite as well when we reach "08" however because 8 should never occur in an octal number. In most cases the parseInt("08") returns zero and so does parseInt("09") which again should never occur in octal.
The rule is that that whenever parseInt reaches a character that isn't a valid numeral it stops parsing the string and returns the result of the conversion so far. Hence for "08" and "09" it returns zero.
As a two digit date string is only interpreted as octal when it starts with a zero days "08" and "09" are the only two that actually cause a problem. All other dates work perfectly and are either interpreted as decimal or octal numbers that work out to the same value as decimal would have given anyway.
The parseInt function is implemented in slightly different ways on different browser. In particular IE9 returns the decimal conversion of "08" i.e. eight but still follows the "return the conversion so far" rule of any other non-numeric characters. This makes our example problem work but who knows what other code this behaviour breaks. The good news is that in ECMAScript 5 strings starting with "0" are not parsed as octal - you have to specify the radix.
At the moment you have to be careful how you use parseInt.
I suppose you could conclude that the only pattern that avoids such problems is to always read the exact definition of any functions you are using. More specifically you should never assume that an optional parameter defaults to the desired behaviour if you leave it out.
In this case the simplest fix for the problem is indeed to specify the optional parameter. That is:
In fact don't think of parseInt as convert to integer. instead think of parseInt( ,10) as convert to decimal integer. You could even create your own foolproof parseInt10 function using:
You could even override the standard global parseInt function to provide the ECMAscript functionality in any browser but an even better idea is to use the Number function. This always performs a decimal conversion but it also has its problems. Number will convert a wider class of objects into a number including date objects. It also will return NaN if the object cannot be converted to a number and this includes any string with non-numeric characters.
In this case however we are sure that the parameter will be a correctly formatted string and so Number is perfectly safe and it works on all browsers and ECMAScript 5.