考虑到数据类型和本地化的各种怪癖,Web服务与应用程序之间传递货币值的最佳方式是什么?某处有标准吗?
我的第一个想法是简单地使用数字类型。例如
"amount": 1234.56
在使用浮点数据类型进行货币计算时,我已经看到很多关于缺乏精度和舍入错误的问题的论点 - 但是,我们只是传递值,而不是计算,所以这不重要。
EventBrite's JSON currency specifications指定如下内容:
{
"currency": "USD",
"value": 432,
"display": "$4.32"
}
Bravo用于避免浮点值,但现在我们遇到另一个问题:我们可以容纳的最大数字是什么?
One comment(我不知道它是否属实,但似乎是合理的)声称,由于数字实现在JSON中有所不同,因此您可以期待的最好的是32位有符号整数。 32位有符号整数可以容纳的最大值是2147483647.如果我们表示次要单位中的值,那么是21,474,836.47美元。 2100万美元似乎是一个巨大的数字,但是某些应用程序可能需要使用大于此值的值,这并不是不可思议的。对于1000个未成年单位成为主要单位的货币,或者货币价值低于美元的货币,问题会变得更严重。例如,突尼斯第纳尔分为1,000毫米。 2147483647 milim,或2147483.647 TND是$ 1,124,492.04。在某些情况下,更有可能超过100万美元的价值。另一个例子:越南盾的子单位因通货膨胀而变得无用,所以让我们只使用主要单位。 2147483647越南盾是98,526.55美元。我相信很多用例(银行存款,房地产价值等)远高于此。 (EventBrite可能不必担心票价会那么高!)
如果我们通过将值作为字符串传递来避免该问题,那么字符串应该如何格式化?不同的国家/地区具有完全不同的格式 - 不同的货币符号,无论符号出现在金额之前还是之后,无论是否在符号和金额之间有空格,如果使用逗号或句点来分隔小数,如果逗号用作千位分隔符,括号或减号来表示负值,可能还有更多我不知道的。
如果应用知道它正在使用的语言环境/货币,请传达
等值"amount": "1234.56"
来回,并相信应用程序正确格式化金额? (另外:是否应避免使用小数值,以及以最小货币单位指定的值?或者主要和次要单位是否应列在不同的属性中?)
或者服务器是否应提供原始值和格式化值?
"amount": "1234.56"
"displayAmount": "$1,234.56"
或者服务器应该提供原始值和货币代码,让应用程序格式化吗? "金额":" 1234.56" " currencyCode":" USD" 我假设使用的方法应该在两个方向上使用,与服务器之间进行传输。
我一直无法找到标准 - 您是否有答案,或者可以指向我定义此资源的资源?这似乎是一个普遍的问题。
答案 0 :(得分:5)
我不知道它是否是最佳解决方案,但我现在尝试的只是将值作为未格式化的字符串传递,除了小数点,如下所示:
"amount": "1234.56"
应用程序可以轻松解析(并将其转换为double,BigDecimal,int或app开发人员认为最适合浮点运算的任何方法)。该应用程序将负责根据区域设置和货币格式化显示的值。
此格式可以容纳其他货币值,无论是高度膨胀的大数字,小数点后三位数字,完全没有小数值的数字等等。
当然,这会假设应用已经知道所使用的区域设置和货币(来自其他呼叫,应用设置或本地设备值)。如果需要为每个呼叫指定那些,则另一个选项是:
"amount": "1234.56",
"currency": "USD",
"locale": "en_US"
我很想将这些内容转换为一个JSON对象,但是JSON提要可能有多个用于不同目的的数量,然后只需要指定一次货币设置。当然,如果列出的每个数量都有所不同,那么最好将它们封装在一起,如下所示:
{
"amount": "1234.56",
"currency": "USD",
"locale": "en_US"
}
另一个值得商榷的方法是服务器提供原始数量和格式化数量。 (如果是这样,我建议将其封装为一个对象,而不是在所有定义相同概念的Feed中具有多个属性):
{
"displayAmount":"$1,234.56",
"calculationAmount":"1234.56"
}
此处,更多工作已卸载到服务器。它还确保了不同平台和应用程序在数字显示方式上的一致性,同时仍为条件测试等提供了易于解析的价值。
然而,它确实留下了一个问题 - 如果应用程序需要执行计算然后向用户显示结果怎么办?它仍然需要格式化显示的数字。也可以使用此答案顶部的第一个示例,并让应用程序控制格式。
这至少是我的想法。我在这个领域找不到任何可靠的最佳实践或研究,所以我欢迎更好的解决方案或潜在的陷阱,我还没有指出。
答案 1 :(得分:3)
AFAIK,没有"货币" JSON中的标准 - 它是基于基本类型的标准。你可能想要考虑的事情是某些货币没有小数部分(几内亚法郎,印度尼西亚盾),有些货币可以分为千分之一(巴林第纳尔) - 因此你不想假设两位小数。对于伊朗真实的200万美元不会让你走得太远所以我希望你需要处理双打而不是整数。如果您正在寻找一般国际模型,那么您将需要货币代码,因为恶性通货膨胀的国家通常每年更换两次货币以将价值除以1,000,000(或100 mill)。我认为,历史上巴西和伊朗都做到了这一点。
如果您需要货币代码的参考(以及其他一些有用的信息),请查看此处:https://gist.github.com/Fluidbyte/2973986
答案 2 :(得分:1)
ON Dev Portal - API Guidelines - Currencies你可能会发现有趣的建议:
"price" : {
"amount": 40,
"currency": "EUR"
}
生产和生产有点困难格式不仅仅是一个字符串,但我觉得这是实现它的最简洁,最有意义的方法:
number
JSON
类型这里建议使用JSON格式: https://pattern.yaas.io/v2/schema-monetary-amount.json
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"title": "Monetary Amount",
"description":"Schema defining monetary amount in given currency.",
"properties": {
"amount": {
"type": "number",
"description": "The amount in the specified currency"
},
"currency": {
"type": "string",
"pattern": "^[a-zA-Z]{3}$",
"description": "ISO 4217 currency code, e.g.: USD, EUR, CHF"
}
},
"required": [
"amount",
"currency"
]
}
另一个questions related to currency format正确或错误地指出,这种做法更像是一个带有基本单位的字符串:
{
"price": "40.0"
}
答案 3 :(得分:1)
金额应表示为字符串。
使用字符串的想法是,使用json的任何客户端都应将其解析为十进制类型,例如BigDecimal
,以避免浮点数不精确。
但是,只有在系统的任何部分也避免浮点的情况下,它才有意义。即使后端仅传递数据而不进行任何计算,使用浮点数最终也会导致您(在程序中)看不到(在json上)得到的结果。
并且假设源是数据库,那么使用正确的类型存储数据非常重要。如果数据已经存储为浮点数,那么任何后续的转换或转换都将毫无意义,因为从技术上讲它会传递不精确的信息。