There is no built-in function formatNumber in javascript
– zerkmsFeb 16 '12 at 20:39

423

Please, to anyone reading this in the future, do not use float to store currency. You will loose precision and data. You should store it as a integer number of cents (or pennies etc.) and then convert prior to output.
– Philip WhitehouseMar 4 '12 at 13:35

@user1308743: Imagine you represent a very big number (lets say you are a lucky guy and it is your bank account balance). Would you really want to loose money because of a precision deficiency ?
– ereOnAug 6 '12 at 9:14

first of all, excellent, concise code. however, if you are american, you should change the defaults of d and t to be . and , respectively so that you don't have to specify them every time. also, i recommend modifying the beginning of the return statement to read: return s + '$' + [rest], otherwise you will not get a dollar sign.
– JasonJan 31 '11 at 23:58

683

Not sure why people think this code is beautiful. It is indecipherable. It seems to work nicely, but it is not beautiful.
– usrOct 24 '12 at 16:28

83

Is this formatMoney function copied from some minified JavaScript code somewhere? Can you not post the original? What do the variables c, d, i, j, n, s, and t stand for? Judging by the amount of upvotes and comments this post has I can assume this code has been copy pasted into production websites everywhere... Good luck maintaining the code if it has a bug some day!
– zuallauzDec 17 '12 at 20:41

Short and fast solution (works everywhere!)

The idea behind this solution is replacing matched sections with first match and comma, i.e. '$&,'. The matching is done using lookahead approach. You may read the expression as "match a number if it is followed by a sequence of three number sets (one or more) and a dot".

CoffeeScript version with of VisioN & kalisjoshua regexp and way of specifying decimal place (so you can leave the default of 2 or specify 0 for no decimal): Number.prototype.toMoney = (decimal=2) -> @toFixed(decimal).replace /(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,"
– Eric AndersonJun 18 '13 at 15:43

@hanumant The regular grammar is a bit complicated here, so I suggest you to read the manuals about regular expressions first (e.g. at MDN). The idea behind it is replacing matched sections with first match and comma, i.e. $1,. The matching is done using lookahead approach. You may read the expression as "match a number if it is followed by a sequence of three number sets (one or more) and a dot".
– VisioNOct 22 '13 at 15:08

2

@JuliendePrabère Please give an example of a long number which doesn't work with this approach.
– VisioNMar 25 '14 at 10:53

Use undefined in place of the first argument ('en-US' in the example) to use the system locale (the user locale in case the code is running in a browser).

Intl.NumberFormat vs Number.prototype.toLocaleString

A final note comparing this to the older .toLocaleString. They both offer essentially the same functionality. However, toLocaleString in its older incarnations (pre-Intl) does not actually support locales: it uses the system locale. Therefore, be sure that you're using the correct version (MDN suggests to check for the existence of Intl). Also, the performance of both is the same for a single item, but if you have a lot of numbers to format, using Intl.NumberFormat is ~70 times faster. Here's how to use toLocaleString:

Looks like it'd be great, but there is little browser support at the moment
– acorncomDec 6 '13 at 0:38

1

@acorncom Why do you say there is "little browser support"? The Number object has been around since Javascript 1.1. Please provide a reference that backs up your claim.
– Doug SAug 31 '15 at 3:43

1

Care should be taken that there is an old version of toLocaleString that uses the system locale, and a new (incompatible) one that comes from ECMAScript Intl API. Explained here. This answer seems to be intended for the old version.
– arossSep 14 '17 at 10:09

You may want to use '10' as the radix in parseInt. Otherwise, any number that starts with '0' will use octal numbering.
– sohtimsso1970Nov 15 '11 at 16:01

3

@sohtimsso1970: sorry for the late response, but could you explain some more? I don't see where a number could be interpreted as octal. The parseInt is called on the absolute value of the INTEGER part of the number. The INTEGER part can not start with ZERO unless it's just a ZERO! And parseInt(0) === 0 either octal or decimal.
– Marco DemaioFeb 9 '12 at 12:20

@Tracker1: I understood that a number starting with 0 is considered octal by parseInt. But in this code is IMPOSSIBLE for parseInt to receive 016 as input (or any other octal formatted value), because the argument passed to parseInt is 1st processed by Math.abs function. So there is no way for parseInt to receive a number that starts with zero unless it's just a zero or 0.nn (where nn are decimals). But both 0 and 0.nn strings would be converted by parseInt into a plain ZERO as suppsed to be.
– Marco DemaioMar 20 '12 at 14:57

This answer was almost there for me, but I needed it to be rounded to the nearest penny. This is what I used amount.toLocaleString('en-GB', { style: 'currency', currency: 'GBP', maximumFractionDigits: 2 });
– NicoNov 18 '14 at 11:47

The above code does rounding to the number of digits you want. See the example and type in 1.237 in the input box.
– Daniel BarbalaceMar 26 '15 at 17:36

3

Doesn't seem to work in Safari. It just returns the number as a String without any formatting.
– Lance AndersonMay 8 '15 at 3:22

Because 'locales' and 'options' arguments are supported just by a very small number of browsers, like Chrome 24, IE11 and Opera 15. Firefox, Safari and older versions of others still don't support it.
– VisioNSep 25 '13 at 6:50

3

Agreed, it's not fully supported across all browsers (yet), but it's still a solution. (And arguably the most valid solution, as its forward compatible with the non-supported browsers, and it's a documented feature of the Javascript api.)
– Nick GrealySep 25 '13 at 22:59

Note that your version doesn't properly round to two decimal digits. For example, 3.706 would be formatted as "£ 3.70", not as "£ 3.71" as it's supposed to be.
– Ates GoralSep 30 '08 at 23:33

Yes, that's OK in my particular case, since the amounts I'm working with already have at most 2 digits The reason I need to fix to 2 decimals is for amounts with no decimals or with only 1.
– Daniel MagliolaOct 2 '08 at 19:12

It's a great project to localize numbers, currencies and dates and to have them automatically formatted the right way according to the user locale! ...and despite it should be a jQuery extension, it's currently a 100% independent library. I suggest you all to try it out! :)

+1 to Jonathan M for providing the original method. Since this is explicitly a currency formatter, I went ahead and added the currency symbol (defaults to '$') to the output, and added a default comma as the thousands separator. If you don't actually want a currency symbol (or thousands separator), just use "" (empty string) as your argument for it.

this is a perfectly useful variable name. Converting it to n so you can save 3 characters at definition time may have been necessary in an era when RAM and bandwidth were counted in KB, but is merely obfuscatory in an era when the minifier will take care of all that before it ever hits production. The other clever micro-optimizations are at least debatable.
– XMLOct 18 '13 at 19:49

This might be a little late, but here's a method I just worked up for a coworker to add a locale-aware .toCurrencyString() function to all numbers. The internalization is for number grouping only, NOT the currency sign - if you're outputting dollars, use "$" as supplied, because $123 4567 in Japan or China is the same number of USD as $1,234,567 is here in the US. If you're outputting euro/etc., then change the currency sign from "$".

Declare this anywhere in your HEAD or wherever necessary, just before you need to use it:

As usually, there are multiple ways of doing the same thing but I would avoid using Number.prototype.toLocaleString since it can return different values based on the user settings.

I also don't recommend extending the Number.prototype - extending native objects prototypes is a bad practice since it can cause conflicts with other people code (e.g. libraries/frameworks/plugins) and may not be compatible with future JavaScript implementations/versions.

I believe that Regular Expressions are the best approach for the problem, here is my implementation:

Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).