Number().toLocaleString() has different format in different browsers - javascript

I format a float to a locale string (Euro) and there are very different results in every browser. Is it possible to fix without an own function?
var sum=2282.0000;
var formated_sum = Number(sum.toFixed(2)).toLocaleString("de-DE", {style: "currency", currency: "EUR"});
Firefox result: 2.282,00 €
Chrome result: 2.282 €
IE result: 2.282,00 €
Safari result: 2282 €
Safari results are very much wrong, chrome results are not so much bad.
Any Idea how to fix that without writing an own function for formatting?
This question may already have an answer here:
Inconsistent behavior of toLocaleString() in different browser
No, my question is different because i am searching for a solution for Currency, not DATE

ECMA 262 specifies that the function is implementation dependent and takes no arguments.
Produces a String value that represents this Number value formatted
according to the conventions of the host environment’s current locale.
This function is implementation-dependent, and it is permissible, but
not encouraged, for it to return the same thing as toString.
NOTE The first parameter to this function is likely to be used in a
future version of this standard; it is recommended that
implementations do not use this parameter position for anything else.
It is also in ECMA internationalization API specification (which for Number.prototype.toLocaleString supersedes ECMA 262 but accepts 2 arguments)
This definition supersedes the definition provided in ES5, 15.7.4.3.
When the toLocaleString method is called with optional arguments
locales and options, the following steps are taken:
Let x be this Number value (as defined in ES5, 15.7.4). If locales is
not provided, then let locales be undefined. If options is not
provided, then let options be undefined. Let numberFormat be the
result of creating a new object as if by the expression new
Intl.NumberFormat(locales, options) where Intl.NumberFormat is the
standard built-in constructor defined in 11.1.3. Return the result of
calling the FormatNumber abstract operation (defined in 11.3.2) with
arguments numberFormat and x. The value of the length property of the
toLocaleString method is 0.
Besides, mdn specifies that Safari has no support for it.
As for a viable solution see this answer on SO

Related

javascript toLocaleString returns 0

