285

Try executing the following in JavaScript:

parseInt('01'); //equals 1
parseInt('02'); //equals 2
parseInt('03'); //equals 3
parseInt('04'); //equals 4
parseInt('05'); //equals 5
parseInt('06'); //equals 6
parseInt('07'); //equals 7
parseInt('08'); //equals 0 !!
parseInt('09'); //equals 0 !!

I just learned the hard way that JavaScript thinks the leading zero indicates an octal integer, and since there is no "8" or "9" in base-8, the function returns zero. Like it or not, this is by design.

What are the workarounds?

Note: For sake of completeness, I'm about to post a solution, but it's a solution that I hate, so please post other/better answers.


Update:

The 5th Edition of the JavaScript standard (ECMA-262) introduces a breaking change that eliminates this behavior. Mozilla has a good write-up.

cнŝdk
  • 31,391
  • 7
  • 56
  • 78
Portman
  • 31,785
  • 25
  • 82
  • 101
  • 22
    Step 1) Do yourself a favor and always include the radix as mentioned in the previous answers as well as in Doug's book. Step 2) If you are serious about learning JavaScript, then get yourself a copy of Doug's book. It is invaluable. My fav book so far. Here's a review fyi: http://realtech.burningbird.net/learning-javascript/basics/javascript-the-good-parts – fuentesjr May 12 '09 at 01:25
  • 9
    In ECMAScript 5th Edition-compatible browsers, such as Internet Explorer 9, the base parameter defaults to `10` (decimal) unless the number to parse is prefixed with `0x`, e.g. `0xFF`, in which case the base parameter defaults to 16. Hopefully, one day, this issue will be a distant memory. – Andy E May 09 '11 at 10:02
  • 2
    How about just `+'08' === 8`? True! Maybe you really need `parseInt` for your real code, but not for the above. – kojiro Dec 24 '11 at 14:04
  • 1
    a) this is not a bug, fix the title b) `Number('08')` – OnTheFly Jan 06 '12 at 20:01
  • Safari’s JavaScript engine aligned its behavior closer to the ECMAScript specification. ... the parseInt method won’t parse octal numbers anymore see http://trac.webkit.org/changeset/103922 – Mark Jan 20 '12 at 00:57
  • 4
    @portman: *"the 5th Edition...introduces a breaking change that eliminates this behavior"* Probably worth pointing out that even in the 3rd edition (13 years ago), implementations were "encouraged" not to do it: *"When radix is `0` or `undefined` and the string's number begins with a `0` digit not followed by an `x` or `X`, then the implementation may, at its discretion, interpret the number either as being octal or as being decimal. **Implementations are encouraged to interpret numbers in this case as being decimal.**"* (my emphasis) – T.J. Crowder Feb 08 '12 at 10:04
  • Thanks for the update. I just read this in [strange language features](http://stackoverflow.com/q/1995113/562769) and wondered why it didn't work. – Martin Thoma Jun 26 '13 at 20:17
  • Just as a note of where it happens to this moment of time: Google Docs javascript still parses it to 0. – Ruslan Bes Aug 01 '14 at 07:59
  • It took me 3 days to pinpoint this error which happens only in ie7 or compatibility mode in explorer. The hours "08:mm" got converted to "00:mm". – Ronen Festinger Oct 16 '15 at 00:47

10 Answers10

333

This is a common Javascript gotcha with a simple solution:

Just specify the base, or 'radix', like so:

parseInt('08',10); // 8

You could also use Number:

Number('08'); // 8
groovecoder
  • 1,551
  • 1
  • 17
  • 27
Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • 10
    Number needs quotes around the 08. Also just be warned, Number('08.123') will produce 8.123 as its output. If you really want an integer, don't use Number (or pattern-match your input to ensure integers only). – Jason S May 11 '09 at 22:22
  • 3
    Number(08); gives me 8 in Firefox and IE. – Paolo Bergantino May 11 '09 at 22:23
  • 3
    it's not part of the ECMAscript standard. I'm testing on JSDB which uses Spidermonkey 1.7 (=Firefox JS engine), and complains "08 is not a legal ECMA-262 octal constant" – Jason S May 11 '09 at 22:25
  • 5
    Still, use '08' in quotes. 08 doesn't meet the ECMA-262 standard and isn't guaranteed to succeed w/o warnings and/or errors and/or a particular specified behavior. – Jason S May 11 '09 at 22:52
  • Old question, but note that Number is different than parseInt: http://stackoverflow.com/a/4090577 – Gary S. Weaver Feb 03 '17 at 22:51
44

If you know your value will be in the signed 32 bit integer range, then ~~x will do the correct thing in all scenarios.

~~"08" === 8
~~"foobar" === 0
~~(1.99) === 1
~~(-1.99)  === -1

If you look up binary not (~), the spec requires a "ToInt32" conversion for the argument which does the obvious conversion to an Int32 and is specified to coerce NaN values to zero.

Yes, this is incredibly hackish but is so convenient...

Karl Guertin
  • 4,346
  • 2
  • 22
  • 19
24

From the parseInt documentation, use the optional radix argument to specify base-10:

parseInt('08', 10); //equals 8
parseInt('09', 10); //equals 9

This strikes me as pedantic, confusing, and verbose (really, an extra argument in every single parseInt?) so I'm hoping there is a Better Way.

Portman
  • 31,785
  • 25
  • 82
  • 101
  • 7
    if you Don't Like Verbosity then just make your own function that calls the builtin function and fills in the arguments you always keep constant. – Jason S May 11 '09 at 22:20
  • 3
    Riiiiiiight, because it's not like every single person on StackOverflow would berate you for writing function parseIntB10. Writing your own wrapper function is a terrible idea for this purpose. – Stefan Kendall May 11 '09 at 22:36
  • 2
    @iftrue: I think you missed my point. I personally don't mind just doing parseInt(someString, 10) everywhere to ensure that I force base 10. The OP appears not to like this approach, so I suggested an alternative, which I wouldn't personally use but perhaps it meets his needs. (this is apparently the thinking behind JQuery: make it convenient by adding extra complexity. I don't use JQuery but many people find it useful.) – Jason S May 11 '09 at 23:26
  • 6
    Actually it's really important to wrap `parseInt` for convenient use in functional expressions, like `map` in `["7","4","09","5"].map(parseInt);` `Map` will pass the *index* of the element in the array as the second argument, which will be interpreted by `parseInt` as the base unless you wrap it. – Plynx Feb 24 '13 at 07:16
12
function parseDecimal(s) { return parseInt(s, 10); }

edit: making your own function, to do what you really want, is just an option if you don't like adding the ",10" all the time to the parseInt() call. It has the disadvantage of being a nonstandard function: more convenient for you if you use it a lot, but perhaps more confusing for others.

Jason S
  • 184,598
  • 164
  • 608
  • 970
10

Specify the base:

var number = parseInt(s, 10);
RichieHindle
  • 272,464
  • 47
  • 358
  • 399
  • Wow you guys are fast. I even had my answer on the clipboard. Are you plugged directly into the Internet, Neo-style? – Portman May 11 '09 at 22:17
  • 1
    Why the devil is it not defaulted to base 10 – Tom Gullen Aug 21 '10 at 10:08
  • 2
    Maybe because it's not primarily meant as a String->Number converting function, but a function that reads a Number from a base b number String. – wnrph Nov 16 '10 at 22:13
  • 3
    it is defaulted to base 10 but leading zeros are a widespread way to indicate octal. – Nathan Dec 08 '10 at 22:09
7

You may also, instead of using parseFloat or parseInt, use the unary operator (+).

+"01"
// => 1

+"02"
// => 2

+"03"
// => 3

+"04"
// => 4

+"05"
// => 5

+"06"
// => 6

+"07"
// => 7

+"08"
// => 8

+"09"
// => 9

and for good measure

+"09.09"
// => 9.09

MDN Link

The unary plus operator precedes its operand and evaluates to its operand but attempts to convert it into a number, if it isn't already. Although unary negation (-) also can convert non-numbers, unary plus is the fastest and preferred way of converting something into a number, because it does not perform any other operations on the number.

SoEzPz
  • 14,958
  • 8
  • 61
  • 64
7

Would it be very naughty to replace parseInt with a version that assumes decimal if it has no second parameter? (note - not tested)

parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}
Andrew Duffy
  • 6,800
  • 2
  • 23
  • 17
  • 2
    yes, that would be naughty -- it would break other code that relied on the standard behavior. – jes5199 Oct 03 '09 at 22:53
  • 4
    That is true, but there isn't much of that. It also isn't standard behaviour - octal support is optional. – Andrew Duffy Oct 05 '09 at 10:14
  • 3
    But you're also dropping hex support which isn't optional, is it? This should always be true: `parseInt("0xFFFFFF") === 16777215`, but with your naughty hack in place it no longer works `parseInt("0xFFFFFF") === 0` – Timo Nov 06 '13 at 16:23
  • 2
    @jes5199 But then [ECMAScript 5 decided to break other code that relied on that behavior](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#Octal_interpretations_with_no_radix) – Piyin Jan 23 '18 at 21:24
5

How about this for decimal:

('09'-0) === 9  // true

('009'-0) === 9 // true
Mark Hall
  • 53,938
  • 9
  • 94
  • 111
Gordon K
  • 51
  • 1
  • 2
4

This issue cannot be replicated in latest Chrome nor Firefox (2019).

Test:

console.log(parseInt('08'));
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
Andrija
  • 14,037
  • 18
  • 60
  • 87
  • 1
    Yeah, looks like someone finally decided the octal stuff caused more problems than it solved. Though would hate to be one of the 0.01% of people who actually used/relied upon the feature where anything with a leading `0` would parse as octal. :) – aroth Sep 02 '20 at 05:26
  • 1
    That's going to cause some really nasty bugs for some people! – aidan Sep 04 '20 at 01:47
4

If you've done a bunch of coding already with parseInt and don't want to add ",10" to everything, you can just override the function to make base 10 the default:

window._oldParseInt = window.parseInt;
window.parseInt = function(str, rad) {
    if (! rad) {
        return _oldParseInt(str, 10);
    }
    return _oldParseInt(str, rad);
};

That may confuse a later reader, so making a parseInt10() function might be more self-explanatory. Personally I prefer using a simple function than having to add ",10" all the time - just creates more opportunity for mistakes.

ingredient_15939
  • 3,022
  • 7
  • 35
  • 55