2446

I would like to format a price in JavaScript. I'd like a function which takes a float as an argument and returns a string formatted like this:

"$ 2,500.00"

How can I do this?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Daniel Magliola
  • 30,898
  • 61
  • 164
  • 243
  • 633
    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 Whitehouse Mar 04 '12 at 13:35
  • @PhilipWhitehouse what would cause loss of data of less than 2 decimal places? – Kyle May 21 '12 at 20:23
  • 12
    @user1308743 Float doesn't store decimal places. It stores numbers using a value, base and offset. 0.01 is not actually representable. See: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems – Philip Whitehouse Jun 10 '12 at 11:11
  • 7
    @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 ? – ereOn Aug 06 '12 at 09:14
  • 3
    @PhilipWhitehouse is right: it's definitely a bad idea to store money as floats. However, storing money as cents only works when you're dealing only in whole cents, which isn't precise enough for a lot of operations. We've recently switched to storing currencies as a 'Big Decimal', of 7 decimal places. You can use Javascript's toFixed(7) method to emulate this, though it returns a string by necessity. It does mean you can deal in familiar $xx.xx formats, though, without converting back from cents. – Ben Hull May 15 '13 at 23:52
  • 201
    So why hasn't anyone suggested the following? (2500).toLocaleString("en-GB", {style: "currency", currency: "GBP", minimumFractionDigits: 2}) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString#Browser_Compatibility – Nick Grealy Sep 25 '13 at 01:41
  • @NickG I am guessing because of it's pretty rubbish support from legacy browsers. But in an ideal world (where everyone has up to date browsers) this would be the best solution. – Ben Aug 19 '14 at 13:27
  • 5
    you can use this Numeral.js javascript library to convert your numbers to dollars. (http://numeraljs.com/) for reference. – Aarthi Chandrasekaran Sep 11 '14 at 10:30
  • Don't forget the English language wrap negative currency amounts in parentthesis `($#,##0.00)`. – einstein Oct 26 '14 at 01:45
  • 2
    @NickG I was enthusiast of your solution but does not work in IPad, Android and IE7, works only in Mozilla and Opera of what I checked – Testo Testini Feb 05 '15 at 21:14
  • @TestoTestini - thanks, fyi Mozilla have documented a compatibility table for browsers https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString#Browser_Compatibility – Nick Grealy Feb 05 '15 at 22:47
  • There's nothing wrong with being generic, is it? – Bergi May 10 '15 at 13:18
  • @PhilipWhitehouse Year 2022, I am from the future, I thanks for your message, I will use it to prevent a pandemic and a war :P – albanx Dec 17 '22 at 23:57

67 Answers67

2718

Intl.NumberFormat

JavaScript has a number formatter (part of the Internationalization API).

// Create our number formatter.
const formatter = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',

  // These options are needed to round to whole numbers if that's what you want.
  //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
  //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
});

console.log(formatter.format(2500)); /* $2,500.00 */

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). Further explanation of the locale code.

Here's a list of the currency codes.

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. So when debugging old browsers, be sure that you're using the correct version (MDN suggests to check for the existence of Intl). There isn't any need to worry about this at all if you don't care about old browsers or just use the shim.

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. Therefore, it's usually best to use Intl.NumberFormat and instantiate only once per page load. Anyway, here's the equivalent usage of toLocaleString:

console.log((2500).toLocaleString('en-US', {
  style: 'currency',
  currency: 'USD',
})); /* $2,500.00 */

Some notes on browser support and Node.js

  • Browser support is no longer an issue nowadays with 98% support globally, 99% in the US and 99+% in the EU
  • There is a shim to support it on fossilized browsers (like Internet Explorer 8), should you really need to
  • Node.js before v13 only supports en-US out of the box. One solution is to install full-icu, see here for more information
  • Have a look at CanIUse for more information
Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
aross
  • 3,325
  • 3
  • 34
  • 42
  • 32
    Pretty sure a quite high % of browsers now support this. This should be upvoted much more. – flq Dec 23 '16 at 21:34
  • 2
    This is a great answer and I have it working with a dynamic currency value so if use is in Europe then it changes to EUR and shows the euro sign. Works a treat! – Sprose Sep 14 '17 at 09:32
  • Works great in React Native as well! – flyandi Jun 13 '18 at 22:48
  • 5
    It's 2018 and this is basically supported everywhere. This should be the correct answer. – Kabir Sarin Sep 27 '18 at 06:38
  • 1
    Support as far back as Internet Explorer 11 (IE 11), with all major browsers supporting as well. – Matt Jensen Feb 07 '20 at 15:04
  • is there a way to reverse this getting $2,500.00 back to a string like 2500.00 – RkuangDev Aug 26 '20 at 01:57
  • @RkuangDev Sure, but you need to know the decimal separator used. If it's a dot (easiest scenario), this will work: `parseFloat('$2,345.67'.replace(/[^0-9.]/g, ''))`. Beware of floats for currency, of course – aross Aug 26 '20 at 09:42
  • upvoting this in 2022. This should be the accepted answer for wide compatibility and simplicity (as it should be) – Qiqo Mar 22 '22 at 10:32
  • I had an issue with Chrome version 87 and below using `maximumFractionDigits: 0` - refuses to use 0 as it's value. – Josh Bonnick Apr 07 '22 at 09:41
  • @JoshBonnick That probably happened due to incomplete/outdated libICU used. Possibly platform related, if Chrome tries to use (or tried to) the system ICU rather than a shipped one. – aross Apr 07 '22 at 15:17
  • @aross It ended up being because the default value for `minimumFractionDigits` was 2 - so min 2 and max 0 caused a `Invalid range error` - took me a while to figure this out, v88+ just accepted a max of 0 – Josh Bonnick Apr 11 '22 at 13:44
  • @JoshBonnick Funny, Firefox never had this issue so sounds like a Chrome bug then. – aross Apr 12 '22 at 08:58
  • Unfortunately it's not well supported by all browsers. and when it comes to react and next js we have loads of hydration issues with it – Sargis Abovyan Jun 21 '23 at 13:32
  • @SargisAbovyan I can't speak for your browser requirements, but 99% support is enough for most people. As for , sounds like you just need some good ol' debugging. It's *your* job as developer to write the required glue code. – aross Jun 22 '23 at 10:03
1960

Number.prototype.toFixed

This solution is compatible with every single major browser:

  const profits = 2489.8237;

  profits.toFixed(3) // Returns 2489.824 (rounds up)
  profits.toFixed(2) // Returns 2489.82
  profits.toFixed(7) // Returns 2489.8237000 (pads the decimals)

All you need is to add the currency symbol (e.g. "$" + profits.toFixed(2)) and you will have your amount in dollars.

Custom function

If you require the use of , between each digit, you can use this function:

function formatMoney(number, decPlaces, decSep, thouSep) {
    decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces,
    decSep = typeof decSep === "undefined" ? "." : decSep;
    thouSep = typeof thouSep === "undefined" ? "," : thouSep;
    var sign = number < 0 ? "-" : "";
    var i = String(parseInt(number = Math.abs(Number(number) || 0).toFixed(decPlaces)));
    var j = (j = i.length) > 3 ? j % 3 : 0;

    return sign +
        (j ? i.substr(0, j) + thouSep : "") +
        i.substr(j).replace(/(\decSep{3})(?=\decSep)/g, "$1" + thouSep) +
        (decPlaces ? decSep + Math.abs(number - i).toFixed(decPlaces).slice(2) : "");
}

document.getElementById("b").addEventListener("click", event => {
  document.getElementById("x").innerText = "Result was: " + formatMoney(document.getElementById("d").value);
});
<label>Insert your amount: <input id="d" type="text" placeholder="Cash amount" /></label>
<br />
<button id="b">Get Output</button>
<p id="x">(press button to get output)</p>

Use it like so:

(123456789.12345).formatMoney(2, ".", ",");

If you're always going to use '.' and ',', you can leave them off your method call, and the method will default them for you.

(123456789.12345).formatMoney(2);

If your culture has the two symbols flipped (i.e., Europeans) and you would like to use the defaults, just paste over the following two lines in the formatMoney method:

    d = d == undefined ? "," : d,
    t = t == undefined ? "." : t,

Custom function (ES6)

If you can use modern ECMAScript syntax (i.e., through Babel), you can use this simpler function instead:

function formatMoney(amount, decimalCount = 2, decimal = ".", thousands = ",") {
  try {
    decimalCount = Math.abs(decimalCount);
    decimalCount = isNaN(decimalCount) ? 2 : decimalCount;

    const negativeSign = amount < 0 ? "-" : "";

    let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
    let j = (i.length > 3) ? i.length % 3 : 0;

    return negativeSign +
      (j ? i.substr(0, j) + thousands : '') +
      i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) +
      (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "");
  } catch (e) {
    console.log(e)
  }
};

document.getElementById("b").addEventListener("click", event => {
  document.getElementById("x").innerText = "Result was: " + formatMoney(document.getElementById("d").value);
});
<label>Insert your amount: <input id="d" type="text" placeholder="Cash amount" /></label>
<br />
<button id="b">Get Output</button>
<p id="x">(press button to get output)</p>
Rafa Guillermo
  • 14,474
  • 3
  • 18
  • 54
