javascript parseInt is broken

posted September 4th 2007 at 1733 EDT in All, Firefox, IE, Javascript, Web

I was debugging some strange errors in a date conversion function I was writing, and I stumbled upon something that amazed me... a strange bug in parseInt


>>>parseInt('06')
6
>>>parseInt('07')
7
>>>parseInt('08')
0
>>>parseInt('09')
0
>>>parseFloat('08')
8
>>>parseFloat('09')
9
 

Clearly for the strings '08' and '09' parseInt fails to return the right value. One workaround is easy, use parseFloat.

Why does this happen and where should I report this? I find it extremely odd that it happens in both Firefox and Internet Explorer 6 & 7; there must be some explanation right?

You can test it out for yourself using the FireBug javascript console), or by using one of these two links

alert(parseInt('07')+' == 7 ?')
alert(parseInt('08')+' == 8 ?')

Ok, Ok, so now that I explained how you would expect it to work (and clearly how I expected it to work) I'm going to answer my own question (yes I hate it when I do that too)

The problem is with how parseInt guesses the base of your number. Read the parseInt spec. Instead of always defaulting to base 10, it tries to guess, and if the first character is '0' it thinks you want to parse as an octal number, and if it starts with '0x' it thinks you want hexadecimal.

So, the solution is either to use parseFloat or to always specify your base.

Defaults that change on their own can't be trusted.


>>>parseInt('08',10)
8
 

