2015-05-14 1 views
14

Принимая во внимание различные причуды типов данных и локализацию, каков наилучший способ для веб-службы передавать денежные значения в приложения и из приложений? Где-то есть стандарт?Каков стандарт форматирования валютных значений в JSON?

Моя первая мысль состояла в том, чтобы просто использовать тип номера. Например

"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 долларов. $ 21 млн. Кажется огромным количеством, но не исключено, что некоторым приложениям, возможно, придется работать со значением, большим, чем это. Проблема ухудшается с валютами, где 1000 второстепенной единицы составляют основную единицу или где валюта стоит меньше, чем доллар США. Например, Тунисский Динар разделен на 1000 миллионов. 2147483647 milim, или 2147483.647 TND составляет 1 124 492,04 доллара США. В некоторых случаях даже более вероятные значения превышают 1 миллион долларов. Другой пример: подразделениями вьетнамских донов были бесполезны инфляция, поэтому давайте просто использовать основные подразделения. 2147483647 VND - $ 98 526,55. Я уверен, что многие случаи использования (банковские балансы, стоимость недвижимости и т. Д.) Значительно выше. (EventBrite, вероятно, не стоит беспокоиться о том, что цены на билеты настолько высоки, хотя!)

Если мы избежим этой проблемы, передав значение в виде строки, как должна форматироваться строка? Различные страны/регионы имеют совершенно разные форматы - разные символы валюты, независимо от того, существует ли символ до или после суммы, независимо от того, существует ли пробел между символом и суммой, если запятая или период используется для разделения десятичной, если запятые используются как разделитель тысяч, круглые скобки или знак минус для обозначения отрицательных значений и, возможно, больше того, о чем я не знаю.

Если приложение знает, что локаль/валюта это работать, общаться ценности как

"amount": "1234.56" 

назад и вперед, и доверять приложение правильно форматировать сумму? (Также: следует ли избегать десятичного значения и значение, указанное в терминах наименьшей денежной единицы? Или следует указать основные и второстепенные единицы в разных свойствах?)

Или сервер должен предоставить исходное значение и форматированное значение?

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

Нужно ли серверу предоставлять исходное значение и код валюты, а также формат приложения? «amount»: «1234.56» «currencyCode»: «USD» Я предполагаю, что любой используемый метод должен использоваться в обоих направлениях, передавая на сервер и с него.

Мне не удалось найти стандарт - есть ли у вас ответ или можете указать мне ресурс, который определяет это? Это похоже на общую проблему.

+1

Связанные вопрос: https: //stackoverflow.com/questions/45222706/what-are-the-best-practices-passing-dollar-amounts-in-json –

ответ

2

AFAIK, в JSON нет стандарта «валюты» - это стандарт, основанный на рудиментарных типах. Вещи, которые вы, возможно, захотите рассмотреть, это то, что в некоторых валютах нет десятичной части (Guinean Franc, Indonesian Rupiah), а некоторые могут быть разделены на тысячные (Bahraini Dinar) - следовательно, вы не хотите брать два десятичных знака. Для иранских Real $ 2million не собирается вас далеко, так что я ожидаю, что вам придется иметь дело с двойниками не целыми числами. Если вы ищете общую международную модель, вам понадобится код валюты, так как страны с гиперинфляцией часто меняют валюты каждый год из двух, чтобы разделить значение на 1 000 000 (или 100 млн.). Я думаю, что исторически Бразилия и Иран сделали это.

Если нужна ссылка на коды валют (и немного другой полезной информации), то посмотрите здесь: https://gist.github.com/Fluidbyte/2973986

+0

Спасибо за ваши мысли. Я уже указывал на ряд проблем с некоторыми подходами. То, что я ищу, - это то, что работает. –

4

Я не знаю, если это лучшее решение, но то, что я пытаюсь в настоящее время это просто передать значения как строки неотформатированными для десятичной точки, за исключением, например, так:

"amount": "1234.56" 

приложение может легко разобрать, что (и преобразовать его в два раза, 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" 
} 

Здесь больше работы выгружается на сервер. Это также обеспечивает согласованность между различными платформами и приложениями в том, как отображаются числа, при этом обеспечивая легко анализируемое значение для условного тестирования и тому подобное.

Однако это оставляет проблему - что делать, если приложение должно выполнять вычисления, а затем показывать результаты пользователю? По-прежнему необходимо форматировать номер для отображения. Могло бы также пойти с первым примером в верхней части этого ответа и дать приложению контроль над форматированием.

Это мои мысли, по крайней мере. Я не смог найти каких-либо твердых передовых методов или исследований в этой области, поэтому я приветствую лучшие решения или потенциальные проблемы, о которых я не упоминал.

0

ON 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" 
}