Patrick Desjardins
  • 136,852
  • 88
  • 292
  • 341
  • 2
    If you always want to round up on 5 and down below 5, you cannot rely on toFixed() because of standard issues involved in representing floating point in binary. For example, try `(1.005).toFixed(2)`. – Ryan Oct 19 '10 at 19:20
  • 28
    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. – Jason Jan 31 '11 at 23:58
  • 1
    Thanks, this is great. Modified to work with user input strings instead (strips the string to numerics first in case they enter $1,500). String.prototype.formatMoney = function(c, d, t){ var n_dirty = this, n = n_dirty.replace(/[^\d.]/g,''), c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "." : d, t = t == undefined ? "," : t, s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0; return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ""); }; – Zhenya Aug 20 '11 at 00:58
  • You may want to use '10' as the radix in parseInt. Otherwise, any number that starts with '0' will use octal numbering. – sohtimsso1970 Nov 15 '11 at 16:01
  • The default value of 0 to be octal is still there but deprecated. But yes you can add it if you want. – Patrick Desjardins Nov 15 '11 at 18:10
  • 801
    Not sure why people think this code is beautiful. It is indecipherable. It seems to work nicely, but it is not beautiful. – usr Oct 24 '12 at 16:28
  • 91
    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! – zuallauz Dec 17 '12 at 20:41
  • 7
    This solution doesn't work very well. 1.155.formatMoney(2,'.',',) === '1.16', but 2.155.formatMoney(2,'.',',') === '2.15' – Nick Colgan Dec 20 '12 at 22:52
  • 273
    "poetry"? More like obscurity. This isn't code golf; use a little white space. Proper var names wouldn't hurt, either. – keithjgrant Dec 30 '12 at 14:07
  • 2
    Not mentioning, that `d == undefined` is used, while `typeof(d) === 'undefined'` should be in place. – trejder Aug 27 '13 at 08:04
  • 2
    @trejder why so? If you have silly programmers that define undefined as a variable with content you're good to go. Btw you don't need to (and so should not) use parenthesis for typeof. – Micaël Félix Sep 25 '13 at 13:35
  • 4
    @MykaEyl Read about JS fundamentals before you say things, that are... a little bit wrong. A variable named `undefined` is defined **by JS**, not by some silly programmers and you **should** use parenthesis for `typeof`, because without it you'll be comparing it to that variable, named `undefined`. I don't present here my own thoughts, I just copied what is expressed in many SO answers and in many sources. Don't have time to find example right now, but you'll for sure find it, if you google a little bit more. – trejder Sep 25 '13 at 15:23
  • 2
    @trejder The parenthesis with the typeof make absolutely no difference to how the construct is parsed that form - [`typeof` has the same precedence as a unary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators). Also the previous comment was saying that it's *safe* to rely that `undefined` evaluates to `(void 0)` as long as a "silly programmer" doesn't introduce a shadowing `undefined` local variable or rebind `window.undefined`. (I would consider that code the offender, not the code using `undefined`.) – user2864740 Nov 18 '13 at 19:17
  • @user2864740 On second thought, I agree (of course!) on not using parenthesis (I had to be blind, when first time reading _Myka Eyl_'s comment! :]). But I disagree on second part. The reason, why you should use `typeof d === 'undefined'` instead of `d === undefined` is, that with first approach you don't have to care about _silly developers_. Since world is overwhelmed by _silly developers_, we need to spend our time on actual coding, not of foreseeing _silly developers_' possible attempts to ruin our code, right? :] – trejder Nov 18 '13 at 19:49
  • @trejder I've *never* run into that problem. Any environment in which `undefined` has been redefined to a value other than `(void 0)` is an environment which I will *not* support. (In Python 2.x, True and False were just variables - e.g. `True,False=False,True` is permissible - but there was never any push to find a "safe" method.) – user2864740 Nov 18 '13 at 19:56
  • 3
    @trejder *Since world is overwhelmed by silly developers, we need to spend our time on actual coding, not of foreseeing silly developers' possible attempts to ruin our code, right?* => Following that line of thought, isn't `typeof(d) === 'undefined'` an attempt at *foreseeing silly developers' possible attempts to ruin our code*? If someone actually redefined `undefined`, I wouldn't trust them not to do something else to break your code. – Bob Jan 17 '14 at 03:19
  • 2
    @RobQuist He almost certainly meant flipped in comparison to what is in the code and not as an invitation to re-fight the Revolutionary War. – McGuireV10 May 21 '14 at 15:57
  • As previous commenters have mentioned, this is not just confusing, it is also wrong. It gives 49.65.formatMoney(1,'.',',') => 49.6 – hlascelles Dec 09 '14 at 12:13
  • I was using this, but got an error, so adding var myMoney = Number(myMoney).toFixed(2); adding Number() worked. – CookieCoder Dec 11 '14 at 17:03
  • 4
    So many sourpusses in these comments. Wow, sure the code may not be the prettiest, but if you're worth your salt as a 'programmer', it is definitely not overly complicated or undecipherable, assuming you know how to read code, that is. And who ever maintains code they've copied and not created themselves anyway? – Deji Nov 26 '15 at 10:33
  • 3
    @Deji, coding style standards, naming things, code structuring, commenting and annotating be damned. – aross Dec 16 '15 at 08:56
  • @aross Is this question related to coding style standards, "naming things", code structuring, commenting and annoting? Is you vaguely mentioning any of those concepts providing any reasons that the particular code above is not a fitting answer? No... – Deji Dec 16 '15 at 13:30
  • @Deji So you would even consider obfuscated code a good answer? – aross Dec 16 '15 at 15:05
  • 2
    @aross Depends on the question. That's what I think you're not getting here - the comments aren't for judging the quality of the code, but the quality of the ANSWER. I really shouldn't have to explain how answers to questions are usually judged for quality... – Deji Dec 16 '15 at 15:08
  • 6
    Fortunately this is a community wiki, so any of you complaining about the code format/readability can just fix it on your own. – Kevin B Dec 16 '15 at 16:20
  • This function is incorrect: > (2030).formatMoney(0, '.', ' '); < "2 03 0" – Anton P Robul Mar 18 '16 at 19:24
  • Strange code, to my mind, ex. value gets re-assigned twice within the function, makes it very dificult to debug. With decimalPlaces = 0, the value is implicitly rounded by "toFixed", which is not indented in my case. – wosis Apr 28 '16 at 08:41
  • 49
    [*Any fool can write code that a computer can understand. Good programmers write code that humans can understand*](http://stackoverflow.com/a/522907/542251) – Liam Jun 07 '16 at 12:32
  • 3
    How did such a terrible practice get 1K+ upvotes? Not to mention it was written pre-minified. –  Aug 30 '16 at 21:52
  • Because I dont like code I can't read I rewrote it to be more developer friendly here: http://syntaxwarriors.com/p/18/Format-currency-in-Javascript Pretty much the same thing but readable. – JensB Dec 20 '16 at 10:12
  • A non-minified version: http://www.josscrowcroft.com/2011/code/format-unformat-money-currency-javascript/ (see "JavaScript Money Format"). – Victor Dombrovsky Dec 30 '16 at 18:48
  • The `toLocaleString()` prototype, does the same thing with less code. and is more robust. [Answered Here](https://stackoverflow.com/a/26745078/5063323) – Mark Carpenter Jr Jun 27 '17 at 14:22
  • 3
    I personally think this solution is garbage. You don't use sensical variable names, you modify the `prototype` of a built-in with an _enumerable_ property, and your code doesn't even make sense, even if it does work. – Patrick Roberts Jul 18 '17 at 04:12
  • 1
    This answer is somewhat outdated now. [See the answer about Intl.numberformat below](https://stackoverflow.com/a/16233919/4641017) – Captain Hypertext Nov 10 '17 at 15:49
  • 1
    If the date could be null then you need to call the function like this: `formatMoney(someDate, 2)` instead of `someDate.formatMoney(2)` otherwise you get "Uncaught TypeError: Cannot read property 'value' of null" when it is. – Robin Wilson Dec 15 '18 at 19:03
  • I'm surprised no one mentioned that the line `j = (j = i.length) > 3 ? j % 3 : 0;` is calling for j before it is defined – Caio Mar May 30 '19 at 23:11
  • 4
    WARNING! The non-ES6 code is not functional as of 10/31/2019, I am surprised it got so many upvotes! Please correct the following simple cases: 100000 (results in 100000.00) and 1000000 (results in 1,000000.00) – ryanm Oct 31 '19 at 14:12
  • is there a way to discredit this answer. its no longer relevant. – Jeff C Jun 25 '20 at 21:19
  • 1
    Everyone just vote-down this answer so the proper answer can be more visible – TheGeekZn Nov 09 '20 at 08:57
  • 1
    I'd like to nominate this answer to be the most upvoted answer that needs to be down voted for heavens sake. – Martin Braun Nov 24 '20 at 01:55
  • The "Custom function" code is incorrect. For example when running the code snippet, 1234567.12 is returned as 1,234567.12, it's just plain wrong. – Mike Jarema Feb 17 '21 at 21:38
  • I had to add the line `let j = 0;` before using j. Issues with the code in some developers browsers... But in other cases still working. Weird. – JotaPardo Apr 26 '21 at 15:12
1500

Short and fast solution (works everywhere!)

(12345.67).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');  // 12,345.67

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".

TESTS:

1        --> "1.00"
12       --> "12.00"
123      --> "123.00"
1234     --> "1,234.00"
12345    --> "12,345.00"
123456   --> "123,456.00"
1234567  --> "1,234,567.00"
12345.67 --> "12,345.67"

DEMO: http://jsfiddle.net/hAfMM/9571/


Extended short solution

You can also extend the prototype of Number object to add additional support of any number of decimals [0 .. n] and the size of number groups [0 .. x]:

/**
 * Number.prototype.format(n, x)
 * 
 * @param integer n: length of decimal
 * @param integer x: length of sections
 */
Number.prototype.format = function(n, x) {
    var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\.' : '$') + ')';
    return this.toFixed(Math.max(0, ~~n)).replace(new RegExp(re, 'g'), '$&,');
};

1234..format();           // "1,234"
12345..format(2);         // "12,345.00"
123456.7.format(3, 2);    // "12,34,56.700"
123456.789.format(2, 4);  // "12,3456.79"

DEMO / TESTS: http://jsfiddle.net/hAfMM/435/


Super extended short solution

In this super extended version you may set different delimiter types:

/**
 * Number.prototype.format(n, x, s, c)
 * 
 * @param integer n: length of decimal
 * @param integer x: length of whole part
 * @param mixed   s: sections delimiter
 * @param mixed   c: decimal delimiter
 */
Number.prototype.format = function(n, x, s, c) {
    var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
        num = this.toFixed(Math.max(0, ~~n));

    return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
};

12345678.9.format(2, 3, '.', ',');  // "12.345.678,90"
123456.789.format(4, 4, ' ', ':');  // "12 3456:7890"
12345678.9.format(0, 3, '-');       // "12-345-679"

DEMO / TESTS: http://jsfiddle.net/hAfMM/612/

VisioN
  • 143,310
  • 32
  • 282
  • 281
  • 22
    I actually went a step further: `.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")`. – kalisjoshua Mar 21 '13 at 02:50
  • 4
    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 Anderson Jun 18 '13 at 15:43
  • If we call toFixed(0), the commas disappear, any idea on getting it to work with `this.toFixed(0).replace(/(\d)(?=(\d{3})+\.)/g, "$1,")`? – Abbas Aug 14 '13 at 17:09
  • 11
    @Abbas Yeah, replace `\.` with `$` (end of line), i.e. `this.toFixed(0).replace(/(\d)(?=(\d{3})+$)/g, "$1,")`. – VisioN Aug 15 '13 at 09:26
  • Hi @VisioN, can you please explain the regex and importance of "$1,". I used the regex function but missed the $ in "$1,". So the result was incorrect. Will help me if you can explain. TIA. – hanumant Oct 22 '13 at 14:27
  • 2
    @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**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)). The idea behind it is replacing matched sections with first match and comma, i.e. `$1,`. The matching is done using [lookahead approach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#special-lookahead). 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"*. – VisioN Oct 22 '13 at 15:08
  • @VisioN in the case of values for Brazilian standards (R$ 1.222.333,44) receiving (122233344). How should be done? I tried some changes in the fiddle without luck. Could you help me here? (or even add a format 3 in your example if there isn't too much to ask for). I know that the [accepted answer](http://stackoverflow.com/a/149099/662581) cover this, but yours is great too – Michel Ayres Mar 17 '14 at 12:15
  • 1
    @Michel Here is a super extended version, which supports different delimiter types: http://jsfiddle.net/hAfMM/610/. – VisioN Mar 17 '14 at 12:47
  • @VisioN : Your short solution does not work for long number. It is necessary to replace the \. by a \b (for word boudarie) like I proposed on Jan 4'12 (see infra). – Julien de Prabère Mar 25 '14 at 10:38
  • 2
    @JuliendePrabère Please give an example of a long number which doesn't work with this approach. – VisioN Mar 25 '14 at 10:53
  • @Gyrocode.com Why `$&` approach didn't work for you? – VisioN Jun 16 '15 at 08:15
  • 1
    Extra super extended version: http://jsfiddle.net/hAfMM/2269/ Integrates currency symbol – Pier-Luc Gendreau Jun 16 '15 at 20:24
  • 1
    Why this is not chosen as the best answer? Its has covered all possible options – Clain Dsilva Sep 12 '15 at 11:54
  • ok awesome code, unfortunately i can't understand many things but it was very useful tks – Andres Felipe Dec 11 '15 at 19:07
  • @1111161171159459134 This is just a short and fast alternative to `Math.floor(n)`. If you want to make it JSHint compliant, replace this bit accordingly. – VisioN Jun 18 '16 at 20:18
  • Awesome code. Can it be possible to do reverse like un-format (12.345.678,90 to 12345678.9) similarly any currency format to normal number @VisioN – Mohammed Farooq Sep 20 '16 at 07:44
  • @MohammedFarooq Sure, as easy as this: http://jsfiddle.net/hAfMM/3934/. – VisioN Sep 21 '16 at 09:03
  • @VisioN- Thanks, But i dont need to pass (comma & dot ) as parameter. I need to return a number if i pass (12.345.678,90 to 12345678.9) or (12,345,678.90 to 12345678.9). EIther euro or standard format to normal number – Mohammed Farooq Sep 21 '16 at 09:18
  • @MohammedFarooq To make this working the script should know what style your number is formatted with. It can't automatically detect if dot or comma is used as a separator for sections or a decimal part. Otherwise you have to use strict number format, so the parser may guess which character separates what part. – VisioN Sep 21 '16 at 10:47
  • How can I do to format "12514652" number? I can't call `12514652.format()` like ruby... so? – Matrix Sep 21 '16 at 22:45
  • 1
    Thanks for your answer. I have a question though.How can I eliminate e+ from the number? for example 1000000000000000000000 now is formatting like: $ 1e+21 but I would like it to be like: $ 1,000,000,000,000,000,000,000.00 – Besat Oct 20 '16 at 13:49
  • @Besat That's a tricky one but we can use a nice workaround with a custom `Number.prototype.toFixed` method, that can implicitly transform numbers in scientific notation to their full length string representation. Please see the solution here: http://jsfiddle.net/hAfMM/4027/. – VisioN Oct 20 '16 at 14:39
  • how to make arr[i].price example, formatted to this? this code work great! @VisioN – Faisal Nov 04 '16 at 04:24
  • @aross Unfortunately Intl API is still [not available in many browsers which are widely used](http://caniuse.com/#feat=internationalization) and this solution will make sense when compatibility requirements feature IE9, IE10, Safari 9, etc. – VisioN Jan 04 '17 at 11:10
  • @aross Often including 2-3 lines of code is faster and easier than embedding 50+Kb library to get the same result. It depends on the thing you are actually doing. I still use this code in my projects when I simply need to format a number in a straightforward format. – VisioN Jan 04 '17 at 11:18
  • 1
    @aross My experience tells the opposite: this code is enough in 90% of all the cases. I don't know what Indial digit grouping is but I'm sure this solution can be easily customised for it. Get me right, I don't say that this answer is the best one nowadays in 2017 but I'm quite confident that developers will still find it useful. – VisioN Jan 04 '17 at 12:06
  • 1
    VisioN, you are correct -- I'm selecting the first of your short solutions -- which, by the way, is a brilliant regex! Thank you for sharing it, I've gained a neuron. – Gerard ONeill Apr 26 '17 at 23:25
  • My TS version that works for many cases: `export const formatNumberToUSFormat = (numberToFormat: number | string) => { const stringNumber = numberToFormat.toString() return stringNumber.match(/\./g) ? stringNumber.replace(/\d(?=(\d{3})+\.)/g, '$&,') : stringNumber.replace(/\d(?=(\d{3})+$)/g, '$&,') }` – Avernikoz Oct 12 '18 at 16:30
  • This is an awesome solution! but I tried it for a number starting with 0 e.g `(012345).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,')` It returns "5,349.00" instead of "12,345.00" – olaoluwa_98 May 12 '20 at 12:57
  • @olaoluwa_98 Numbers that start with zero are considered to be octal literals, so `012345` is `5349` in decimal notation. You are not allowed to use octal literals in strict mode. – VisioN May 12 '20 at 13:35
  • My 2 cents: for non-imperial(ists) guys`(7642818.78).toFixed(2).replace(".",",").replace(/\d(?=(\d{3})+\,)/g, '$&.')` – Paulo Bueno Sep 30 '20 at 14:56
  • 1
    These inbuilt format functions are inconsistent (require locale data...) so this regex is a lifesaver. – wilmol Jan 19 '21 at 23:38
351

Take a look at the JavaScript Number object and see if it can help you.

  • toLocaleString() will format a number using location specific thousands separator.
  • toFixed() will round the number to a specific number of decimal places.

To use these at the same time the value must have its type changed back to a number because they both output a string.

Example:

Number((someNumber).toFixed(1)).toLocaleString()

EDIT

One can just use toLocaleString directly and its not necessary to recast to a number:

someNumber.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});

Multiple numbers

If you need to frequently format numbers similarly you can create a specific object for reuse. Like for German (Switzerland):

const money = new Intl.NumberFormat('de-CH',
  { style:'currency', currency: 'CHF' });
const percent = new Intl.NumberFormat('de-CH',
  { style:'percent', maximumFractionDigits: 1, signDisplay: "always"});

which than can be used as:

money.format(1234.50); // output CHF 1'234.50
percent.format(0.083);  // output +8.3%

Pretty nifty.

theking2
  • 2,174
  • 1
  • 27
  • 36
17 of 26
  • 27,121
  • 13
  • 66
  • 85
  • 4
    Thanks! Based on this idea I was able to make one that is short and simple enough! (and localized) Excellent. – Daniel Magliola Sep 29 '08 at 15:25
  • 7
    Actually You can. i.e. for dollars: '$'+(value + 0.001).toLocaleString().slice(0,-1) – Zaptree Nov 18 '13 at 03:33
  • 6
    Looks like it'd be great, but there is little browser support at the moment – acorncom Dec 06 '13 at 00:38
  • Safari definitely implements toLocale functions differently. The locale date formats also produce different output than every other major browser. – Neil Monroe Jun 26 '14 at 16:18
  • 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 S Aug 31 '15 at 03:43
  • 2
    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](https://stackoverflow.com/a/16233919/1000608). This answer seems to be intended for the old version. – aross Sep 14 '17 at 10:09
  • 6
    Not sure why this is so highly voted, but this doesn't do what OP is asking for. For example, `10000` would turn into `"10,000"` and not `"10,000.00"` which is the desired behavior for currency formatting. – Burak Jun 07 '18 at 14:20
  • Regarding @Burak comment. I don't think this is the case. For me the code "var currency = "$"+Number(someNumber.toFixed(2)).toLocaleString()" turns var someNumber = 2345667.7899; into $2,345,667.79 which is what I need. –  Jun 10 '18 at 01:48
  • 1
    @Alexander but what if someNumber is "234567" or "234567.8"? Then you have zero or one decimals, instead of two, which isn't what OP wants and generally seems undesired for currency formatting too. – Burak Jun 18 '18 at 13:59
  • Yes, you are correct. The one I now use is the prototype Number.prototype.formatMoney which is identified below. –  Jun 20 '18 at 10:43
  • the best answer by far – oldboy Aug 12 '19 at 09:06
  • The Number() is mandatory if the var is a string or any other type. This helped me a lot! thanks for sharing it. – vhugo Nov 08 '19 at 18:22
  • I agree with @Burak, why this is best answer so far.. anyone tried? it is not giving expected output – Cegone Jun 16 '20 at 14:03
171

Below is the Patrick Desjardins (alias Daok) code with a bit of comments added and some minor changes:

/*
decimal_sep: character used as decimal separator, it defaults to '.' when omitted
thousands_sep: char used as thousands separator, it defaults to ',' when omitted
*/
Number.prototype.toMoney = function(decimals, decimal_sep, thousands_sep)
{
   var n = this,
   c = isNaN(decimals) ? 2 : Math.abs(decimals), // If decimal is zero we must take it. It means the user does not want to show any decimal
   d = decimal_sep || '.', // If no decimal separator is passed, we use the dot as default decimal separator (we MUST use a decimal separator)

   /*
   According to [https://stackoverflow.com/questions/411352/how-best-to-determine-if-an-argument-is-not-sent-to-the-javascript-function]
   the fastest way to check for not defined parameter is to use typeof value === 'undefined'
   rather than doing value === undefined.
   */
   t = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep, // If you don't want to use a thousands separator you can pass empty string as thousands_sep value

   sign = (n < 0) ? '-' : '',

   // Extracting the absolute value of the integer part of the number and converting to string
   i = parseInt(n = Math.abs(n).toFixed(c)) + '',

   j = ((j = i.length) > 3) ? j % 3 : 0;
   return sign + (j ? i.substr(0, j) + t : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : '');
}

And here some tests:

// Some tests (do not forget parenthesis when using negative numbers and number with no decimals)
alert(123456789.67392.toMoney() + '\n' + 123456789.67392.toMoney(3) + '\n' + 123456789.67392.toMoney(0) + '\n' + (123456).toMoney() + '\n' + (123456).toMoney(0) + '\n' + 89.67392.toMoney() + '\n' + (89).toMoney());

// Some tests (do not forget parenthesis when using negative numbers and number with no decimals)
alert((-123456789.67392).toMoney() + '\n' + (-123456789.67392).toMoney(-3));

The minor changes are:

  1. moved a bit the Math.abs(decimals) to be done only when is not NaN.

  2. decimal_sep can not be empty string any more (a some sort of decimal separator is a must)

  3. we use typeof thousands_sep === 'undefined' as suggested in How best to determine if an argument is not sent to the JavaScript function

  4. (+n || 0) is not needed because this is a Number object

JSFiddle

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Marco Demaio
  • 33,578
  • 33
  • 128
  • 159
  • 9
    You may want to use '10' as the radix in parseInt. Otherwise, any number that starts with '0' will use octal numbering. – sohtimsso1970 Nov 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 Demaio Feb 09 '12 at 12:20
  • try, for example: parseInt("016") ... returns 14, as parseInt assumes it's octal encoded, when the string begins with a zero. – Tracker1 Mar 20 '12 at 00:02
  • 4
    @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 Demaio Mar 20 '12 at 14:57
  • This function are incorrect: > (2030).toMoney(0, '.', ' '); < "2 03 0" – Anton P Robul Mar 18 '16 at 19:26
  • @AntonPRobul it's not true you can test it with JS FIddle link added in the answer, `(2030).toMoney(0, '.', ' ');` produces this: `"2 030"` which is the expected result since you are telling the function to use a single whitespace as thousands separator. – Marco Demaio Jan 30 '21 at 22:58
  • I had to add the line `let j = 0;` before using j. Issues with the code in some developers browsers... But in other cases still working. Weird. – JotaPardo Apr 26 '21 at 15:11
145

If amount is a number, say -123, then

amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' });

will produce the string "-$123.00".

Here's a complete working example.

Community
  • 1
  • 1
Daniel Barbalace
  • 1,197
  • 1
  • 17
  • 10
  • 9
    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 }); – Nico Nov 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 Barbalace Mar 26 '15 at 17:36
  • 4
    Doesn't seem to work in Safari. It just returns the number as a String without any formatting. – Lance Anderson May 08 '15 at 03:22
  • 1
    The [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString) for anyone who would like to see the full set of options. – Mark Carpenter Jr Jun 27 '17 at 14:20
  • 4
    If for some reason you don't want cents, you can change decimal precision with: `minimumFractionDigits: 0` – Horacio May 29 '18 at 16:50
  • 1
    @Horacio / Nico - See earlier answer: https://stackoverflow.com/a/18994850/782034 – Nick Grealy May 18 '19 at 14:39
