1
\$\begingroup\$

I have some code that is used to convert a decimal currency to an integer with precision being a function of which currency is being converted.

This code is more of a "brute-force" method to do the conversion and just doesn't feel right to me. Is there a better way to achieve the result?

 public static int CurrencyToInt(decimal amount, string currencyCode)
 {
 var precision = 0;
 currencyCode = currencyCode?.ToUpperInvariant();
 if (new[] {
 "BHD", "IQD", "JOD", "KWD", "LYD", "OMR", "TND"
 }.Contains(currencyCode))
 {
 precision = 3;
 }
 else if (new[] {
 "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BMD",
 "BND", "BOB", "BRL", "BSD", "BTN", "BWP", "BZD", "CAD", "CDF", "CHF", "CNY", "COP", "CRC", "CUC", "CUP",
 "CZK", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GGP", "GHS", "GIP",
 "GMD", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "IMP", "INR", "IRR", "JEP", "JMD",
 "KES", "KGS", "KHR", "KPW", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LTL", "LVL", "MAD", "MDL",
 "MKD", "MMK", "MNT", "MOP", "MUR", "MVP", "MVR", "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK",
 "NPR", "NZD", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "QAR", "RON", "RSD", "RUB", "SAR", "SBD", "SCR",
 "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SPL", "SRD", "STD", "SVC", "SYP", "SZL", "THB", "TJS", "TMT",
 "TOP", "TRY", "TTD", "TVD", "TWD", "TZS", "UAH", "USD", "UYU", "UZS", "VEF", "WST", "XCD", "XDR", "YER",
 "ZAR", "ZMW", "ZWD"
 }.Contains(currencyCode))
 {
 precision = 2;
 }
 else if (new[] {
 "MGA", "MRO"
 }.Contains(currencyCode))
 {
 precision = 1;
 }
 else if (new[]{
 "BIF", "BYR", "CLP", "CVE", "DJF", "GNF", "ISK", "JPY", "KMF", "KRW", "PYG", "RWF", "UGX", "VND", "VUV",
 "XAF", "XOF", "XPF"
 }.Contains(currencyCode))
 {
 precision = 0;
 }
 else
 {
 throw new ArgumentException("Unknown currency code " + currencyCode, nameof(currencyCode));
 }
 while (precision > 0)
 {
 amount *= 10;
 precision--;
 }
 return (int)Math.Floor(amount);
 }
200_success
145k22 gold badges190 silver badges478 bronze badges
asked May 24, 2018 at 15:45
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Why not to create static Dictionary<string, int> instead? \$\endgroup\$ Commented May 24, 2018 at 16:56
  • 1
    \$\begingroup\$ Suggest reading up on CultureInfo Class and CultureInfo.NumberFormat in particular. Let the framework help you. CultureInfo includes country codes and currency symbol. \$\endgroup\$ Commented May 24, 2018 at 17:19
  • 1
    \$\begingroup\$ amount *= Math.Pow(10, precision); \$\endgroup\$ Commented May 24, 2018 at 17:27

1 Answer 1

1
\$\begingroup\$

Maybe it is intentionally(?):

I would expect CurrencyToInt(234.567m, "USD") to return 23457, but it returns 23456?


Instead of the rather unclear if-statements it is more readable with a switch:

public static int CurrencyToInt(decimal amount, string currencyCode)
{
 var precision = 0;
 currencyCode = currencyCode?.ToUpperInvariant();
 switch (currencyCode)
 {
 case "BHD": case "IQD": case "JOD": case "KWD": case "LYD": case "OMR": case "TND":
 precision = 3;
 break;
 case "AED": case "AFN": case "ALL": case "AMD": case "ANG": case "AOA": case "ARS": case "AUD": case "AWG": case "AZN": case "BAM": case "BBD": case "BDT": case "BGN": case "BMD":
 case "BND": case "BOB": case "BRL": case "BSD": case "BTN": case "BWP": case "BZD": case "CAD": case "CDF": case "CHF": case "CNY": case "COP": case "CRC": case "CUC": case "CUP":
 case "CZK": case "DKK": case "DOP": case "DZD": case "EGP": case "ERN": case "ETB": case "EUR": case "FJD": case "FKP": case "GBP": case "GEL": case "GGP": case "GHS": case "GIP":
....

As stated in the comments the whole thing can be boiled down to 3 lines of code, if you use the framework:

public static int CurrencyToIntByCulture(decimal amount, string currencyCode)
{
 CultureInfo culture = new CultureInfo(currencyCode);
 int precision = culture.NumberFormat.CurrencyDecimalDigits;
 return (int)(amount * (decimal)Math.Pow(10, precision));
 // Or?: return (int)Math.Round((amount * (decimal)Math.Pow(10, precision)));
}

But culture.NumberFormat.CurrencyDecimalDigits returns different numbers of decimals for certain cultures, so maybe you have special needs?

answered May 25, 2018 at 7:49
\$\endgroup\$
2
  • \$\begingroup\$ As to the special needs, it seems better to abstract this in a separate method anyway. Defining the precision and applying it are two different things. It doesn't matter for your example, but if it's a custom mapping, it does start to matter more. That would mean that your 3 line example would turn into a 2 line example, where int precision = getCustomPrecision(currencyCode);. \$\endgroup\$ Commented May 25, 2018 at 11:19
  • \$\begingroup\$ @Flater: You may be right, but we know to little about the context and needs. If you have to overrule some of the culture defined precisions then a separate function is appropriate for that. \$\endgroup\$ Commented May 25, 2018 at 12:53

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.