问题描述
考虑到数据类型和本地化的各种怪癖,Web 服务与应用程序之间传递货币价值的最佳方式是什么?某处有标准吗?
Bearing in mind various quirks of the data types, and localization, what is the best way for a web service to communicate monetary values to and from applications? Is there a standard somewhere?
我的第一个想法是简单地使用数字类型.例如
My first thought was to simply use the number type. For example
"amount": 1234.56
我见过很多关于在使用浮点数据类型进行货币计算时缺乏精度和舍入误差问题的争论——但是,我们只是传输值,而不是计算,所以这无关紧要.
I have seen many arguments about issues with a lack of precision and rounding errors when using floating point data types for monetary calculations--however, we are just transmitting the value, not calculating, so that shouldn't matter.
EventBrite 的 JSON 货币规范 指定如下:
{
"currency": "USD",
"value": 432,
"display": "$4.32"
}
为避免浮点值而喝彩,但现在我们遇到了另一个问题:我们可以容纳的最大数字是多少?
Bravo for avoiding floating point values, but now we run into another issue: what's the largest number we can hold?
一条评论(我不知道是否属实,但似乎合理) 声称,由于数字实现在 JSON 中有所不同,因此您可以期望的最佳值是 32 位有符号整数.一个 32 位有符号整数可以容纳的最大值是 2147483647.如果我们用次要单位表示值,那就是 $21,474,836.47.2100 万美元似乎是一个巨大的数字,但某些应用程序可能需要以更大的价值运行并非不可想象.对于以 1,000 小单位为主要单位的货币,或货币价值低于美元的货币,问题会变得更糟.例如,突尼斯第纳尔被划分为 1,000 milim.2147483647 milim 或 2147483.647 TND 为 1,124,492.04 美元.在某些情况下,更有可能使用超过 100 万美元的价值.另一个例子:越南盾的子单位因通货膨胀而变得无用,所以让我们使用主要单位.2147483647 越南盾为 98,526.55 美元.我确信许多用例(银行余额、房地产价值等)远高于此.(不过,EventBrite 可能不必担心票价那么高!)
One comment (I don’t know if it’s true, but seems reasonable) claims that, since number implementations vary in JSON, the best you can expect is a 32-bit signed integer. The largest value a 32-bit signed integer can hold is 2147483647. If we represent values in the minor unit, that’s $21,474,836.47. $21 million seems like a huge number, but it’s not inconceivable that some application may need to work with a value larger than that. The problem gets worse with currencies where 1,000 of the minor unit make a major unit, or where the currency is worth less than the US dollar. For example, a Tunisian Dinar is divided into 1,000 milim. 2147483647 milim, or 2147483.647 TND is $1,124,492.04. It's even more likely values over $1 million may be worked with in some cases. Another example: the subunits of the Vietnamese dong have been rendered useless by inflation, so let’s just use major units. 2147483647 VND is $98,526.55. I’m sure many use cases (bank balances, real estate values, etc.) are substantially higher than that. (EventBrite probably doesn’t have to worry about ticket prices being that high, though!)
如果我们通过将值作为字符串进行通信来避免该问题,那么该字符串应该如何格式化?不同的国家/地区有截然不同的格式——不同的货币符号、符号出现在金额之前还是之后、符号和金额之间是否有空格、是否使用逗号或句点分隔小数点、是否使用逗号用作千位分隔符、括号或减号来表示负值,可能还有更多我不知道的.
If we avoid that problem by communicating the value as a string, how should the string be formatted? Different countries/locales have drastically different formats—different currency symbols, whether the symbol occurs before or after the amount, whether or not there is a space between the symbol and amount, if a comma or period is used to separate the decimal, if commas are used as a thousands separator, parentheses or a minus sign to indicate negative values, and possibly more that I’m not aware of.
应用程序是否应该知道它所使用的语言环境/货币,传达类似的值
Should the app know what locale/currency it's working with, communicate values like
"amount": "1234.56"
来回,并相信应用程序正确格式化金额?(另外:是否应该避免使用十进制值,以最小货币单位指定的值?还是应该在不同的属性中列出主要和次要单位?)
back and forth, and trust the app to correctly format the amount? (Also: should the decimal value be avoided, and the value specified in terms of the smallest monetary unit? Or should the major and minor unit be listed in different properties?)
或者服务器应该提供原始值和格式化的值吗?
Or should the server provide the raw value and the formatted value?
"amount": "1234.56"
"displayAmount": "$1,234.56"
还是应该由服务器提供原始值和货币代码,然后让应用对其进行格式化?金额":1234.56"货币代码":美元"我假设无论使用哪种方法都应该双向使用,传输到服务器和从服务器传输.
Or should the server provide the raw value and the currency code, and let the app format it? "amount": "1234.56" "currencyCode": "USD"I assume whichever method is used should be used in both directions, transmitting to and from the server.
我一直找不到标准——你有答案吗,或者可以给我指点定义这个标准的资源吗?这似乎是一个常见问题.
I have been unable to find the standard--do you have an answer, or can point me to a resource that defines this? It seems like a common issue.
推荐答案
我不知道这是否是最好的解决方案,但我现在尝试的是将值作为除小数点外的未格式化字符串传递,例如所以:
I don't know if it's the best solution, but what I'm trying now is to just pass values as strings unformatted except for a decimal point, like so:
"amount": "1234.56"
应用程序可以轻松解析(并将其转换为 double、BigDecimal、int 或应用程序开发人员认为最适合浮点运算的任何方法).该应用程序将负责根据区域设置和货币格式化显示值.
The app could easily parse that (and convert it to double, BigDecimal, int, or whatever method the app developer feels best for floating-point arithmetic). The app would be responsible for formatting the value for display according to locale and currency.
这种格式可以容纳其他货币值,无论是高度膨胀的大数字、小数点后三位数字、根本没有小数值的数字等.
This format could accommodate other currency values, whether highly inflated large numbers, numbers with three digits after the decimal point, numbers with no fractional values at all, etc.
当然,这假设应用已经知道使用的区域设置和货币(来自另一个调用、应用设置或本地设备值).如果每次调用都需要指定这些,另一种选择是:
Of course, this would assume the app already knows the locale and currency used (from another call, an app setting, or local device values). If those need to be specified per call, another option would be:
"amount": "1234.56",
"currency": "USD",
"locale": "en_US"
我很想将它们合并到一个 JSON 对象中,但一个 JSON 提要可能有多个用于不同目的的金额,然后只需要指定一次货币设置.当然,如果列出的每个金额都会有所不同,那么最好将它们封装在一起,如下所示:
I'm tempted to roll these into one JSON object, but a JSON feed may have multiple amounts for different purposes, and then would only need to specify currency settings once. Of course, if it could vary for each amount listed, then it would be best to encapsulate them together, like so:
{
"amount": "1234.56",
"currency": "USD",
"locale": "en_US"
}
另一种有争议的方法是让服务器提供原始数量和格式化数量.(如果是这样,我建议将其封装为一个对象,而不是在一个提要中有多个属性都定义了相同的概念):
Another debatable approach is for the server to provide the raw amount and the formatted amount. (If so, I would suggest encapsulating it as an object, instead of having multiple properties in a feed that all define the same concept):
{
"displayAmount":"$1,234.56",
"calculationAmount":"1234.56"
}
在这里,更多的工作被卸载到服务器上.它还确保不同平台和应用程序在数字显示方式上的一致性,同时仍为条件测试等提供易于解析的值.
Here, more of the work is offloaded to the server. It also ensures consistency across different platforms and apps in how the numbers are displayed, while still providing an easily parseable value for conditional testing and the like.
然而,它确实留下了一个问题——如果应用程序需要执行计算然后将结果显示给用户怎么办?它仍然需要格式化显示的数字.不妨使用此答案顶部的第一个示例,并让应用控制格式.
However, it does leave a problem--what if the app needs to perform calculations and then show the results to the user? It will still need to format the number for display. Might as well go with the first example at the top of this answer and give the app control over the formatting.
至少这是我的想法.我一直无法在这方面找到任何可靠的最佳实践或研究,因此我欢迎更好的解决方案或我尚未指出的潜在陷阱.
Those are my thoughts, at least. I've been unable to find any solid best practices or research in this area, so I welcome better solutions or potential pitfalls I haven't pointed out.
这篇关于在 JSON 中格式化货币值的标准是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!