26 Responses

  1. #1 Jonathan van Zuijlekom
    2 years, 10 months ago

    It’s not broken. The parseInt function allways gueses if you don’t add the base/radix! That’s why I allways pass the base 10 to the function.

  2. #2 jehiah
    2 years, 10 months ago

    I know it’s not “broken”, my point was that because it guesses instead of always defaulting to the same base, you can’t reliably use the default (which is exactly what you expect to be able to do)

    I am also comparing it to python in my head thinking it would be ridiculous to assume that int() would not convert '08' to an integer. If you want hex conversions you specify that explicitly.

  3. #3 joelle
    2 years, 10 months ago

    for a second i looked quickly at your title and thought you were talking about parseltongue.

  4. #4 jv
    2 years, 9 months ago

    use parseInt('09',10) instead ; see the spec.
    It seems to work OK.

  5. #5 jehiah
    2 years, 9 months ago

    @jv: did you read what i posted? clearly using parseInt('09',10) is exactly what i said people need to do all the time! I was trying to make a strong case that the default functionality was poorly chosen, and causes the function to be broken.

  6. #6 Tim Harper
    2 years, 8 months ago

    Jehiah, I got what you were posted. Great stuff, I’ve never known about the unreliability of the supposed default, I’ll specify base10 from now on.

    This is a very surprising feature of JavaScript – surprising in a very bad way. Everyone knows that base 10 numbers are often padded with 0’s. It makes me wonder what someone was thinking when they made this decision.

  7. [...] After randomly searching for this problem (how do you search for something when you don’t really know what to search for?), I stumbled on this blog entry that explained it all: [...]

  8. #8 Mikkel Løkke
    2 years, 7 months ago

    Wow! I can’t believe how much time I just wasted on this! Do the people who write specifications not understand what “default” means? It is not readily interchangeable with “arbitrary”.

  9. #9 Flavio
    2 years, 3 months ago

    That was very helpful, I had no clue what was going on with my JS… thanks!

  10. #10 Paul-Joseph de Werk
    2 years, 2 months ago

    It’s not broken. According to the ECMAScipt Specification (JavaScript is a version of ECMAScript), strings with leading 0’s may be interpreted, at the implementation’s discretion, as either octal or decimal, if a radix of 0 or undefined is specified. implementations are encouraged to interpret as decimal, but it is not required.

    Being a programmer that is used to working with octal, decimal, and hexadecimal on a daily basis, I automatically interpret numbers with leading 0’s as octal and consider ‘08′, and ‘09′ to be invalid numbers unless I have a spec that tells me that decimals are left padded with 0’s.

  11. #11 jehiah
    2 years, 2 months ago

    @Paul-Joseph, I am not saying you should not be able to do one or the other at will when converting strings to one form or another, what i am arguing is that the default that the parseInt function uses should not change based upon the input, because integer values left padded with ‘0’s are not invalid and so one should not expect those integer values to be converted differently based on the default base 10 setting.

  12. #12 Justin The
    2 years, 2 months ago

    I was having the same problem and your article really saves my day…Thanks

  13. #13 soulcheck
    2 years, 2 months ago

    Another reason why I like opera.

  14. #14 Stuart
    2 years, 2 months ago

    A simpler (but probably unsupported) fix is to pre-fix the input stng with a ‘+’ e.g. parseInt(“+08″)

    Anyway here is a more interesting one. While trying to round numeric values to 2 decimal places I tried -

    this.rawValue = (parseInt(this.rawValue * 100) / 100)

    Probably not great code, I’m new to js, but it works UNTILL you input a value of EXACTLY 4.31

    It then returns 4.30 !!!!

    I have found no other number that does this – anyone got any ideas ?

  15. #15 Reggie Drake
    2 years, 1 month ago

    Just use Number. parseInt is a special-purpose function for parsing numbers from random strings, the fact that everyone is using it as a string->number conversion function is a historic accident. Number(“08″) is the recommended way to convert decimal numeric strings to numbers.

  16. #16 Jehiah
    2 years, 1 month ago

    @Reggie Good point about using Number to convert from string to int. parseInt() still has a few capabilities that I don’t see in Number and you hinted at one of them

    • Number only converts base 10 strings to numeric representation
    • parseInt converts any base string to numeric base 10 representation
    • parseInt converts to integer, dropping decimal values, Number does not. Sometimes that is desired.
  17. #17 Storm
    2 years, 1 month ago

    I’d just like to leave this for those getting a total “hard-on” dropping their “I am so leet and you are an idiot” comments.

    I develop in 13 (Yes, that’s a 1 and a 3) different languages. Some of them I know very well while others I know little. I (and I’m sure many other 16 hour day coders out there) simply don’t have the time to wade through thousands of lines of documentation when moving to a new language. We’re cowboys, we jump in and we start coding, we most likely never reach guru status unless the language becomes one of max 3 of our mosts used languages. So drop your holier than thou attitudes and support those who are kind enough to post findings like the OP did here. My 20k USD per month “all round coder” paycheck far outweighs your “guru” comments!

    As for the OP, many thanks, I just hit this bug now and was wondering what was causing it, many thanks for you short description into the problem (read feature) too. Always helps to have an idea of what is causing the issue.

  18. #18 shan
    2 years, 1 month ago

    Thanx for such kind of help.

  19. #19 veronica
    2 years ago

    Thanks for posting this. It’s helpful regardless of the reasoning behind it. I really don’t care why. I just need to get the code working!

  20. #20 Mike
    1 year, 5 months ago

    RTFM people. Paul-Joseph got it right. If the string begins with a zero, parseInt assumes it represents a number in octal. This is documented on the w3schools.com site, the first link when you Google ‘parseInt’.

  21. #21 raju dasa
    1 year, 5 months ago

    Thanks for your article. I got the answer to my problem, why ‘08′ or ‘09′ are not considered as integers in javascript.

  22. #22 Matt
    1 year, 3 months ago

    Good article, explained everything. Cheers!

  23. #23 desenfoque
    1 year, 1 month ago

    Thanks… I put the radix and now works fine….

  24. #24 Anonymous
    1 year, 1 month ago

    It does not mean that it’s “broken” just because it’s against YOUR interpretation of what should be default. The document clearly indicates the behavior and it also warns that it’s implementation dependent.

    You can claim that it’s another annoying idiosyncrasy of JavaScript. But it’s not broken…

    RTFM, my friend. RTFM.

  25. #25 Bruno
    1 year, 1 month ago

    Hey, Anonymous, and everyone who says it’s not broken.

    If you all go and “RTFM” as many of the defensors of the “not broken” say, you will actually see it IS BROKEN indeed.

    I’ve blogged about it, with excerpts from the ECMA-262 standard, THE authoritative information source for JavaScript (who says w3schools.com is authoritative? who says it is reliable?).

    Take a look: http://brunoreis.com/tech/old-javascript-implementation-bug-parsein/

    Quoting someone: “RTFM, my friend. RTFM.” But RTFAM, read the ** AUTHORITATIVE manual :-)

    Bruno

  26. #26 Paul-Joseph de Werk
    11 months, 1 week ago

    I did RTFM and it is not broken, read 15.1.2.2 steps 11 & 12. They state:

    1. Let R (radix) = 10
    2. If the length of S is at least 1 and the first character of S is “0″, then at the implementation’s discretion either let R = 8 or leave R unchanged.

    So, setting the radix to 8 and interpretting the string as octal is perfectly valid.