【问题标题】:What is the standard for formatting currency values in JSON?在 JSON 中格式化货币值的标准是什么?
【发布时间】:2015-07-26 18:46:18
【问题描述】:

考虑到数据类型和本地化的各种怪癖,Web 服务与应用程序之间传递货币价值的最佳方式是什么?某处有标准吗?

我的第一个想法是简单地使用数字类型。例如

"amount": 1234.56

我看到很多关于使用浮点数据类型进行货币计算时缺乏精度和舍入误差的争论——但是,我们只是传输值,而不是计算,所以这无关紧要。

EventBrite's JSON currency specifications 指定如下内容:

{
"currency": "USD", 
"value": 432, 
"display": "$4.32"
}

避免使用浮点值真是太棒了,但现在我们遇到了另一个问题:我们可以容纳的最大数字是多少?

One comment(我不知道这是否属实,但似乎合理)声称,由于 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 可能不必担心票价那么高!)

如果我们通过将值作为字符串传递来避免这个问题,那么字符串应该如何格式化?不同的国家/地区具有截然不同的格式——不同的货币符号,符号出现在金额之前还是之后,符号和金额之间是否有空格,是否使用逗号或句点分隔小数点,如果逗号用作千位分隔符、括号或减号以表示负值,可能还有更多我不知道的值。

应用是否应该知道它正在使用的语言环境/货币,传达诸如

之类的值
"amount": "1234.56"

来回,并相信应用程序正确格式化金额? (另外:应该避免使用十进制值,并以最小货币单位指定值?还是应该在不同的属性中列出主要和次要单位?)

或者服务器应该提供原始值和格式化值?

"amount": "1234.56"
"displayAmount": "$1,234.56"

或者服务器应该提供原始值和货币代码,并让应用程序格式化它? “金额”:“1234.56” “货币代码”:“美元” 我认为无论使用哪种方法都应该双向使用,向服务器传输和从服务器传输。

我一直找不到标准——你有答案吗,或者可以指出一个定义这个的资源?这似乎是一个常见问题。

【问题讨论】:

标签: json currency api-design


【解决方案1】:

我不知道这是否是最好的解决方案,但我现在正在尝试将值作为除小数点外未格式化的字符串传递,如下所示:

"amount": "1234.56"

应用程序可以轻松解析它(并将其转换为 double、BigDecimal、int 或应用程序开发人员认为最适合浮点运算的任何方法)。该应用程序将负责根据区域设置和货币格式化显示的值。

这种格式可以容纳其他货币值,无论是高度膨胀的大数字、小数点后三位数字、根本没有小数值的数字等等。

当然,这假设应用已经知道使用的区域设置和货币(来自另一个调用、应用设置或本地设备值)。如果需要在每次调用时指定这些,另一种选择是:

"amount": "1234.56",
"currency": "USD",
"locale": "en_US"

我很想将这些汇总到一个 JSON 对象中,但 JSON 提要可能有多个用于不同目的的金额,然后只需要指定一次货币设置。当然,如果列出的每个数量可能有所不同,那么最好将它们封装在一起,如下所示:

{
"amount": "1234.56",
"currency": "USD",
"locale": "en_US"
}

另一种有争议的方法是让服务器提供原始金额和格式化金额。 (如果是这样,我建议将其封装为一个对象,而不是在一个提要中包含多个定义相同概念的属性):

{
"displayAmount":"$1,234.56",
"calculationAmount":"1234.56"
}

在这里,更多的工作被卸载到服务器上。它还确保了不同平台和应用程序在数字显示方式上的一致性,同时仍为条件测试等提供易于解析的值。

但是,它确实留下了一个问题——如果应用程序需要执行计算然后将结果显示给用户怎么办?它仍然需要格式化数字以进行显示。不妨使用此答案顶部的第一个示例,并让应用控制格式。

这些是我的想法,至少。我一直无法在该领域找到任何可靠的最佳实践或研究,因此我欢迎更好的解决方案或我没有指出的潜在陷阱。

【讨论】:

    【解决方案2】:

    AFAIK,JSON 中没有“货币”标准——它是基于基本类型的标准。您可能要考虑的事情是,有些货币没有小数部分(几内亚法郎、印尼盾),有些可以分成千分之一(巴林第纳尔)——因此您不想假设两位小数。对于伊朗雷亚尔来说,200 万美元不会让你走得太远,所以我希望你需要处理双打而不是整数。如果您正在寻找通用的国际模型,那么您将需要一个货币代码,因为恶性通货膨胀的国家通常每两年更换一次货币,以将价值除以 1,000,000(或 100 米尔)。我认为,从历史上看,巴西和伊朗都曾这样做过。

    如果您需要货币代码参考(以及其他一些有用的信息),请查看此处:https://gist.github.com/Fluidbyte/2973986

    【讨论】:

    • 感谢您的意见。我已经指出了一些方法的一些问题。我正在寻找的东西确实有效。
    【解决方案3】:

    金额应以字符串表示。

    使用字符串的想法是任何使用json的客户端都应该将其解析为十进制类型,例如BigDecimal,以避免浮点不精确。

    但是,只有当系统的任何部分也避免使用浮点时,它才有意义。即使后端只是传递数据而不做任何计算,使用浮点最终会导致你看到的(在程序中)不是你得到的(在 json 上)。

    假设源是数据库,以正确的类型存储数据很重要。如果数据已经存储为浮点数,那么任何后续的转换或转换都将毫无意义,因为它在技术上会传递不精确性。

    【讨论】:

      【解决方案4】:

      打开Dev Portal - API Guidelines - Currencies,您可能会发现有趣的建议:

      "price" : {
       "amount": 40,
       "currency": "EUR"
      }
      

      生成和格式化比字符串要难一些,但我觉得这是实现它的最简洁和有意义的方式:

      1. 将金额和货币解耦
      2. 使用numberJSON类型

      这里建议使用 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"
      }
      

      【讨论】:

        【解决方案5】:

        可能没有任何官方标准。我们的产品使用以下结构:

        "amount": {
            "currency": "EUR",
            "precision": 2,
            "value": 875
        }
        

        以上示例表示金额为 8.75 欧元。

        Currency 定义为字符串(值应对应 ISO4217),precision 和 value 为整数。我猜“精确”的含义是显而易见的。这种结构解决了货币没有分数、有非标准分数等的许多问题。

        【讨论】:

          猜你喜欢
          • 2016-04-19
          • 2020-05-24
          • 1970-01-01
          • 1970-01-01
          • 2014-01-20
          • 1970-01-01
          • 2012-01-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多