129

accounting.js is a tiny JavaScript library for number, money and currency formatting.

Aliaksandr Sushkevich
  • 11,550
  • 7
  • 37
  • 44
GasheK
  • 450
  • 1
  • 4
  • 6
115

Here's the best JavaScript money formatter I've seen:

Number.prototype.formatMoney = function(decPlaces, thouSeparator, decSeparator) {
    var n = this,
        decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces,
        decSeparator = decSeparator == undefined ? "." : decSeparator,
        thouSeparator = thouSeparator == undefined ? "," : thouSeparator,
        sign = n < 0 ? "-" : "",
        i = parseInt(n = Math.abs(+n || 0).toFixed(decPlaces)) + "",
        j = (j = i.length) > 3 ? j % 3 : 0;
    return sign + (j ? i.substr(0, j) + thouSeparator : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thouSeparator) + (decPlaces ? decSeparator + Math.abs(n - i).toFixed(decPlaces).slice(2) : "");
};

It was reformatted and borrowed from here: How to format numbers as currency strings

You'll have to supply your own currency designator (you used $ above).

Call it like this (although note that the arguments default to 2, comma, and period, so you don't need to supply any arguments if that's your preference):

var myMoney = 3543.75873;
var formattedMoney = '$' + myMoney.formatMoney(2, ',', '.'); // "$3,543.76"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jonathan M
  • 17,145
  • 9
  • 58
  • 91
87

Here's another attempt, just for fun:

function formatDollar(num) {
    var p = num.toFixed(2).split(".");
    return "$" + p[0].split("").reverse().reduce(function(acc, num, i, orig) {
        return num + (num != "-" && i && !(i % 3) ? "," : "") + acc;
    }, "") + "." + p[1];
}

And some tests:

formatDollar(45664544.23423) // "$45,664,544.23"
formatDollar(45) // "$45.00"
formatDollar(123) // "$123.00"
formatDollar(7824) // "$7,824.00"
formatDollar(1) // "$1.00"
formatDollar(-1345) // "$-1,345.00
formatDollar(-3) // "$-3.00"
Wayne
  • 59,728
  • 15
  • 131
  • 126
  • poetry. brilliant. have you tried reduceRight() https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/ReduceRight which should eliminate the reverse() ? – Steve Dec 20 '11 at 21:50
  • 1
    @Steve - You're right, but you'd need to do something like `i = orig.length - i - 1` in the callback. Still, one less traversal of the array. – Wayne Dec 20 '11 at 22:29
  • 11
    A not about compatability: The `reduce` method was introduced in Ecmascript 1.8, and is not supported in Internet Explorer 8 and below. – Blaise May 10 '12 at 12:07
  • Like @Blaise said, this method will not work in IE 8 or below. – rsbarro Aug 01 '13 at 19:46
  • Yes, that's of course correct. As noted in the answer itself, this is just for fun. Also, it should handle negative numbers just fine. – Wayne Sep 16 '13 at 20:23
  • Negative numbers worked fine for me. What I like about this is that there isn't very much code and it doesn't depend on a regex. – Betty Mock Jan 15 '15 at 00:10
  • Why didn't you just do `(parseInt(p[0])).toLocaleString()`? – Chase Sandmann Jun 16 '15 at 20:37
  • Because that function can produce different results in different locales. That may very well be what you want, but it doesn't answer the specific formatting question directly. (Also, notice the date on the question/answers here.) – Wayne Jun 16 '15 at 21:07
  • in order to handle negative number properly prepend following code before returning `num=="-" ? acc:`
    i.e. function passed to reduce method will be
    `function(acc, num, i, orig) { return num=="-" ? acc:num + (i && !(i % 3) ? "," : "") + acc; }`
    – Akshay Vijay Jain Dec 07 '16 at 06:27
  • The edit to support negative numbers doesn't actually seem to work – Wayne May 04 '21 at 05:41
  • 1
    Not work with negative number – Md. Rejaul Karim Nov 24 '21 at 08:29
  • @Md.RejaulKarim Yeah, that was a bad edit. I've fixed it with a much more elegant solution. (You always want to output the value of `num` prepended to `acc`; the only question is whether to include a comma between the two. *That's* the check that should have been updated.) – Wayne Dec 03 '21 at 15:59
85

Works for all current browsers

Use toLocaleString to format a currency in its language-sensitive representation (using ISO 4217 currency codes).

(2500).toLocaleString("en-GB", {style: "currency", currency: "GBP", minimumFractionDigits: 2})

Example South African Rand code snippets for avenmore:

console.log((2500).toLocaleString("en-ZA", {style: "currency", currency: "ZAR", minimumFractionDigits: 2}))
// -> R 2 500,00
console.log((2500).toLocaleString("en-GB", {style: "currency", currency: "ZAR", minimumFractionDigits: 2}))
// -> ZAR 2,500.00
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nick Grealy
  • 24,216
  • 9
  • 104
  • 119
  • 1
    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. – VisioN Sep 25 '13 at 06: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 Grealy Sep 25 '13 at 22:59
  • MDN has an example of [checking for support for locales and options arguments](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString#Example:_Checking_for_support_for_locales_and_options_arguments) – Jared Beck Sep 26 '14 at 16:43
  • 1
    I like this and am happy that it works with Indian digit grouping. – MSC Jul 03 '16 at 06:35
  • 8
    This is fully supported as of 2017 and should be the only correct answer – Evgeny Apr 14 '17 at 15:33
  • This does not get the commonly used format for en-ZA/ZAR (South Africa) correct, so if you are in a outlying region you may be at the mercy of what an outsider has guessed your format should be. – avenmore Aug 19 '19 at 17:50
  • @avenmore works for latest versions of Chrome/Firefox/Safari. I hate to ask... but what browser & version are you testing on? – Nick Grealy Aug 20 '19 at 00:56
  • 1
    Latest and greatest :) FF69, Chrome76, etc. "R 2 500,00" is not what we use here, it should be "R 2,500.00", same as en-GB. – avenmore Aug 20 '19 at 07:59
  • @avenmore ... interesting... I did a bit of investigation, and TLDR; comma is the official decimal separator for South Africa. "When South Africa adopted the metric system, it adopted the comma as its decimal separator, although a number of house styles, including some English-language newspapers such as The Sunday Times, continue to use the full stop" - https://en.wikipedia.org/wiki/Decimal_separator. However, you can switch formats by using `(2500).toLocaleString("en-GB", {style: "currency", currency: "ZAR", minimumFractionDigits: 2})` – Nick Grealy Aug 20 '19 at 11:13
  • @Nick Grealy Thanks for the investigation, it is the bane of South African software people - having things break from an unexpected comma. I did try the params you suggest but it produced "ZAR 2,500.00", also not acceptable. – avenmore Aug 20 '19 at 11:56
  • 1
    `minimumFractionDigits: 2` just what I was looking for! – Tim Oct 24 '19 at 15:13
69

I think you want:

f.nettotal.value = "$" + showValue.toFixed(2);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
crush
  • 16,713
  • 9
  • 59
  • 100
39

just use the native javascript Intl

you just use the options to format its value

const number = 1233445.5678
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(number));

mozilla documentation link

jessieloo
  • 1,759
  • 17
  • 24
gadielkalleb
  • 36
  • 2
  • 7
30

Ok, based on what you said, I'm using this:

var DecimalSeparator = Number("1.2").toLocaleString().substr(1,1);

var AmountWithCommas = Amount.toLocaleString();
var arParts = String(AmountWithCommas).split(DecimalSeparator);
var intPart = arParts[0];
var decPart = (arParts.length > 1 ? arParts[1] : '');
decPart = (decPart + '00').substr(0,2);

return '£ ' + intPart + DecimalSeparator + decPart;

I'm open to improvement suggestions (I'd prefer not to include YUI just to do this :-) )

I already know I should be detecting the "." instead of just using it as the decimal separator...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Daniel Magliola
  • 30,898
  • 61
  • 164
  • 243
  • 8
    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 Goral Sep 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 Magliola Oct 02 '08 at 19:12
29

Numeral.js - a JavaScript library for easy number formatting by @adamwdraper

numeral(23456.789).format('$0,0.00'); // = "$23,456.79"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
adamwdraper
  • 193
  • 3
  • 4
28

The following is concise, easy to understand, and doesn't rely on any overly complicated regular expressions.

function moneyFormat(price, sign = '$') {
  const pieces = parseFloat(price).toFixed(2).split('')
  let ii = pieces.length - 3
  while ((ii-=3) > 0) {
    pieces.splice(ii, 0, ',')
  }
  return sign + pieces.join('')
}

console.log(
  moneyFormat(100),
  moneyFormat(1000),
  moneyFormat(10000.00),
  moneyFormat(1000000000000000000)
)

Here is a version with more options in the final output to allow formatting different currencies in different locality formats.

// higher order function that takes options then a price and will return the formatted price
const makeMoneyFormatter = ({
  sign = '$',
  delimiter = ',',
  decimal = '.',
  append = false,
  precision = 2,
  round = true,
  custom
} = {}) => value => {

  const e = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000]

  value = round
    ? (Math.round(value * e[precision]) / e[precision])
    : parseFloat(value)

  const pieces = value
    .toFixed(precision)
    .replace('.', decimal)
    .split('')

  let ii = pieces.length - (precision ? precision + 1 : 0)

  while ((ii-=3) > 0) {
    pieces.splice(ii, 0, delimiter)
  }

  if (typeof custom === 'function') {
    return custom({
      sign,
      float: value,
      value: pieces.join('')
    })
  }

  return append
    ? pieces.join('') + sign
    : sign + pieces.join('')
}

// create currency converters with the correct formatting options
const formatDollar = makeMoneyFormatter()
const formatPound = makeMoneyFormatter({
  sign: '£',
  precision: 0
})
const formatEuro = makeMoneyFormatter({
  sign: '€',
  delimiter: '.',
  decimal: ',',
  append: true
})

const customFormat = makeMoneyFormatter({
  round: false,
  custom: ({ value, float, sign }) => `SALE:$${value}USD`
})

console.log(
  formatPound(1000),
  formatDollar(10000.0066),
  formatEuro(100000.001),
  customFormat(999999.555)
)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
synthet1c
  • 6,152
  • 2
  • 24
  • 39
  • Great code snippet, thank you. However, be careful, as it will not work on IE because default parameters are not supported, and "const" and "let" not supported in – Charlie Dalsass Nov 21 '16 at 17:52
  • 1
    No worries @CharlieDalsass. I would recommend using babel to compile it down to ES5 for production code. – synthet1c Nov 23 '16 at 09:35
  • But how to do Euro currency? 1.000,00 Euro? –  Jun 06 '17 at 15:41
  • @YumYumYum I added a full example with more formatting options to allow for more flexibility. – synthet1c Jun 07 '17 at 04:53
27

I use the library Globalize (from Microsoft):

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! :)

Aliaksandr Sushkevich
  • 11,550
  • 7
  • 37
  • 44
daveoncode
  • 18,900
  • 15
  • 104
  • 159
  • 3
    Wow, why is this not upvoted more? Big standardized library for all sorts of formatting. Industry-standard formatting parameters with correct globalization. Great answer!! – pbristow Sep 10 '13 at 02:11
  • It is still considered alpha stage, so use cautiously, but great find. – Neil Monroe Jun 26 '14 at 16:23
  • 1
    No longer in alpha (or beta). This seems to be very useful while we wait for Safari to meet the new standard and for IE < 11 to die. – Guy Schalnat Aug 21 '15 at 18:26
26