I find toLocaleString function very odd.
the following line will return 0.003:
alert(0.0031.toLocaleString(2))
this line will return 0:
alert(0.00031.toLocaleString(2))
why?
This is not a valid parameters to the method toLocaleString.
You can use minimumFractionDigits param like this:
var res = 0.00031.toLocaleString(undefined, {minimumFractionDigits: 4});
console.log(res);
The toLocaleString() method returns a string with a language sensitive representation of this number.
numObj.toLocaleString([locales [, options]]) has two parameters.
Reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
var num = 0.00031;
console.log(num.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
console.log(num.toLocaleString(undefined, { maximumFractionDigits: 4}));
toLocaleString truncates and rounds the decimal number to 3 digits after the decimal.
0.0005.toLocaleString()
for example will return 0.001.
The 2 in that you pass in as a method param doesn't do anything.
2 is not a valid argument for toLocaleString method of a Number. You may only pass a locale, which is a string, and and an object of options.
Options object can be used, among other things, to specify number of fraction digits:
number.toLocaleString(undefined, { maximumFractionDigits: 4 })
And the default value for it happens to be 3:
maximumFractionDigits
The maximum number of fraction digits to use.
Possible values are from 0 to 20; the default for plain number
formatting is the larger of minimumFractionDigits and 3; the default
for currency formatting is the larger of minimumFractionDigits and the
number of minor unit digits provided by the ISO 4217 currency code
list (2 if the list doesn't provide that information); the default for
percent formatting is the larger of minimumFractionDigits and 0.
The number 2 in the argument is not making any difference. toLocaleString returns a string with a language sensitive representation of the number.
In the second case of your problem it is basically 0.000 which is equal to 0
console.log("Passing argument " + 0.0031.toLocaleString(2))
console.log("Without argument " + 0.0031.toLocaleString())
console.log("Zeros " + 0.000)
number.toLocaleString() returns language sensitive representation of the number. Here in your case you are first not passing any locale information, and you are not telling this function that what is your max fraction limit.
See this example
0.0003.toLocaleString(undefined, {minimumFractionDigits: 2})
"0.00"
0.0003.toLocaleString(undefined, {minimumFractionDigits: 3})
"0.000"
0.0003.toLocaleString(undefined, {minimumFractionDigits: 4})
"0.0003
As per spec, first two arguments to toLocaleString is locale and options
When the toLocaleString method is called with optional arguments
locales and options, the following steps are taken:
When this API receive value 2 or 3, it first try to resolve locales and if not found the check within the supported locales.
The resolved locale is used as an effective locale to format the number as per the locale as per Common Locale Data Repository.
NOTE It is recommended that implementations use the locale data
provided by the Common Locale Data Repository (available at
http://cldr.unicode.org/).
As per documentation
The locales argument must be either a string holding a BCP 47 language
tag, or an array of such language tags. If the locales argument is not
provided or is undefined, the runtime's default locale is used.
A BCP 47 language tag defines a language and minimally contains a
primary language code. In its most common form it can contain, in
order: a language code, a script code, and a country or region code,
all separated by hyphens. While the tag is not case sensitive, it is
recommended to use title case for script code, upper case for country
and region codes and lower case for everything else.
Finally, lookup is performed to find the best fit from the supported locales as per BCP47 logic as per locales registered in IANA language subtag registry as per various attributes of a language mentioned.
2 doesn't matches any of the supported locales so, default maximum fraction digits as per your system environment is used from available value (appears to be 3 in your case.)
Hence you get
0.00031.toLocaleString(2) //"0"
0.0031.toLocaleString(2) //"0.003"

Why does qUnit's assert.equal think these 2 strings are different in IE?

I am working with some qUnit tests written by another developer and am having some trouble understanding why a particular test in IE is failing.
There is a function that can convert a number of differently formatted string dates into a UTC date and it seems to function correctly. However, I am having some issues with testing it in IE.
In order to test it I am taking the return of the function (which is a number rather than a standard formatted date), creating a new date from it and then using JavaScript's toLocaleString() function to get a string I can compare to another string I created. An example of the test is below; minus the call to the function, I have replaced the call to the function with the output I get from it.
var expectedResult = "11/11/2000 12:56:00";
var actualResult = new Date(973947360000).toLocaleString():
assert.equal(expectedResult, actualResult);
This fails but I cannot see why, I am not using a deepEqual() and the types are the same anyway (I have debugged and checked). I think it may be down to IE's encoding but am not sure of 1, how to ascertain this is the case and 2, get around it/effectively test it. It is worth noting that this test passes fine in FF and Chrome, though Chrome appends "PM" to the end of the date.
Any help would be greatly appreciated.
Below is a snapshot of the output from IE.
qUnit output difference
Seeing as no one else is coming forward with an explanation I am going to simply submit my workaround as an answer.
It would appear that .toLocaleString() in Internet Explorer is encoding the space between the 2 dates differently to how a string initialised by JavaScript does. Using the following code replaces the .toLocaleString() space and allows an effective evaluation of the equality of the 2 values.
.replace(/[^ -~]/g, '');
As I only need to know that the displayed date has the same value as the input date this is acceptable.

How to check that a string ending with a number is NOT a date?

When I want to check that a string is a date in Javascript, I usually do something like:
!isNaN(Date.parse(myString));
But I just discovered that
isNaN(Date.parse("smth")) === true
isNaN(Date.parse("smth_1")) === true
isNaN(Date.parse("1 smth")) === true
isNaN(Date.parse("smth 1")) === false // !!
See this fiddle.
So my question is: why does any string ending with a number (with a space before) parse as a valid date (which it is obviously not), and how to reliably check that it's not ?
Known Chrome issue:
The spec actually says that date parsing is implementation-dependent, and implementations may make a best guess effort when faced with unknown formats. That's what V8 does. We could be stricter and reject more strings, but it's very low priority.
https://code.google.com/p/chromium/issues/detail?id=124398
https://code.google.com/p/chromium/issues/detail?id=126448
Also
Issue with Date.parse in Chrome
According to the Mozilla developer Network:
The ECMAScript specification states: If the String does not conform to the standard format the function may fall back to any implementation–specific heuristics or implementation–specific parsing algorithm. Unrecognizable strings or dates containing illegal element values in ISO formatted strings shall cause Date.parse() to return NaN.
So this is a case of implementation specific parsing.

Understanding implicit conversion in Javascript

I hunted down a bothersome JavaScript error where I was passing one argument, but when it was received, it was something completely different. I fixed it, but would like to know what was happening for future reference.
What I should have passed as an argument is '0616' (with quotes). What I actually passed was 0616 (without the quotes).
So, when it was received, some kind of implicit numeric conversion took place, and it was received as 398. I understand implicit and explicit conversion, but WHAT was happening to turn 0616 into 398. The leading zero seems to have something to do with it because other values that I passed that were non-zero in the most significant digit survived just fine. It's only those that begin with zero?
But what relation is there between 398 and '0616' ?
Any ideas?
Ahh the magical world of javascript!!
Any numeric literal that starts with a 0 is treated as an octal number.
A hacky workaround is
parseInt('0616', 10)
0616 is the old octal number format. In new spec it should be 0o616, however the old format is still supported by browsers.
See this wiki page:
prefix 0o was introduced to .... and it is intended to be supported by ECMAScript 6 (the prefix 0 has been discouraged in ECMAScript 3 and dropped in ECMAScript 5).
the reason is that the leading zero is javascript notation for base octal, e.g. 010 = 8. The notation for hexadecimal is a leading 0x, e.g. 0x10 = 16

Javascript toFixed localized?

Do you know if toFixed is a localized function?
I mean, will this:
var n = 100.67287;
alert(n.toFixed(2));
show "100.67" on english US OS/browsers
and "100,67" (with comma) on Italian OS/browsers?
(Italian or any other local system that uses comma as decimal separator).
Thanks!
Late addition: with Number.toLocaleString() now available on everything bar IE 10 & below, this works, albeit rather long-winded:
var n = 100.67287;
console.log(n.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}));
Using undefined or 'default' for the language code will use the browser default language to format the number.
See developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString for full details.
If you're free to extend the Number prototype, you could defined Number.toLocaleFixed().
No, this will always return a point. The ECMA 262-spec [15.7.4.5] states it should be a point.
You can use this:
var n = 100.67287;
alert(parseFloat(n.toFixed(2)).toLocaleString());
On my german system the result is
100,67
No sadly, there is no real solution in pure jQuery/JavaScript. You'll need Globalize. The problem is that both toFixed() and toLocaleString() take a number and return a string. So you can never use them together. :( If you call foo.toFixed(2).toLocaleString() you won't get the localization (i.e. '1.234' in en should be '1,234' in fr) because its working on the result of toFixed() which is a string, not a number. :(

Categories

Resources