leer - mostrar datos json javascript
¿Cuál es el estándar para formatear valores de moneda en JSON? (4)
Teniendo en cuenta varias particularidades de los tipos de datos y la localización, ¿cuál es la mejor manera para que un servicio web comunique valores monetarios desde y hacia las aplicaciones? ¿Hay algún estándar en alguna parte?
Mi primer pensamiento fue simplemente usar el tipo de número. Por ejemplo
"amount": 1234.56
He visto muchos argumentos sobre problemas con la falta de precisión y errores de redondeo al usar tipos de datos de punto flotante para cálculos monetarios; sin embargo, solo estamos transmitiendo el valor, no calculando, por lo que no debería importar.
Las especificaciones de moneda JSON de EventBrite especifican algo como esto:
{
"currency": "USD",
"value": 432,
"display": "$4.32"
}
Bravo por evitar los valores de punto flotante, pero ahora nos encontramos con otro problema: ¿cuál es el número más grande que podemos mantener?
Un comentario (no sé si es cierto, pero parece razonable) afirma que, dado que las implementaciones de números varían en JSON, lo mejor que puede esperar es un entero con signo de 32 bits. El valor más grande que puede contener un entero con signo de 32 bits es 2147483647. Si representamos valores en la unidad menor, eso es $ 21,474,836.47. $ 21 millones parece una gran cantidad, pero no es inconcebible que algunas aplicaciones necesiten trabajar con un valor mayor que ese. El problema se agrava con las monedas donde 1,000 de la unidad menor forman una unidad principal, o donde la moneda vale menos que el dólar estadounidense. Por ejemplo, un dinar tunecino se divide en 1,000 milim. 2147483647 milim, o 2147483.647 TND es $ 1,124,492.04. Es incluso más probable que se puedan trabajar con valores de más de $ 1 millón en algunos casos. Otro ejemplo: las subunidades del dong vietnamita se han vuelto inútiles por la inflación, así que solo usemos las unidades principales. 2147483647 VND es $ 98,526.55. Estoy seguro de que muchos casos de uso (saldos bancarios, valores de bienes raíces, etc.) son sustancialmente más altos que eso. (EventBrite probablemente no tenga que preocuparse porque los precios de los boletos sean tan altos, sin embargo)
Si evitamos ese problema comunicando el valor como una cadena, ¿cómo debería formatearse la cadena? Diferentes países / locales tienen formatos drásticamente diferentes: diferentes símbolos de moneda, ya sea que el símbolo aparezca antes o después de la cantidad, ya sea que haya o no un espacio entre el símbolo y la cantidad, si se usa una coma o un punto para separar el decimal, si las comas se utilizan como separadores de miles, paréntesis o un signo de menos para indicar valores negativos, y posiblemente más de lo que no tengo conocimiento.
Si la aplicación sabe con qué configuración regional / moneda está trabajando, comunique valores como
"amount": "1234.56"
¿Atrás y adelante, y confía en la aplicación para formatear correctamente la cantidad? (Además: ¿se debe evitar el valor decimal y el valor especificado en términos de la unidad monetaria más pequeña? ¿O deben las unidades mayor y menor aparecer en diferentes propiedades?)
¿O debería el servidor proporcionar el valor sin formato y el valor con formato?
"amount": "1234.56"
"displayAmount": "$1,234.56"
¿O debería el servidor proporcionar el valor bruto y el código de moneda, y dejar que la aplicación lo formatee? "amount": "1234.56" "currencyCode": "USD" Supongo que el método que se use debe usarse en ambas direcciones, transmitiendo desde y hacia el servidor.
No he podido encontrar el estándar. ¿Tiene una respuesta o puede indicarme un recurso que lo defina? Parece un problema común.
AFAIK, no hay un estándar de "moneda" en JSON, es un estándar basado en tipos rudimentarios. Las cosas que tal vez quiera considerar es que algunas monedas no tienen una parte decimal (franco guineano, rupias indonesias) y algunas se pueden dividir en milésimas (dinar de Bahrein), por lo que no quiere asumir dos decimales. Para iraní, $ 2 millones reales no lo llevarán lejos, así que espero que tenga que lidiar con los dobles no con los enteros. Si está buscando un modelo internacional general, necesitará un código de moneda, ya que los países con hiperinflación a menudo cambian las monedas cada año de dos para dividir el valor por 1,000,000 (o 100 mill). Históricamente, Brasil e Irán han hecho esto, creo.
Si necesita una referencia para códigos de moneda (y un poco de otra buena información), eche un vistazo aquí: https://gist.github.com/Fluidbyte/2973986
La cantidad de dinero debe ser representada como una cadena.
La idea de usar cadena es que cualquier cliente que consuma el json debería analizarlo en un tipo decimal como BigDecimal
para evitar la imprecisión de punto flotante.
Sin embargo, solo sería significativo si alguna parte del sistema evita el punto flotante también. Incluso si el backend solo pasa datos y no realiza ningún cálculo, el uso de punto flotante eventualmente resultará en lo que se ve (en el programa) no es lo que se obtiene (en el json).
Y suponiendo que la fuente es una base de datos, es importante tener los datos almacenados con el tipo correcto. Si los datos ya están almacenados como punto flotante, entonces cualquier conversión o conversión posterior no tendría sentido, ya que técnicamente sería una imprecisión.
No sé si es la mejor solución, pero lo que estoy intentando ahora es pasar los valores como cadenas sin formato, excepto por un punto decimal, como por ejemplo:
"amount": "1234.56"
La aplicación podría analizarlo fácilmente (y convertirla en método doble, BigDecimal, int o cualquier otro que el desarrollador de la aplicación se sienta mejor para la aritmética de punto flotante). La aplicación sería responsable de formatear el valor para mostrar de acuerdo con la configuración regional y la moneda.
Este formato podría acomodar otros valores de moneda, ya sean números grandes altamente inflados, números con tres dígitos después del punto decimal, números sin valores fraccionarios, etc.
Por supuesto, esto supondría que la aplicación ya conoce la configuración regional y la moneda utilizada (de otra llamada, una configuración de la aplicación o los valores del dispositivo local). Si es necesario especificarlos por llamada, otra opción sería:
"amount": "1234.56",
"currency": "USD",
"locale": "en_US"
Estoy tentado a convertirlos en un objeto JSON, pero un feed JSON puede tener múltiples cantidades para diferentes propósitos, y luego solo tendría que especificar la configuración de moneda una vez. Por supuesto, si pudiera variar para cada cantidad enlistada, entonces sería mejor encapsularlos juntos, así:
{
"amount": "1234.56",
"currency": "USD",
"locale": "en_US"
}
Otro enfoque discutible es que el servidor proporcione la cantidad en bruto y la cantidad formateada. (Si es así, sugeriría que lo encapsule como un objeto, en lugar de tener varias propiedades en una fuente que definan el mismo concepto):
{
"displayAmount":"$1,234.56",
"calculationAmount":"1234.56"
}
Aquí, más del trabajo se descarga al servidor. También garantiza la coherencia en las diferentes plataformas y aplicaciones en la forma en que se muestran los números, al tiempo que proporciona un valor fácilmente analizable para las pruebas condicionales y similares.
Sin embargo, deja un problema: ¿qué sucede si la aplicación necesita realizar cálculos y luego mostrar los resultados al usuario? Todavía necesitará formatear el número para mostrar. También podría ir con el primer ejemplo en la parte superior de esta respuesta y dar a la aplicación el control sobre el formato.
Esos son mis pensamientos, al menos. No he podido encontrar buenas prácticas sólidas ni investigaciones en esta área, por lo que acojo con satisfacción las mejores soluciones o las posibles dificultades que no he señalado.
ON Dev Portal - Pautas API - Monedas puede encontrar sugerencias interesantes:
"price" : {
"amount": 40,
"currency": "EUR"
}
Es un poco más difícil de producir y formatear que solo una cadena, pero creo que esta es la forma más limpia y significativa de lograrlo:
- desacoplar cantidad y moneda
- usar
number
tipoJSON
Aquí se sugiere el formato 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"
]
}
Otra de las preguntas relacionadas con el formato de moneda señaló correcta o incorrectamente que la práctica es mucho más parecida a una cadena con unidades base:
{
"price": "40.0"
}