javascript-number-formatter (formerly at Google Code)

  • Short, fast, flexible yet stand-alone.
  • Accept standard number formatting like #,##0.00 or with negation -000.####.
  • Accept any country format like # ##0,00, #,###.##, #'###.## or any type of non-numbering symbol.
  • Accept any numbers of digit grouping. #,##,#0.000 or #,###0.## are all valid.
  • Accept any redundant/foolproof formatting. ##,###,##.# or 0#,#00#.###0# are all OK.
  • Auto number rounding.
  • Simple interface, just supply mask & value like this: format( "0.0000", 3.141592).
  • Include a prefix & suffix with the mask

(excerpt from its README)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Goodeq
  • 91
  • 2
  • 2
26

A shorter method (for inserting space, comma or point) with a regular expression:

    Number.prototype.toCurrencyString = function(){
        return this.toFixed(2).replace(/(\d)(?=(\d{3})+\b)/g, '$1 ');
    }

    n = 12345678.9;
    alert(n.toCurrencyString());
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
25

The main part is inserting the thousand-separators, and that could be done like this:

<script type="text/javascript">
  function ins1000Sep(val) {
    val = val.split(".");
    val[0] = val[0].split("").reverse().join("");
    val[0] = val[0].replace(/(\d{3})/g, "$1,");
    val[0] = val[0].split("").reverse().join("");
    val[0] = val[0].indexOf(",") == 0 ? val[0].substring(1) : val[0];
    return val.join(".");
  }

  function rem1000Sep(val) {
    return val.replace(/,/g, "");
  }

  function formatNum(val) {
    val = Math.round(val*100)/100;
    val = ("" + val).indexOf(".") > -1 ? val + "00" : val + ".00";
    var dec = val.indexOf(".");
    return dec == val.length-3 || dec == 0 ? val : val.substring(0, dec+3);
  }
</script>

<button onclick="alert(ins1000Sep(formatNum(12313231)));">
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
roenving
  • 2,560
  • 14
  • 14
25

Please try the below code

"250000".replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');

Ans: 250,000

Enter image description here

Mo.
  • 26,306
  • 36
  • 159
  • 225
Vinod Kumar
  • 1,191
  • 14
  • 12
24

+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.

Number.prototype.formatMoney = function(decPlaces, thouSeparator, decSeparator, currencySymbol) {
    // check the args and supply defaults:
    decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces;
    decSeparator = decSeparator == undefined ? "." : decSeparator;
    thouSeparator = thouSeparator == undefined ? "," : thouSeparator;
    currencySymbol = currencySymbol == undefined ? "$" : currencySymbol;

    var n = this,
        sign = n < 0 ? "-" : "",
        i = parseInt(n = Math.abs(+n || 0).toFixed(decPlaces)) + "",
        j = (j = i.length) > 3 ? j % 3 : 0;

    return sign + currencySymbol + (j ? i.substr(0, j) + thouSeparator : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thouSeparator) + (decPlaces ? decSeparator + Math.abs(n - i).toFixed(decPlaces).slice(2) : "");
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
XML
  • 19,206
  • 9
  • 64
  • 65
  • The first var is kinda weird, as those variables are already declared in the function declaration. Other than that, thanks! – Rich Bradshaw Mar 22 '13 at 16:15
  • 2
    You're right. That's an error I brought in from Jonathan M's original, where they're all chained as a single var expression. Those should be simple assignments. Fixing. – XML Oct 18 '13 at 19:27
  • For that matter, I think this is probably prematurely optimized and should be refactored for readability. But my goal was to augment the OP's code, not fundamentally alter it. – XML Oct 18 '13 at 19:37
  • It's not too bad – the `+n || 0` is the only thing that seems a little odd (to me anyway). – Rich Bradshaw Oct 18 '13 at 19:38
  • 2
    `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. – XML Oct 18 '13 at 19:49
  • True – didn't catch that one. – Rich Bradshaw Oct 18 '13 at 20:45
23

There is a JavaScript port of the PHP function "number_format".

I find it very useful as it is easy to use and recognisable for PHP developers.

function number_format (number, decimals, dec_point, thousands_sep) {
    var n = number, prec = decimals;

    var toFixedFix = function (n,prec) {
        var k = Math.pow(10,prec);
        return (Math.round(n*k)/k).toString();
    };

    n = !isFinite(+n) ? 0 : +n;
    prec = !isFinite(+prec) ? 0 : Math.abs(prec);
    var sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep;
    var dec = (typeof dec_point === 'undefined') ? '.' : dec_point;

    var s = (prec > 0) ? toFixedFix(n, prec) : toFixedFix(Math.round(n), prec);
    // Fix for Internet Explorer parseFloat(0.55).toFixed(0) = 0;

    var abs = toFixedFix(Math.abs(n), prec);
    var _, i;

    if (abs >= 1000) {
        _ = abs.split(/\D/);
        i = _[0].length % 3 || 3;

        _[0] = s.slice(0,i + (n < 0)) +
               _[0].slice(i).replace(/(\d{3})/g, sep+'$1');
        s = _.join(dec);
    } else {
        s = s.replace('.', dec);
    }

    var decPos = s.indexOf(dec);
    if (prec >= 1 && decPos !== -1 && (s.length-decPos-1) < prec) {
        s += new Array(prec-(s.length-decPos-1)).join(0)+'0';
    }
    else if (prec >= 1 && decPos === -1) {
        s += dec+new Array(prec).join(0)+'0';
    }
    return s;
}

(Comment block from the original, included below for examples & credit where due)

// Formats a number with grouped thousands
//
// version: 906.1806
// discuss at: http://phpjs.org/functions/number_format
// +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// +     bugfix by: Michael White (http://getsprink.com)
// +     bugfix by: Benjamin Lupton
// +     bugfix by: Allan Jensen (http://www.winternet.no)
// +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// +     bugfix by: Howard Yeend
// +    revised by: Luke Smith (http://lucassmith.name)
// +     bugfix by: Diogo Resende
// +     bugfix by: Rival
// +     input by: Kheang Hok Chin (http://www.distantia.ca/)
// +     improved by: davook
// +     improved by: Brett Zamir (http://brett-zamir.me)
// +     input by: Jay Klehr
// +     improved by: Brett Zamir (http://brett-zamir.me)
// +     input by: Amir Habibi (http://www.residence-mixte.com/)
// +     bugfix by: Brett Zamir (http://brett-zamir.me)
// *     example 1: number_format(1234.56);
// *     returns 1: '1,235'
// *     example 2: number_format(1234.56, 2, ',', ' ');
// *     returns 2: '1 234,56'
// *     example 3: number_format(1234.5678, 2, '.', '');
// *     returns 3: '1234.57'
// *     example 4: number_format(67, 2, ',', '.');
// *     returns 4: '67,00'
// *     example 5: number_format(1000);
// *     returns 5: '1,000'
// *     example 6: number_format(67.311, 2);
// *     returns 6: '67.31'
// *     example 7: number_format(1000.55, 1);
// *     returns 7: '1,000.6'
// *     example 8: number_format(67000, 5, ',', '.');
// *     returns 8: '67.000,00000'
// *     example 9: number_format(0.9, 0);
// *     returns 9: '1'
// *     example 10: number_format('1.20', 2);
// *     returns 10: '1.20'
// *     example 11: number_format('1.20', 4);
// *     returns 11: '1.2000'
// *     example 12: number_format('1.2000', 3);
// *     returns 12: '1.200'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DaMayan
  • 94
  • 1
  • 4
20

Patrick Desjardins' answer looks good, but I prefer my JavaScript code simple. Here's a function I just wrote to take a number in and return it in currency format (minus the dollar sign):

// Format numbers to two decimals with commas
function formatDollar(num) {
    var p = num.toFixed(2).split(".");
    var chars = p[0].split("").reverse();
    var newstr = '';
    var count = 0;
    for (x in chars) {
        count++;
        if(count%3 == 1 && count != 1) {
            newstr = chars[x] + ',' + newstr;
        } else {
            newstr = chars[x] + newstr;
        }
    }
    return newstr + "." + p[1];
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tim Saylor
  • 1,054
  • 2
  • 12
  • 19
  • I needed something to work in both the browser and in an old version of Node. This worked perfectly. Thanks – n8jadams Aug 13 '19 at 16:48
19

There is a built-in function, toFixed, in JavaScript:

var num = new Number(349);
document.write("$" + num.toFixed(2));
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gate
  • 495
  • 4
  • 11
  • This answer looks redundant. Crush's answer already mentinoed `toFixed()` – Ian Dunn Sep 25 '12 at 17:28
  • 3
    `toFixed()` is a function of the `Number` object and won't work on `var num` if it was a `String`, so the additional context helped me. – timborden Nov 20 '12 at 14:03
16
function CurrencyFormatted(amount)
{
    var i = parseFloat(amount);
    if(isNaN(i)) { i = 0.00; }
    var minus = '';
    if(i < 0) { minus = '-'; }
    i = Math.abs(i);
    i = parseInt((i + .005) * 100);
    i = i / 100;
    s = new String(i);
    if(s.indexOf('.') < 0) { s += '.00'; }
    if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
    s = minus + s;
    return s;
}

From WillMaster.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
15

I suggest the NumberFormat class from Google Visualization API.

You can do something like this:

var formatter = new google.visualization.NumberFormat({
    prefix: '$',
    pattern: '#,###,###.##'
});

formatter.formatValue(1000000); // $ 1,000,000
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
juan.obando
  • 210
  • 4
  • 11
14

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 in the US. If you're outputting euro, etc., then change the currency sign from "$".

Declare this anywhere in your HTML <head> section or wherever necessary, just before you need to use it:

  Number.prototype.toCurrencyString = function(prefix, suffix) {
    if (typeof prefix === 'undefined') { prefix = '$'; }
    if (typeof suffix === 'undefined') { suffix = ''; }
    var _localeBug = new RegExp((1).toLocaleString().replace(/^1/, '').replace(/\./, '\\.') + "$");
    return prefix + (~~this).toLocaleString().replace(_localeBug, '') + (this % 1).toFixed(2).toLocaleString().replace(/^[+-]?0+/,'') + suffix;
  }

Then you're done! Use (number).toCurrencyString() anywhere you need to output the number as currency.

var MyNumber = 123456789.125;
alert(MyNumber.toCurrencyString()); // alerts "$123,456,789.13"
MyNumber = -123.567;
alert(MyNumber.toCurrencyString()); // alerts "$-123.57"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jay Dansand
  • 789
  • 1
  • 9
  • 13
14

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:

/**
 * Converts number into currency format
 * @param {number} number    Number that should be converted.
 * @param {string} [decimalSeparator]    Decimal separator, defaults to '.'.
 * @param {string} [thousandsSeparator]    Thousands separator, defaults to ','.
 * @param {int} [nDecimalDigits]    Number of decimal digits, defaults to `2`.
 * @return {string} Formatted string (e.g. numberToCurrency(12345.67) returns '12,345.67')
 */
function numberToCurrency(number, decimalSeparator, thousandsSeparator, nDecimalDigits){
    //default values
    decimalSeparator = decimalSeparator || '.';
    thousandsSeparator = thousandsSeparator || ',';
    nDecimalDigits = nDecimalDigits == null? 2 : nDecimalDigits;

    var fixed = number.toFixed(nDecimalDigits), //limit/add decimal digits
        parts = new RegExp('^(-?\\d{1,3})((?:\\d{3})+)(\\.(\\d{'+ nDecimalDigits +'}))?$').exec( fixed ); //separate begin [$1], middle [$2] and decimal digits [$4]

    if(parts){ //number >= 1000 || number <= -1000
        return parts[1] + parts[2].replace(/\d{3}/g, thousandsSeparator + '$&') + (parts[4] ? decimalSeparator + parts[4] : '');
    }else{
        return fixed.replace('.', decimalSeparator);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Miller Medeiros
  • 1,256
  • 14
  • 12
12

Number(value)
        .toFixed(2)
        .replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
Adam Pery
  • 1,924
  • 22
  • 21
  • An explanation would be in order. For example, how can it be so simple and not covered by any of the previous more than 50 answers over 9 years (at the time)? – Peter Mortensen May 27 '21 at 11:39
11

Here are some solutions and all pass the test suite. The test suite and benchmark are included. If you want copy and paste to test, try this gist.

Method 0 (RegExp)

It is based on VisioN's answer, but it fixes if there isn't a decimal point.

if (typeof Number.prototype.format === 'undefined') {
    Number.prototype.format = function (precision) {
        if (!isFinite(this)) {
            return this.toString();
        }

        var a = this.toFixed(precision).split('.');
        a[0] = a[0].replace(/\d(?=(\d{3})+$)/g, '$&,');
        return a.join('.');
    }
}

Method 1

if (typeof Number.prototype.format === 'undefined') {
    Number.prototype.format = function (precision) {
        if (!isFinite(this)) {
            return this.toString();
        }

        var a = this.toFixed(precision).split('.'),
            // Skip the '-' sign
            head = Number(this < 0);

        // Skip the digits that's before the first thousands separator
        head += (a[0].length - head) % 3 || 3;

        a[0] = a[0].slice(0, head) + a[0].slice(head).replace(/\d{3}/g, ',$&');
        return a.join('.');
    };
}

Method 2 (Split to Array)

if (typeof Number.prototype.format === 'undefined') {
    Number.prototype.format = function (precision) {
        if (!isFinite(this)) {
            return this.toString();
        }

        var a = this.toFixed(precision).split('.');

        a[0] = a[0]
            .split('').reverse().join('')
            .replace(/\d{3}(?=\d)/g, '$&,')
            .split('').reverse().join('');

        return a.join('.');
    };
}

Method 3 (Loop)

if (typeof Number.prototype.format === 'undefined') {
    Number.prototype.format = function (precision) {
        if (!isFinite(this)) {
            return this.toString();
        }

        var a = this.toFixed(precision).split('');
        a.push('.');

        var i = a.indexOf('.') - 3;
        while (i > 0 && a[i-1] !== '-') {
            a.splice(i, 0, ',');
            i -= 3;
        }

        a.pop();
        return a.join('');
    };
}

Usage Example

console.log('======== Demo ========')
console.log(
    (1234567).format(0),
    (1234.56).format(2),
    (-1234.56).format(0)
);
var n = 0;
for (var i=1; i<20; i++) {
    n = (n * 10) + (i % 10)/100;
    console.log(n.format(2), (-n).format(2));
}

Separator

If we want custom a thousands separator or decimal separator, use replace():

123456.78.format(2).replace(',', ' ').replace('.', ' ');

Test suite

function assertEqual(a, b) {
    if (a !== b) {
        throw a + ' !== ' + b;
    }
}

function test(format_function) {
    console.log(format_function);
    assertEqual('NaN', format_function.call(NaN, 0))
    assertEqual('Infinity', format_function.call(Infinity, 0))
    assertEqual('-Infinity', format_function.call(-Infinity, 0))

    assertEqual('0', format_function.call(0, 0))
    assertEqual('0.00', format_function.call(0, 2))
    assertEqual('1', format_function.call(1, 0))
    assertEqual('-1', format_function.call(-1, 0))

    // Decimal padding
    assertEqual('1.00', format_function.call(1, 2))
    assertEqual('-1.00', format_function.call(-1, 2))

    // Decimal rounding
    assertEqual('0.12', format_function.call(0.123456, 2))
    assertEqual('0.1235', format_function.call(0.123456, 4))
    assertEqual('-0.12', format_function.call(-0.123456, 2))
    assertEqual('-0.1235', format_function.call(-0.123456, 4))

    // Thousands separator
    assertEqual('1,234', format_function.call(1234.123456, 0))
    assertEqual('12,345', format_function.call(12345.123456, 0))
    assertEqual('123,456', format_function.call(123456.123456, 0))
    assertEqual('1,234,567', format_function.call(1234567.123456, 0))
    assertEqual('12,345,678', format_function.call(12345678.123456, 0))
    assertEqual('123,456,789', format_function.call(123456789.123456, 0))
    assertEqual('-1,234', format_function.call(-1234.123456, 0))
    assertEqual('-12,345', format_function.call(-12345.123456, 0))
    assertEqual('-123,456', format_function.call(-123456.123456, 0))
    assertEqual('-1,234,567', format_function.call(-1234567.123456, 0))
    assertEqual('-12,345,678', format_function.call(-12345678.123456, 0))
    assertEqual('-123,456,789', format_function.call(-123456789.123456, 0))

    // Thousands separator and decimal
    assertEqual('1,234.12', format_function.call(1234.123456, 2))
    assertEqual('12,345.12', format_function.call(12345.123456, 2))
    assertEqual('123,456.12', format_function.call(123456.123456, 2))
    assertEqual('1,234,567.12', format_function.call(1234567.123456, 2))
    assertEqual('12,345,678.12', format_function.call(12345678.123456, 2))
    assertEqual('123,456,789.12', format_function.call(123456789.123456, 2))
    assertEqual('-1,234.12', format_function.call(-1234.123456, 2))
    assertEqual('-12,345.12', format_function.call(-12345.123456, 2))
    assertEqual('-123,456.12', format_function.call(-123456.123456, 2))
    assertEqual('-1,234,567.12', format_function.call(-1234567.123456, 2))
    assertEqual('-12,345,678.12', format_function.call(-12345678.123456, 2))
    assertEqual('-123,456,789.12', format_function.call(-123456789.123456, 2))
}

console.log('======== Testing ========');
test(Number.prototype.format);
test(Number.prototype.format1);
test(Number.prototype.format2);
test(Number.prototype.format3);

Benchmark

function benchmark(f) {
    var start = new Date().getTime();
    f();
    return new Date().getTime() - start;
}

function benchmark_format(f) {
    console.log(f);
    time = benchmark(function () {
        for (var i = 0; i < 100000; i++) {
            f.call(123456789, 0);
            f.call(123456789, 2);
        }
    });
    console.log(time.format(0) + 'ms');
}

// If not using async, the browser will stop responding while running.
// This will create a new thread to benchmark
async = [];
function next() {
    setTimeout(function () {
        f = async.shift();
        f && f();
        next();
    }, 10);
}

console.log('======== Benchmark ========');
async.push(function () { benchmark_format(Number.prototype.format); });
next();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Steely Wing
  • 16,239
  • 8
  • 58
  • 54
  • Improved from your method 2. change from var a = this.toFixed(precision).split('.'), to var multiplier = Math.pow( 10, precision + 1 ), wholeNumber = Math.floor( this * multiplier ); var a = Math.round( wholeNumber / 10 ) * 10 / multiplier; if (String(a).indexOf('.') < 1) { a += '.00'; } a = String(a).split('.'), Don't use toFixed because it is buggy. – vee Oct 18 '14 at 12:41
  • console.log(parseFloat('4.835').toFixed(2)); > 4.83 console.log(parseFloat('54.835').toFixed(2)); > 54.84 console.log(parseFloat('454.835').toFixed(2)); > 454.83 console.log(parseFloat('8454.835').toFixed(2)); > 8454.83 all of these value's decimal should be .84 not .83 – vee Oct 18 '14 at 12:42
11

I found this from: accounting.js. It's very easy and perfectly fits my need.

// Default usage:
accounting.formatMoney(12345678); // $12,345,678.00

// European formatting (custom symbol and separators), can also use options object as second parameter:
accounting.formatMoney(4999.99, "€", 2, ".", ","); // €4.999,99

// Negative values can be formatted nicely:
accounting.formatMoney(-500000, "£ ", 0); // £ -500,000

// Simple `format` string allows control of symbol position (%v = value, %s = symbol):
accounting.formatMoney(5318008, { symbol: "GBP",  format: "%v %s" }); // 5,318,008.00 GBP

// Euro currency symbol to the right
accounting.formatMoney(5318008, {symbol: "€", precision: 2, thousand: ".", decimal : ",", format: "%v%s"}); // 1.008,00€ 
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Faysal Haque
  • 410
  • 5
  • 21
  • `$('#price').val( accounting.formatMoney(OOA, { symbol: "€", precision: 2,thousand: ".", decimal :",",format: "%v%s" } ) );` - show 1.000,00 E –  Jun 07 '17 at 07:59
10

A simple option for proper comma placement by reversing the string first and basic regexp.

String.prototype.reverse = function() {
    return this.split('').reverse().join('');
};

Number.prototype.toCurrency = function( round_decimal /*boolean*/ ) {       
     // format decimal or round to nearest integer
     var n = this.toFixed( round_decimal ? 0 : 2 );

     // convert to a string, add commas every 3 digits from left to right 
     // by reversing string
     return (n + '').reverse().replace( /(\d{3})(?=\d)/g, '$1,' ).reverse();
};
miku
  • 181,842
  • 47
  • 306
  • 310
troy
  • 41
  • 1
  • 2
9

The YUI codebase uses the following formatting:

format: function(nData, oConfig) {
    oConfig = oConfig || {};

    if(!YAHOO.lang.isNumber(nData)) {
        nData *= 1;
    }

    if(YAHOO.lang.isNumber(nData)) {
        var sOutput = nData + "";
        var sDecimalSeparator = (oConfig.decimalSeparator) ? oConfig.decimalSeparator : ".";
        var nDotIndex;

        // Manage decimals
        if(YAHOO.lang.isNumber(oConfig.decimalPlaces)) {
            // Round to the correct decimal place
            var nDecimalPlaces = oConfig.decimalPlaces;
            var nDecimal = Math.pow(10, nDecimalPlaces);
            sOutput = Math.round(nData*nDecimal)/nDecimal + "";
            nDotIndex = sOutput.lastIndexOf(".");

            if(nDecimalPlaces > 0) {
                // Add the decimal separator
                if(nDotIndex < 0) {
                    sOutput += sDecimalSeparator;
                    nDotIndex = sOutput.length-1;
                }
                // Replace the "."
                else if(sDecimalSeparator !== "."){
                    sOutput = sOutput.replace(".",sDecimalSeparator);
                }
                // Add missing zeros
                while((sOutput.length - 1 - nDotIndex) < nDecimalPlaces) {
                    sOutput += "0";
                }
            }
        }

        // Add the thousands separator
        if(oConfig.thousandsSeparator) {
            var sThousandsSeparator = oConfig.thousandsSeparator;
            nDotIndex = sOutput.lastIndexOf(sDecimalSeparator);
            nDotIndex = (nDotIndex > -1) ? nDotIndex : sOutput.length;
            var sNewOutput = sOutput.substring(nDotIndex);
            var nCount = -1;
            for (var i=nDotIndex; i>0; i--) {
                nCount++;
                if ((nCount%3 === 0) && (i !== nDotIndex)) {
                    sNewOutput = sThousandsSeparator + sNewOutput;
                }
                sNewOutput = sOutput.charAt(i-1) + sNewOutput;
            }
            sOutput = sNewOutput;
        }

        // Prepend prefix
        sOutput = (oConfig.prefix) ? oConfig.prefix + sOutput : sOutput;

        // Append suffix
        sOutput = (oConfig.suffix) ? sOutput + oConfig.suffix : sOutput;

        return sOutput;
    }
    // Still not a number. Just return it unaltered
    else {
        return nData;
    }
}

It would need editing as the YUI library is configurable, like replacing oConfig.decimalSeparator with ".".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
albertein
  • 26,396
  • 5
  • 54
  • 57
  • 4
    Too long, and i'd have to include YUI – Daniel Magliola Sep 29 '08 at 15:25
  • 6
    My first reaction was "lol--too long, YUI sucks"...but upon reconsideration, it's not bad code, it's just very...complete. It checks whether the arg is actually a number ( not done by other posters, and the only part that requires YUI library ). It does rounding ( not done by all posters ). It has configurable separator, prefix, and suffix. Lastly, the code is commented, and uses no regex and no tricky one-liners. So...I am giving you a +1 to compensate for others -1...this code is not bad -- it could be adapted even if not using YUI. – Nick Perkins Nov 15 '11 at 19:13
  • At YUI they must be sick, can't believe they wrote such piece of code. – Marco Demaio Feb 09 '12 at 11:47
9

Patrick Desjardins (ex Daok)'s example worked well for me. I ported it over to CoffeeScript if anyone is interested.

Number.prototype.toMoney = (decimals = 2, decimal_separator = ".", thousands_separator = ",") ->
    n = this
    c = if isNaN(decimals) then 2 else Math.abs decimals
    sign = if n < 0 then "-" else ""
    i = parseInt(n = Math.abs(n).toFixed(c)) + ''
    j = if (j = i.length) > 3 then j % 3 else 0
    x = if j then i.substr(0, j) + thousands_separator else ''
    y = i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands_separator)
    z = if c then decimal_separator + Math.abs(n - i).toFixed(c).slice(2) else ''
    sign + x + y + z
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jc00ke
  • 2,435
  • 1
  • 21
  • 14
8

A minimalistic approach that just meets the original requirements:

function formatMoney(n) {
    return "$ " + (Math.round(n * 100) / 100).toLocaleString();
}

@Daniel Magliola: You're right. The above was a hasty, incomplete implementation. Here's the corrected implementation:

function formatMoney(n) {
    return "$ " + n.toLocaleString().split(".")[0] + "."
        + n.toFixed(2).split(".")[1];
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ates Goral
  • 137,716
  • 26
  • 137
  • 190
  • 1
    Sorry, no. That will remove extra decimal places, but it won't fix to 2 decimal positions. "25" will be "$ 25" with your code, not "$ 25.00" – Daniel Magliola Sep 29 '08 at 19:22
  • 1
    Still wrong! You're using toLocaleString, which can make the decimal separator "," instead of ".", and assuming it's "." – Daniel Magliola Oct 02 '08 at 19:13
  • 1
    This was a "minimalistic" approach to meet the original vague requirements that just gave "$ 2,500.00" as an example. – Ates Goral Oct 03 '08 at 14:49
7

tggagne is correct. My solution below is not good due to float rounding. And the toLocaleString function lacks some browser support. I'll leave the below comments for archival purposes of what not to do. :)

Date.prototype.toLocaleString()

(Old Solution) Use Patrick Desjardins' solution instead.

This is a terse solution that uses toLocaleString(), which has been supported since JavaScript version 1.0. This example designates the currency to U.S. Dollars, but could be switched to pounds by using 'GBP' instead of 'USD'.

var formatMoney = function (value) {
    // Convert the value to a floating point number in case it arrives as a string.
    var numeric = parseFloat(value);
    // Specify the local currency.
    return numeric.toLocaleString('USD', { style: 'currency', currency: "USD", minimumFractionDigits: 2, maximumFractionDigits: 2 });
}

See Internationalization and localization, Currencies for additional details.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ken Palmer
  • 2,355
  • 5
  • 37
  • 57
6

A function to handle currency output, including negatives.

Sample Output:
$5.23
-$5.23

function formatCurrency(total) {
    var neg = false;
    if(total < 0) {
        neg = true;
        total = Math.abs(total);
    }
    return (neg ? "-$" : '$') + parseFloat(total, 10).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,").toString();
}
2Yootz
  • 3,971
  • 1
  • 36
  • 31
6

Another way:

function centsToDollaString(x){
  var cents = x + ""
  while(cents.length < 4){
    cents = "0" + cents;
  }
  var dollars = cents.substr(0,cents.length - 2)
  var decimal = cents.substr(cents.length - 2, 2)
  while(dollars.length % 3 != 0){
    dollars = "0" + dollars;
  }
  str = dollars.replace(/(\d{3})(?=\d)/g, "$1" + ",").replace(/^0*(?=.)/, "");
  return "$" + str + "." + decimal;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jacob
  • 325
  • 4
  • 8
5

http://code.google.com/p/javascript-number-formatter/:

  • Short, fast, flexible yet stand-alone. Only 75 lines including MIT license info, blank lines & comments.
  • Accept standard number formatting like #,##0.00 or with negation -000.####.
  • Accept any country format like # ##0,00, #,###.##, #'###.## or any type of non-numbering symbol.
  • Accept any numbers of digit grouping. #,##,#0.000 or #,###0.## are all valid.
  • Accept any redundant/fool-proof formatting. ##,###,##.# or 0#,#00#.###0# are all OK.
  • Auto number rounding.
  • Simple interface, just supply mask & value like this: format( "0.0000", 3.141592)

UPDATE This is my home-grown pp utilities for most common tasks:

var NumUtil = {};

/**
  Petty print 'num' wth exactly 'signif' digits.
  pp(123.45, 2) == "120"
  pp(0.012343, 3) == "0.0123"
  pp(1.2, 3) == "1.20"
*/
NumUtil.pp = function(num, signif) {
    if (typeof(num) !== "number")
        throw 'NumUtil.pp: num is not a number!';
    if (isNaN(num))
        throw 'NumUtil.pp: num is NaN!';
    if (num < 1e-15 || num > 1e15)
        return num;
    var r = Math.log(num)/Math.LN10;
    var dot = Math.floor(r) - (signif-1);
    r = r - Math.floor(r) + (signif-1);
    r = Math.round(Math.exp(r * Math.LN10)).toString();
    if (dot >= 0) {
        for (; dot > 0; dot -= 1)
            r += "0";
        return r;
    } else if (-dot >= r.length) {
        var p = "0.";
        for (; -dot > r.length; dot += 1) {
            p += "0";
        }
        return p+r;
    } else {
        return r.substring(0, r.length + dot) + "." + r.substring(r.length + dot);
    }
}

/** Append leading zeros up to 2 digits. */
NumUtil.align2 = function(v) {
    if (v < 10)
        return "0"+v;
    return ""+v;
}
/** Append leading zeros up to 3 digits. */
NumUtil.align3 = function(v) {
    if (v < 10)
        return "00"+v;
    else if (v < 100)
        return "0"+v;
    return ""+v;
}

NumUtil.integer = {};

/** Round to integer and group by 3 digits. */
NumUtil.integer.pp = function(num) {
    if (typeof(num) !== "number") {
        console.log("%s", new Error().stack);
        throw 'NumUtil.integer.pp: num is not a number!';
    }
    if (isNaN(num))
        throw 'NumUtil.integer.pp: num is NaN!';
    if (num > 1e15)
        return num;
    if (num < 0)
        throw 'Negative num!';
    num = Math.round(num);
    var group = num % 1000;
    var integ = Math.floor(num / 1000);
    if (integ === 0) {
        return group;
    }
    num = NumUtil.align3(group);
    while (true) {
        group = integ % 1000;
        integ = Math.floor(integ / 1000);
        if (integ === 0)
            return group + " " + num;
        num = NumUtil.align3(group) + " " + num;
    }
    return num;
}

NumUtil.currency = {};

/** Round to coins and group by 3 digits. */
NumUtil.currency.pp = function(amount) {
    if (typeof(amount) !== "number")
        throw 'NumUtil.currency.pp: amount is not a number!';
    if (isNaN(amount))
        throw 'NumUtil.currency.pp: amount is NaN!';
    if (amount > 1e15)
        return amount;
    if (amount < 0)
        throw 'Negative amount!';
    if (amount < 1e-2)
        return 0;
    var v = Math.round(amount*100);
    var integ = Math.floor(v / 100);
    var frac = NumUtil.align2(v % 100);
    var group = integ % 1000;
    integ = Math.floor(integ / 1000);
    if (integ === 0) {
        return group + "." + frac;
    }
    amount = NumUtil.align3(group);
    while (true) {
        group = integ % 1000;
        integ = Math.floor(integ / 1000);
        if (integ === 0)
            return group + " " + amount + "." + frac;
        amount = NumUtil.align3(group) + " " + amount;
    }
    return amount;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
5

Intl.NumberFormat

var number = 3500;
alert(new Intl.NumberFormat().format(number));
// → "3,500" if in US English locale

Or PHP's number_format in JavaScript.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
iBet7o
  • 758
  • 8
  • 9
5

We can also use numeraljs

Numbers can be formatted to look like currency, percentages, times, or even plain old numbers with decimal places, thousands, and abbreviations. And you can always create a custom format.

var string = numeral(1000).format('0,0');
// '1,000'
Murtaza Hussain
  • 3,851
  • 24
  • 30
4

This answer meets the following criteria:

  • Does not depend on an external dependency.
  • Does support localization.
  • Does have tests/proofs.
  • Does use simple and best coding practices (no complicated regex's and uses standard coding patterns).

This code is built on concepts from other answers. Its execution speed should be among the better posted here if that's a concern.

var decimalCharacter = Number("1.1").toLocaleString().substr(1,1);
var defaultCurrencyMarker = "$";
function formatCurrency(number, currencyMarker) {
    if (typeof number != "number")
        number = parseFloat(number, 10);

    // if NaN is passed in or comes from the parseFloat, set it to 0.
    if (isNaN(number))
        number = 0;

    var sign = number < 0 ? "-" : "";
    number = Math.abs(number);    // so our signage goes before the $ symbol.

    var integral = Math.floor(number);
    var formattedIntegral = integral.toLocaleString();

    // IE returns "##.00" while others return "##"
    formattedIntegral = formattedIntegral.split(decimalCharacter)[0];

    var decimal = Math.round((number - integral) * 100);
    return sign + (currencyMarker || defaultCurrencyMarker) +
        formattedIntegral  +
        decimalCharacter +
        decimal.toString() + (decimal < 10 ? "0" : "");
}

These tests only work on a US locale machine. This decision was made for simplicity and because this could cause of crappy input (bad auto-localization) allowing for crappy output issues.

var tests = [
    // [ input, expected result ]
    [123123, "$123,123.00"],    // no decimal
    [123123.123, "$123,123.12"],    // decimal rounded down
    [123123.126, "$123,123.13"],    // decimal rounded up
    [123123.4, "$123,123.40"],    // single decimal
    ["123123", "$123,123.00"],    // repeat subset of the above using string input.
    ["123123.123", "$123,123.12"],
    ["123123.126", "$123,123.13"],
    [-123, "-$123.00"]    // negatives
];

for (var testIndex=0; testIndex < tests.length; testIndex++) {
    var test = tests[testIndex];
    var formatted = formatCurrency(test[0]);
    if (formatted == test[1]) {
        console.log("Test passed, \"" + test[0] + "\" resulted in \"" + formatted + "\"");
    } else {
        console.error("Test failed. Expected \"" + test[1] + "\", got \"" + formatted + "\"");
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Joseph Lennox
  • 3,202
  • 1
  • 27
  • 25
4

Here is the short and best one to convert numbers into a currency format:

function toCurrency(amount){
    return amount.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
}

// usage: toCurrency(3939920.3030);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Anunay
  • 497
  • 3
  • 13
4

The code from Jonathan M looked too complicated for me, so I rewrote it and got about 30% on Firefox v30 and 60% on Chrome v35 speed boost (http://jsperf.com/number-formating2):

Number.prototype.formatNumber = function(decPlaces, thouSeparator, decSeparator) {
    decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces;
    decSeparator = decSeparator == undefined ? "." : decSeparator;
    thouSeparator = thouSeparator == undefined ? "," : thouSeparator;

    var n = this.toFixed(decPlaces);
    if (decPlaces) {
        var i = n.substr(0, n.length - (decPlaces + 1));
        var j = decSeparator + n.substr(-decPlaces);
    } else {
        i = n;
        j = '';
    }

    function reverse(str) {
        var sr = '';
        for (var l = str.length - 1; l >= 0; l--) {
            sr += str.charAt(l);
        }
        return sr;
    }

    if (parseInt(i)) {
        i = reverse(reverse(i).replace(/(\d{3})(?=\d)/g, "$1" + thouSeparator));
    }
    return i + j;
};

Usage:

var sum = 123456789.5698;
var formatted = '$' + sum.formatNumber(2, ',', '.'); // "$123,456,789.57"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tom
  • 53
  • 4
4

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat Example: Using locales

This example shows some of the variations in localized number formats. In order to get the format of the language used in the user interface of your application, make sure to specify that language (and possibly some fallback languages) using the locales argument:

var number = 123456.789;

// German uses comma as decimal separator and period for thousands console.log(new Intl.NumberFormat('de-DE').format(number)); // → 123.456,789

// Arabic in most Arabic speaking countries uses real Arabic digits console.log(new Intl.NumberFormat('ar-EG').format(number)); // → ١٢٣٤٥٦٫٧٨٩

// India uses thousands/lakh/crore separators console.log(new Intl.NumberFormat('en-IN').format(number));

Mohamed.Abdo
  • 2,054
  • 1
  • 19
  • 12
4

toLocaleString is good, but it doesn't work in all browsers. I usually use currencyFormatter.js (https://osrec.github.io/currencyFormatter.js/). It's pretty lightweight and contains all the currency and locale definitions right out of the box. It's also good at formatting unusually formatted currencies, such as the INR (which groups numbers in lakhs, crores, etc.). Also, there aren't any dependencies!

OSREC.CurrencyFormatter.format(2534234, { currency: 'INR' }); // Returns ₹ 25,34,234.00

OSREC.CurrencyFormatter.format(2534234, { currency: 'EUR' }); // Returns 2.534.234,00 €

OSREC.CurrencyFormatter.format(2534234, { currency: 'EUR', locale: 'fr' }); // Returns 2 534 234,00 €

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
3

Here is a mootools 1.2 implementation from the code provided by XMLilley...

Number.implement('format', function(decPlaces, thouSeparator, decSeparator){
decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces;
decSeparator = decSeparator === undefined ? '.' : decSeparator;
thouSeparator = thouSeparator === undefined ? ',' : thouSeparator;

var num = this,
    sign = num < 0 ? '-' : '',
    i = parseInt(num = Math.abs(+num || 0).toFixed(decPlaces)) + '',
    j = (j = i.length) > 3 ? j % 3 : 0;

return sign + (j ? i.substr(0, j) + thouSeparator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thouSeparator) + (decPlaces ? decSeparator + Math.abs(num - i).toFixed(decPlaces).slice(2) : '');
});
Kirk Bentley
  • 243
  • 1
  • 7
3

I based this heavily on the answer from VisioN:

function format (val) {
  val = (+val).toLocaleString();
  val = (+val).toFixed(2);
  val += "";
  return val.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1" + format.thousands);
}

(function (isUS) {
  format.decimal =   isUS ? "." : ",";
  format.thousands = isUS ? "," : ".";
}(("" + (+(0.00).toLocaleString()).toFixed(2)).indexOf(".") > 0));

I tested with inputs:

[   ""
  , "1"
  , "12"
  , "123"
  , "1234"
  , "12345"
  , "123456"
  , "1234567"
  , "12345678"
  , "123456789"
  , "1234567890"
  , ".12"
  , "1.12"
  , "12.12"
  , "123.12"
  , "1234.12"
  , "12345.12"
  , "123456.12"
  , "1234567.12"
  , "12345678.12"
  , "123456789.12"
  , "1234567890.12"
  , "1234567890.123"
  , "1234567890.125"
].forEach(function (item) {
  console.log(format(item));
});

And got these results:

0.00
1.00
12.00
123.00
1,234.00
12,345.00
123,456.00
1,234,567.00
12,345,678.00
123,456,789.00
1,234,567,890.00
0.12
1.12
12.12
123.12
1,234.12
12,345.12
123,456.12
1,234,567.12
12,345,678.12
123,456,789.12
1,234,567,890.12
1,234,567,890.12
1,234,567,890.13

Just for fun.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kalisjoshua
  • 2,306
  • 2
  • 26
  • 37
3

I like the shortest answer by VisionN except when I need to modify it for a number without a decimal point ($123 instead of $123.00). It does not work, so instead of quick copy/paste I need to decipher the arcane syntax of the JavaScript regular expression.

Here is the original solution

n.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');

I'll make it a bit longer:

var re = /\d(?=(\d{3})+\.)/g;
var subst = '$&,';
n.toFixed(2).replace(re, subst);

The re part here (search part in string replace) means

  1. Find all digits (\d)
  2. Followed by (?= ...) (lookahead)
  3. One or more groups (...)+
  4. Of exactly three digits (\d{3})
  5. Ending with a dot (\.)
  6. Do it for all occurrences (g)

The subst part here means:

  1. Every time there is a match, replace it with itself ($&), followed by a comma.

As we use string.replace, all other text in the string remains the same and only found digits (those that are followed by 3, 6, 9, etc. other digits) get an additional comma.

So in a number, 1234567.89, digits 1 and 4 meet the condition (1234567.89) and are replaced with "1," and "4," resulting in 1,234,567.89.

If we don't need the decimal point in dollar amount at all (i.e., $123 instead of $123.00), we may change the regular expression like this:

var re2 = /\d(?=(\d{3})+$)/g;

It relies on the end of line ($) instead of a dot (\.) and the final expression will be (notice also toFixed(0)):

n.toFixed(0).replace(/\d(?=(\d{3})+$)/g, '$&,');

This expression will give

1234567.89 -> 1,234,567

Also instead of end of line ($) in the regular expression above, you may opt for a word boundary as well (\b).

My apology in advance if I misinterpreted any part of the regular expression handling.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mp31415
  • 6,531
  • 1
  • 44
  • 34
  • After decimal you want only two (2) digits for example, suppose your currency format is this 22.2737, at that time you can use following solution for getting result in this format 22.27, function currencyFormat(num){ return parseFloat(num).toFixed(2); } var moneyWithDecimal = currencyFormat(22.2737); alert(moneyWithDecimal ); – Amzad Khan May 03 '20 at 12:44
  • By choosing the regex answer while your requirements were more complicated you put yourself in a tough spot. You could just have used `maximumFractionDigits`, as described [here](https://stackoverflow.com/a/16233919/1000608). – aross Sep 21 '21 at 10:53
3

Many of the answers had helpful ideas, but none of them could fit my needs. So I used all the ideas and build this example:

function Format_Numb(fmt){
    var decimals = isNaN(decimals) ? 2 : Math.abs(decimals);
    if(typeof decSgn === "undefined") decSgn = ".";
    if(typeof kommaSgn === "undefined") kommaSgn= ",";

    var s3digits = /(\d{1,3}(?=(\d{3})+(?=[.]|$))|(?:[.]\d*))/g;
    var dflt_nk = "00000000".substring(0, decimals);

    //--------------------------------
    // handler for pattern: "%m"
    var _f_money = function(v_in){
                       var v = v_in.toFixed(decimals);
                       var add_nk = ",00";
                       var arr = v.split(".");
                       return arr[0].toString().replace(s3digits, function ($0) {
                           return ($0.charAt(0) == ".")
                                   ? ((add_nk = ""), (kommaSgn + $0.substring(1)))
                                   : ($0 + decSgn);
                           })
                           + ((decimals > 0)
                                 ? (kommaSgn
                                       + (
                                           (arr.length > 1)
                                           ? arr[1]
                                           : dflt_nk
                                       )
                                   )
                                 : ""
                           );
                   }

    // handler for pattern: "%<len>[.<prec>]f"
    var _f_flt = function(v_in, l, prec){
        var v = (typeof prec !== "undefined") ? v_in.toFixed(prec) : v_in;
        return ((typeof l !== "undefined") && ((l=l-v.length) > 0))
                ? (Array(l+1).join(" ") + v)
                : v;
    }

    // handler for pattern: "%<len>x"
    var _f_hex = function(v_in, l, flUpper){
        var v = Math.round(v_in).toString(16);
        if(flUpper) v = v.toUpperCase();
        return ((typeof l !== "undefined") && ((l=l-v.length) > 0))
                ? (Array(l+1).join("0") + v)
                : v;
    }

    //...can be extended..., just add the function, for example:    var _f_octal = function( v_in,...){
    //--------------------------------

    if(typeof(fmt) !== "undefined"){
        //...can be extended..., just add the char, for example "O":    MFX -> MFXO
        var rpatt = /(?:%([^%"MFX]*)([MFX]))|(?:"([^"]*)")|("|%%)/gi;
        var _qu = "\"";
        var _mask_qu = "\\\"";
        var str = fmt.toString().replace(rpatt, function($0, $1, $2, $3, $4){
                      var f;
                      if(typeof $1 !== "undefined"){
                          switch($2.toUpperCase()){
                              case "M": f = "_f_money(v)";    break;

                              case "F": var n_dig0, n_dig1;
                                        var re_flt =/^(?:(\d))*(?:[.](\d))*$/;
                                        $1.replace(re_flt, function($0, $1, $2){
                                            n_dig0 = $1;
                                            n_dig1 = $2;
                                        });
                                        f = "_f_flt(v, " + n_dig0 + "," + n_dig1 + ")";    break;

                              case "X": var n_dig = "undefined";
                                        var re_flt = /^(\d*)$/;
                                        $1.replace(re_flt, function($0){
                                            if($0 != "") n_dig = $0;
                                        });
                                        f = "_f_hex(v, " + n_dig + "," + ($2=="X") + ")";    break;
                              //...can be extended..., for example:    case "O":
                          }
                          return "\"+"+f+"+\"";
                      } else if(typeof $3 !== "undefined"){
                          return _mask_qu + $3 + _mask_qu;
                      } else {
                          return ($4 == _qu) ? _mask_qu : $4.charAt(0);
                      }
                  });

        var cmd =     "return function(v){"
                +     "if(typeof v === \"undefined\")return \"\";"  // null returned as empty string
                +     "if(!v.toFixed) return v.toString();"         // not numb returned as string
                +     "return \"" + str + "\";"
                + "}";

        //...can be extended..., just add the function name in the 2 places:
        return new Function("_f_money,_f_flt,_f_hex", cmd)(_f_money,_f_flt,_f_hex);
    }
}

First, I needed a C-style format-string-definition that should be flexible, but very easy to use and I defined it in following way; patterns:

%[<len>][.<prec>]f   float, example "%f", "%8.2d", "%.3f"
%m                   money
%[<len>]x            hexadecimal lower case, example "%x", "%8x"
%[<len>]X            hexadecimal upper case, example "%X", "%8X"

Because there isn't any need to format others than to euro for me, I implemented only "%m".

But it's easy to extend this... Like in C, the format string is a string containing the patterns. For example, for euro: "%m €" (returns strings like "8.129,33 €")

Besides the flexibility, I needed a very fast solution for processing tables. That means that, when processing thousands of cells, the processing of format string must not be done more than once. A call like "format( value, fmt)" is not acceptable for me, but this must be split into two steps:

// var formatter = Format_Numb( "%m €");
// simple example for Euro...

//   but we use a complex example:

var formatter = Format_Numb("a%%%3mxx \"zz\"%8.2f°\"  >0x%8X<");

// formatter is now a function, which can be used more than once (this is an example, that can be tested:)

var v1 = formatter(1897654.8198344);

var v2 = formatter(4.2);

... (and thousands of rows)

Also for performance, _f_money encloses the regular expression;

Third, a call like "format( value, fmt)" is not acceptable because:

Although it should be possible to format different collections of objects (for example, cells of a column) with different masks, I don't want to have something to handle format strings at the point of processing. At this point I only want to use formatting, like in

for( var cell in cells){ do_something( cell.col.formatter( cell.value)); }

What format - maybe it's defined in an .ini file, in an XML for each column or somewhere else ..., but analyzing and setting formats or dealing with internationalizaton is processed in totally another place, and there I want to assign the formatter to the collection without thinking about performance issues:

col.formatter = Format_Numb( _getFormatForColumn(...) );

Fourth, I wanted an "tolerant" solution, so passing, for example, a string instead of a number should return simply the string, but "null" should return en empty string.

(Also formatting "%4.2f" must not cut something if the value is too big.)

And last, but not least - it should be readable and easy extendable, without having any effects in performance... For example, if somebody needs "octal values", please refer to lines with "...can be extended..." - I think that should be a very easy task.

My overall focus lay on performance. Each "processing routine" (for example, _f_money) can be encapsulated optimized or exchanged with other ideas in this or other threads without change of the "prepare routines" (analyze format strings and creation of the functions), which must only be processed once and in that sense are not so performance critical like the conversion calls of thousands of numbers.

For all, who prefer methods of numbers:

Number.prototype.format_euro = (function(formatter){
    return function(){ return formatter(this); }})
(Format_Numb( "%m €"));

var v_euro = (8192.3282).format_euro(); // results: 8.192,33 €

Number.prototype.format_hex = (function(formatter){
    return function(){ return formatter(this); }})
(Format_Numb( "%4x"));

var v_hex = (4.3282).format_hex();

Although I tested some, there may be a lot of bugs in the code. So it's not a ready module, but just an idea and a starting point for non-JavaScript experts like me.

The code contains many and little modified ideas from a lot of Stack Overflow posts; sorry I can't reference all of them, but thanks to all the experts.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user2807653
  • 79
  • 2
  • 7
  • Re *"a lot of bugs in the code"*: Three places that look suspicious: `l=l-v.length` (is in a Boolean context/comparison), `return "\"+"+f+"+\"";` (missing escapes?), and `return new Function("_f_money,_f_flt,_f_hex", cmd)(_f_money,_f_flt,_f_hex);` (is that valid syntax? - not a rhetorical question). – Peter Mortensen May 27 '21 at 10:38
3
function getMoney(A){
    var a = new Number(A);
    var b = a.toFixed(2); // Get 12345678.90
    a = parseInt(a); // Get 12345678
    b = (b-a).toPrecision(2); // Get 0.90
    b = parseFloat(b).toFixed(2); // In case we get 0.0, we pad it out to 0.00
    a = a.toLocaleString(); // Put in commas - Internet Explorer also puts in .00, so we'll get 12,345,678.00
    // If Internet Explorer (our number ends in .00)
    if(a < 1 && a.lastIndexOf('.00') == (a.length - 3))
    {
        a = a.substr(0, a.length-3); // Delete the .00
    }
    return a + b.substr(1); // Remove the 0 from b, then return a + b = 12,345,678.90
}
alert(getMoney(12345678.9));

This works in Firefox and Internet Explorer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Richard Parnaby-King
  • 14,703
  • 11
  • 69
  • 129
3

I had a hard time finding a simple library to work with date and currency, so I created my own: https://github.com/dericeira/slimFormatter.js

Simple as that:

var number = slimFormatter.currency(2000.54);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Daniel Campos
  • 971
  • 4
  • 11
  • 20
3

Because every problem deserves a one-line solution:

Number.prototype.formatCurrency = function() { return this.toFixed(2).toString().split(/[-.]/).reverse().reduceRight(function (t, c, i) { return (i == 2) ? '-' + t : (i == 1) ? t + c.replace(/(\d)(?=(\d{3})+$)/g, '$1,') : t + '.' + c; }, '$'); }

This is easy enough to change for different locales. Just change the '$1,' to '$1.' and '.' to ',' to swap , and . in numbers. The currency symbol can be changed by changing the '$' at the end.

Or, if you have ES6, you can just declare the function with default values:

Number.prototype.formatCurrency = function(thou = ',', dec = '.', sym = '$') { return this.toFixed(2).toString().split(/[-.]/).reverse().reduceRight(function (t, c, i) { return (i == 2) ? '-' + t : (i == 1) ? t + c.replace(/(\d)(?=(\d{3})+$)/g, '$1' + thou) : t + dec + c; }, sym); }

console.log((4215.57).formatCurrency())
$4,215.57
console.log((4216635.57).formatCurrency('.', ','))
$4.216.635,57
console.log((4216635.57).formatCurrency('.', ',', "\u20AC"))
€4.216.635,57

Oh and it works for negative numbers too:

console.log((-6635.574).formatCurrency('.', ',', "\u20AC"))
-€6.635,57
console.log((-1066.507).formatCurrency())
-$1,066.51

And of course you don't have to have a currency symbol:

console.log((1234.586).formatCurrency(',','.',''))
1,234.59
console.log((-7890123.456).formatCurrency(',','.',''))
-7,890,123.46
console.log((1237890.456).formatCurrency('.',',',''))
1.237.890,46
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nick
  • 138,499
  • 22
  • 57
  • 95
3

This might work:

function format_currency(v, number_of_decimals, decimal_separator, currency_sign){
  return (isNaN(v)? v : currency_sign + parseInt(v||0).toLocaleString() + decimal_separator + (v*1).toFixed(number_of_decimals).slice(-number_of_decimals));
}

No loops, no regexes, no arrays, no exotic conditionals.

3

A quicker way with regexp:

Number.prototype.toMonetaryString = function() {
  var n = this.toFixed(2), m;
  //var = this.toFixed(2).replace(/\./, ','); For comma separator
  // with a space for thousands separator
  while ((m = n.replace(/(\d)(\d\d\d)\b/g, '$1 $2')) != n)
      n = m;
  return m;
}

String.prototype.fromMonetaryToNumber = function(s) {
  return this.replace(/[^\d-]+/g, '')/100;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
3

There is no equivalent of "formatNumber" in JavaScript. You can write it yourself or find a library that already does this.

Diodeus - James MacFarlane
  • 112,730
  • 33
  • 157
  • 176
2
String.prototype.toPrice = function () {
    var v;
    if (/^\d+(,\d+)$/.test(this))
        v = this.replace(/,/, '.');
    else if (/^\d+((,\d{3})*(\.\d+)?)?$/.test(this))
        v = this.replace(/,/g, "");
    else if (/^\d+((.\d{3})*(,\d+)?)?$/.test(this))
        v = this.replace(/\./g, "").replace(/,/, ".");
    var x = parseFloat(v).toFixed(2).toString().split("."),
    x1 = x[0],
    x2 = ((x.length == 2) ? "." + x[1] : ".00"),
    exp = /^([0-9]+)(\d{3})/;
    while (exp.test(x1))
        x1 = x1.replace(exp, "$1" + "," + "$2");
    return x1 + x2;
}

alert("123123".toPrice()); //123,123.00
alert("123123,316".toPrice()); //123,123.32
alert("12,312,313.33213".toPrice()); //12,312,313.33
alert("123.312.321,32132".toPrice()); //123,312,321.32
Ebubekir Dirican
  • 386
  • 4
  • 12
2

CoffeeScript for Patrick's popular answer:

Number::formatMoney = (decimalPlaces, decimalChar, thousandsChar) ->
  n = this
  c = decimalPlaces
  d = decimalChar
  t = thousandsChar
  c = (if isNaN(c = Math.abs(c)) then 2 else c)
  d = (if d is undefined then "." else d)
  t = (if t is undefined then "," else t)
  s = (if n < 0 then "-" else "")
  i = parseInt(n = Math.abs(+n or 0).toFixed(c)) + ""
  j = (if (j = i.length) > 3 then j % 3 else 0)
  s + (if j then i.substr(0, j) + t else "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (if c then d + Math.abs(n - i).toFixed(c).slice(2) else "")
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DanielEli
  • 3,393
  • 5
  • 29
  • 36
2

There are already good answers. Here's a simple attempt for fun:

function currencyFormat(no) {
  var ar = (+no).toFixed(2).split('.');
  return [
      numberFormat(ar[0] | 0),
      '.',
      ar[1]
  ].join('');
}


function numberFormat(no) {
  var str = no + '';
  var ar = [];
  var i  = str.length -1;

  while(i >= 0) {
    ar.push((str[i-2] || '') + (str[i-1] || '') + (str[i] || ''));
    i = i-3;
  }
  return ar.reverse().join(',');
}

Then run some examples:

console.log(
  currencyFormat(1),
  currencyFormat(1200),
  currencyFormat(123),
  currencyFormat(9870000),
  currencyFormat(12345),
  currencyFormat(123456.232)
)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rab
  • 4,134
  • 1
  • 29
  • 42
2

I want to contribute with this:

function toMoney(amount) {
    neg = amount.charAt(0);
    amount = amount.replace(/\D/g, '');
    amount = amount.replace(/\./g, '');
    amount = amount.replace(/\-/g, '');

    var numAmount = new Number(amount);
    amount = numAmount.toFixed(0).replace(/./g, function(c, i, a) {
        return i > 0 && c !== "," && (a.length - i) % 3 === 0 ? "." + c : c;
    });

    if(neg == '-')
        return neg + amount;
    else
        return amount;
}

This allows you to convert numbers in a text box where you are only supposed to put numbers (consider this scenario).

This is going to clean a textbox where there are only supposed to be numbers, even if you paste a string with numbers and letters or any character

<html>
<head>
    <script language=="Javascript">
        function isNumber(evt) {
            var theEvent = evt || window.event;
            var key = theEvent.keyCode || theEvent.which;
            key = String.fromCharCode(key);
            if (key.length == 0)
                return;
            var regex = /^[0-9\-\b]+$/;
            if (!regex.test(key)) {
                theEvent.returnValue = false;
                if (theEvent.preventDefault)
                    theEvent.preventDefault();
            }
        }

        function toMoney(amount) {
            neg = amount.charAt(0);
            amount = amount.replace(/\D/g, '');
            amount = amount.replace(/\./g, '');
            amount = amount.replace(/\-/g, '');

            var numAmount = new Number(amount);
            amount = numAmount.toFixed(0).replace(/./g, function(c, i, a) {
                return i > 0 && c !== "," && (a.length - i) % 3 === 0 ? "." + c : c;
            });

            if(neg == '-')
                return neg + amount;
            else
                return amount;
        }

        function clearText(inTxt, newTxt, outTxt) {
            inTxt = inTxt.trim();
            newTxt = newTxt.trim();
            if(inTxt == '' || inTxt == newTxt)
                return outTxt;

            return inTxt;
        }

        function fillText(inTxt, outTxt) {
            inTxt = inTxt.trim();
            if(inTxt != '')
                outTxt = inTxt;

            return outTxt;
        }
    </script>
</head>

<body>
    $ <input name=reca2 id=reca2 type=text value="0" onFocus="this.value = clearText(this.value, '0', '');" onblur="this.value = fillText(this.value, '0'); this.value = toMoney(this.value);" onKeyPress="isNumber(event);" style="width:80px;" />
</body>

</html>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

Here's a straightforward formatter in vanilla JavaScript:

function numberFormatter (num) {
    console.log(num)
    var wholeAndDecimal = String(num.toFixed(2)).split(".");
    console.log(wholeAndDecimal)
    var reversedWholeNumber = Array.from(wholeAndDecimal[0]).reverse();
    var formattedOutput = [];

    reversedWholeNumber.forEach( (digit, index) => {
        formattedOutput.push(digit);
        if ((index + 1) % 3 === 0 && index < reversedWholeNumber.length - 1) {
            formattedOutput.push(",");
        }
    })

    formattedOutput = formattedOutput.reverse().join('') + "." + wholeAndDecimal[1];

    return formattedOutput;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Choylton B. Higginbottom
  • 2,236
  • 3
  • 24
  • 34
2

I wanted a vanilla JavaScript solution that automatically returned the decimal portion.

function formatDollar(amount) {
    var dollar = Number(amount).toLocaleString("us", "currency");
    // Decimals
    var arrAmount = dollar.split(".");
    if (arrAmount.length==2) {
        var decimal = arrAmount[1];
        if (decimal.length==1) {
            arrAmount[1] += "0";
        }
    }
    if (arrAmount.length==1) {
        arrAmount.push("00");
    }

    return "$" + arrAmount.join(".");
}


console.log(formatDollar("1812.2");
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nicolas Giszpenc
  • 677
  • 6
  • 11
1

Here's mine...

function thousandCommas(num) {
  num = num.toString().split('.');
  var ints = num[0].split('').reverse();
  for (var out=[],len=ints.length,i=0; i < len; i++) {
    if (i > 0 && (i % 3) === 0) out.push(',');
    out.push(ints[i]);
  }
  out = out.reverse() && out.join('');
  if (num.length === 2) out += '.' + num[1];
  return out;
}
mendezcode
  • 857
  • 8
  • 7
1

I like it simple:

function formatPriceUSD(price) {
    var strPrice = price.toFixed(2).toString();
    var a = strPrice.split('');

    if (price > 1000000000)
        a.splice(a.length - 12, 0, ',');

    if (price > 1000000)
        a.splice(a.length - 9, 0, ',');

    if (price > 1000)
        a.splice(a.length - 6, 0, ',');

    return '$' + a.join("");
}
Tomas Kubes
  • 23,880
  • 18
  • 111
  • 148
  • An explanation would be in order. At a *minimum* a statement about what range of numbers it is supposed to work for. You could also include some sample input and output (e.g., you could use some sample inputs from other answers). – Peter Mortensen May 27 '21 at 09:36
1

Please find in the below code what I have developed to support internationalization.

It formats the given numeric value to language specific format. In the given example I have used ‘en’ while have tested for ‘es’, ‘fr’ and other countries where in the format varies. It not only stops the user from keying characters, but it formats the value on tab out.

I have created components for Number as well as for Decimal format. Apart from this, I have created parseNumber(value, locale) and parseDecimal(value, locale) functions which will parse the formatted data for any other business purposes. The said function will accept the formatted data and will return the non-formatted value. I have used the jQuery validator plugin in the below shared code.

HTML:

<tr>
    <td>
        <label class="control-label">
            Number Field:
        </label>
        <div class="inner-addon right-addon">
            <input type="text" id="numberField"
                   name="numberField"
                   class="form-control"
                   autocomplete="off"
                   maxlength="17"
                   data-rule-required="true"
                   data-msg-required="Cannot be blank."
                   data-msg-maxlength="Exceeding the maximum limit of 13 digits. Example: 1234567890123"
                   data-rule-numberExceedsMaxLimit="en"
                   data-msg-numberExceedsMaxLimit="Exceeding the maximum limit of 13 digits. Example: 1234567890123"
                   onkeydown="return isNumber(event, 'en')"
                   onkeyup="return updateField(this)"
                   onblur="numberFormatter(this,
                               'en',
                               'Invalid character(s) found. Please enter valid characters.')">
        </div>
    </td>
</tr>

<tr>
    <td>
        <label class="control-label">
            Decimal Field:
        </label>
        <div class="inner-addon right-addon">
            <input type="text" id="decimalField"
                   name="decimalField"
                   class="form-control"
                   autocomplete="off"
                   maxlength="20"
                   data-rule-required="true"
                   data-msg-required="Cannot be blank."
                   data-msg-maxlength="Exceeding the maximum limit of 16 digits. Example: 1234567890123.00"
                   data-rule-decimalExceedsMaxLimit="en"
                   data-msg-decimalExceedsMaxLimit="Exceeding the maximum limit of 16 digits. Example: 1234567890123.00"
                   onkeydown="return isDecimal(event, 'en')"
                   onkeyup="return updateField(this)"
                   onblur="decimalFormatter(this,
                       'en',
                       'Invalid character(s) found. Please enter valid characters.')">
        </div>
    </td>
</tr>

JavaScript:

/*
 * @author: dinesh.lomte
 */
/* Holds the maximum limit of digits to be entered in number field. */
var numericMaxLimit = 13;
/* Holds the maximum limit of digits to be entered in decimal field. */
var decimalMaxLimit = 16;

/**
 *
 * @param {type} value
 * @param {type} locale
 * @returns {Boolean}
 */
parseDecimal = function(value, locale) {

    value = value.trim();
    if (isNull(value)) {
        return 0.00;
    }
    if (isNull(locale)) {
        return value;
    }
    if (getNumberFormat(locale)[0] === '.') {
        value = value.replace(/\./g, '');
    } else {
        value = value.replace(
                    new RegExp(getNumberFormat(locale)[0], 'g'), '');
    }
    if (getNumberFormat(locale)[1] === ',') {
        value = value.replace(
                    new RegExp(getNumberFormat(locale)[1], 'g'), '.');
    }
    return value;
};

/**
 *
 * @param {type} element
 * @param {type} locale
 * @param {type} nanMessage
 * @returns {Boolean}
 */
decimalFormatter = function (element, locale, nanMessage) {

    showErrorMessage(element.id, false, null);
    if (isNull(element.id) || isNull(element.value) || isNull(locale)) {
        return true;
    }
    var value = element.value.trim();
    value = value.replace(/\s/g, '');
    value = parseDecimal(value, locale);
    var numberFormatObj = new Intl.NumberFormat(locale,
            {   minimumFractionDigits: 2,
                maximumFractionDigits: 2
            }
    );
    if (numberFormatObj.format(value) === 'NaN') {
        showErrorMessage(element.id, true, nanMessage);
        setFocus(element.id);
        return false;
    }
    element.value = numberFormatObj.format(value);
    return true;
};

/**
 *
 * @param {type} element
 * @param {type} locale
 * @param {type} nanMessage
 * @returns {Boolean}
 */
numberFormatter = function (element, locale, nanMessage) {

    showErrorMessage(element.id, false, null);
    if (isNull(element.id) || isNull(element.value) || isNull(locale)) {
        return true;
    }
    var value = element.value.trim();
    var format = getNumberFormat(locale);
    if (hasDecimal(value, format[1])) {
        showErrorMessage(element.id, true, nanMessage);
        setFocus(element.id);
        return false;
    }
    value = value.replace(/\s/g, '');
    value = parseNumber(value, locale);
    var numberFormatObj = new Intl.NumberFormat(locale,
            {   minimumFractionDigits: 0,
                maximumFractionDigits: 0
            }
    );
    if (numberFormatObj.format(value) === 'NaN') {
        showErrorMessage(element.id, true, nanMessage);
        setFocus(element.id);
        return false;
    }
    element.value =
            numberFormatObj.format(value);
    return true;
};

/**
 *
 * @param {type} id
 * @param {type} flag
 * @param {type} message
 * @returns {undefined}
 */
showErrorMessage = function(id, flag, message) {

    if (flag) {
        // only add if not added
        if ($('#'+id).parent().next('.app-error-message').length === 0) {
            var errorTag = '<div class=\'app-error-message\'>' + message + '</div>';
            $('#'+id).parent().after(errorTag);
        }
    } else {
        // remove it
        $('#'+id).parent().next(".app-error-message").remove();
    }
};

/**
 *
 * @param {type} id
 * @returns
 */
setFocus = function(id) {

    id = id.trim();
    if (isNull(id)) {
        return;
    }
    setTimeout(function() {
        document.getElementById(id).focus();
    }, 10);
};

/**
 *
 * @param {type} value
 * @param {type} locale
 * @returns {Array}
 */
parseNumber = function(value, locale) {

    value = value.trim();
    if (isNull(value)) {
        return 0;
    }
    if (isNull(locale)) {
        return value;
    }
    if (getNumberFormat(locale)[0] === '.') {
        return value.replace(/\./g, '');
    }
    return value.replace(
        new RegExp(getNumberFormat(locale)[0], 'g'), '');
};

/**
 *
 * @param {type} locale
 * @returns {Array}
 */
getNumberFormat = function(locale) {

    var format = [];
    var numberFormatObj = new Intl.NumberFormat(locale,
            {   minimumFractionDigits: 2,
                maximumFractionDigits: 2
            }
    );
    var value = numberFormatObj.format('132617.07');
    format[0] = value.charAt(3);
    format[1] = value.charAt(7);
    return format;
};

/**
 *
 * @param {type} value
 * @param {type} fractionFormat
 * @returns {Boolean}
 */
hasDecimal = function(value, fractionFormat) {

    value = value.trim();
    if (isNull(value) || isNull(fractionFormat)) {
        return false;
    }
    if (value.indexOf(fractionFormat) >= 1) {
        return true;
    }
};

/**
 *
 * @param {type} event
 * @param {type} locale
 * @returns {Boolean}
 */
isNumber = function(event, locale) {

    var keyCode = event.which ? event.which : event.keyCode;
    // Validating if user has pressed shift character
    if (keyCode === 16) {
        return false;
    }
    if (isNumberKey(keyCode)) {
        return true;
    }
    var numberFormatter = [32, 110, 188, 190];
    if (keyCode === 32
            && isNull(getNumberFormat(locale)[0]) === isNull(getFormat(keyCode))) {
        return true;
    }
    if (numberFormatter.indexOf(keyCode) >= 0
            && getNumberFormat(locale)[0] === getFormat(keyCode)) {
        return true;
    }
    return false;
};

/**
 *
 * @param {type} event
 * @param {type} locale
 * @returns {Boolean}
 */
isDecimal = function(event, locale) {

    var keyCode = event.which ? event.which : event.keyCode;
    // Validating if user has pressed shift character
    if (keyCode === 16) {
        return false;
    }
    if (isNumberKey(keyCode)) {
        return true;
    }
    var numberFormatter = [32, 110, 188, 190];
    if (keyCode === 32
            && isNull(getNumberFormat(locale)[0]) === isNull(getFormat(keyCode))) {
        return true;
    }
    if (numberFormatter.indexOf(keyCode) >= 0
            && (getNumberFormat(locale)[0] === getFormat(keyCode)
                || getNumberFormat(locale)[1] === getFormat(keyCode))) {
        return true;
    }
    return false;
};

/**
 *
 * @param {type} keyCode
 * @returns {Boolean}
 */
isNumberKey = function(keyCode) {

    if ((keyCode >= 48 && keyCode <= 57) ||
        (keyCode >= 96 && keyCode <= 105)) {
        return true;
    }
    var keys = [8, 9, 13, 35, 36, 37, 39, 45, 46, 109, 144, 173, 189];
    if (keys.indexOf(keyCode) !== -1) {
        return true;
    }
    return false;
};

/**
 *
 * @param {type} keyCode
 * @returns {JSON@call;parse.numberFormatter.value|String}
 */
getFormat = function(keyCode) {

    var jsonString = '{"numberFormatter" : [{"key":"32", "value":" ", "description":"space"}, {"key":"188", "value":",", "description":"comma"}, {"key":"190", "value":".", "description":"dot"}, {"key":"110", "value":".", "description":"dot"}]}';
    var jsonObject = JSON.parse(jsonString);
    for (var key in jsonObject.numberFormatter) {
        if (jsonObject.numberFormatter.hasOwnProperty(key)
                && keyCode === parseInt(jsonObject.numberFormatter[key].key)) {
            return jsonObject.numberFormatter[key].value;
        }
    }
    return '';
};

/**
 *
 * @type String
 */
var jsonString = '{"shiftCharacterNumberMap" : [{"char":")", "number":"0"}, {"char":"!", "number":"1"}, {"char":"@", "number":"2"}, {"char":"#", "number":"3"}, {"char":"$", "number":"4"}, {"char":"%", "number":"5"}, {"char":"^", "number":"6"}, {"char":"&", "number":"7"}, {"char":"*", "number":"8"}, {"char":"(", "number":"9"}]}';

/**
 *
 * @param {type} value
 * @returns {JSON@call;parse.shiftCharacterNumberMap.number|String}
 */
getShiftCharSpecificNumber = function(value) {

    var jsonObject = JSON.parse(jsonString);
    for (var key in jsonObject.shiftCharacterNumberMap) {
        if (jsonObject.shiftCharacterNumberMap.hasOwnProperty(key)
                && value === jsonObject.shiftCharacterNumberMap[key].char) {
            return jsonObject.shiftCharacterNumberMap[key].number;
        }
    }
    return '';
};

/**
 *
 * @param {type} value
 * @returns {Boolean}
 */
isShiftSpecificChar = function(value) {

    var jsonObject = JSON.parse(jsonString);
    for (var key in jsonObject.shiftCharacterNumberMap) {
        if (jsonObject.shiftCharacterNumberMap.hasOwnProperty(key)
                && value === jsonObject.shiftCharacterNumberMap[key].char) {
            return true;
        }
    }
    return false;
};

/**
 *
 * @param {type} element
 * @returns {undefined}
 */
updateField = function(element) {

    var value = element.value;

    for (var index = 0; index < value.length; index++) {
        if (!isShiftSpecificChar(value.charAt(index))) {
            continue;
        }
        element.value = value.replace(
                value.charAt(index),
                getShiftCharSpecificNumber(value.charAt(index)));
    }
};

/**
 *
 * @param {type} value
 * @param {type} element
 * @param {type} params
 */
jQuery.validator.addMethod('numberExceedsMaxLimit', function(value, element, params) {

    value = parseInt(parseNumber(value, params));
    if (value.toString().length > numericMaxLimit) {
        showErrorMessage(element.id, false, null);
        setFocus(element.id);
        return false;
    }
    return true;
}, 'Exceeding the maximum limit of 13 digits. Example: 1234567890123.');

/**
 *
 * @param {type} value
 * @param {type} element
 * @param {type} params
 */
jQuery.validator.addMethod('decimalExceedsMaxLimit', function(value, element, params) {

    value = parseFloat(parseDecimal(value, params)).toFixed(2);
    if (value.toString().substring(
            0, value.toString().lastIndexOf('.')).length > numericMaxLimit
            || value.toString().length > decimalMaxLimit) {
        showErrorMessage(element.id, false, null);
        setFocus(element.id);
        return false;
    }
    return true;
}, 'Exceeding the maximum limit of 16 digits. Example: 1234567890123.00.');

/**
 * @param {type} id
 * @param {type} locale
 * @returns {boolean}
 */
isNumberExceedMaxLimit = function(id, locale) {

    var value = parseInt(parseNumber(
            document.getElementById(id).value, locale));
    if (value.toString().length > numericMaxLimit) {
        setFocus(id);
        return true;
    }
    return false;
};

/**
 * @param {type} id
 * @param {type} locale
 * @returns {boolean}
 */
isDecimalExceedsMaxLimit = function(id, locale) {

    var value = parseFloat(parseDecimal(
            document.getElementById(id).value, locale)).toFixed(2);
    if (value.toString().substring(
            0, value.toString().lastIndexOf('.')).length > numericMaxLimit
            || value.toString().length > decimalMaxLimit) {
        setFocus(id);
        return true;
    }
    return false;
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dinesh Lomte
  • 569
  • 7
  • 5
1

Taking a few of the best rated answers, I combined and made an ECMAScript 2015 (ES6) function that passes ESLint.

export const formatMoney = (
  amount,
  decimalCount = 2,
  decimal = '.',
  thousands = ',',
  currencySymbol = '$',
) => {
  if (typeof Intl === 'object') {
    return new Intl.NumberFormat('en-AU', {
      style: 'currency',
      currency: 'AUD',
    }).format(amount);
  }
  // Fallback if Intl is not present.
  try {
    const negativeSign = amount < 0 ? '-' : '';
    const amountNumber = Math.abs(Number(amount) || 0).toFixed(decimalCount);
    const i = parseInt(amountNumber, 10).toString();
    const j = i.length > 3 ? i.length % 3 : 0;
    return (
      currencySymbol +
      negativeSign +
      (j ? i.substr(0, j) + thousands : '') +
      i.substr(j).replace(/(\d{3})(?=\d)/g, `$1${thousands}`) +
      (decimalCount
        ? decimal +
          Math.abs(amountNumber - i)
            .toFixed(decimalCount)
            .slice(2)
        : '')
    );
  } catch (e) {
    // eslint-disable-next-line no-console
    console.error(e);
  }
  return amount;
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pgee70
  • 3,707
  • 4
  • 35
  • 41
-1

after converting PHP number_format() to javascript this work for me

function number_format(number, decimals = 0, dec_point = ".",thousands_sep = ",") {
    number = (number + '').replace(/[^0-9+\-Ee.]/g, '');
    var n = !isFinite(+number) ? 0 : +number,
        prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
        s = '',
        toFixedFix = function(n, prec)
        {
            var k = Math.pow(10, prec);
            return '' + (Math.round(n * k) / k).toFixed(prec);
        };
    // Fix for IE parseFloat(0.55).toFixed(0) = 0;
    s = (prec ? toFixedFix(n, prec) : '' + 
        Math.round(n)).split('.');
    if (s[0].length > 3)
    {
        s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, 
            thousands_sep);
    }
    if ((s[1] || '').length < prec)
    {
        s[1] = s[1] || '';
        s[1] += new Array(prec - s[1].length + 1).join('0');
    }
    return s.join(dec_point);
}
odionk
  • 79
  • 2
  • 6