← All articles

Parsing currency values with an explicit culture

Parse local monetary text once with the intended culture, then keep calculations in decimal form. A separator mismatch can change the amount itself.

t.Turgay
Parsing currency values with an explicit culture

A correctly formatted amount is not proof that the calculation received the correct value. Parsing “1.234,50” under an unspecified machine culture can fail or produce a different interpretation elsewhere. I define the input representation, numeric type and rounding policy separately when working on report or service conversions.

Parse the format the source actually promises

The sample explicitly uses tr-TR: a period groups digits and a comma separates the fraction. Parsing therefore produces 1234.50. The factor 1.25 is an illustrative multiplier, not a current exchange-rate claim. Run the .NET 10 console example to obtain 1543.13.

using System.Globalization;
var tr = CultureInfo.GetCultureInfo("tr-TR");
var amount = decimal.Parse("1.234,50", NumberStyles.Number, tr);
var rate = 1.25m;
var converted = Math.Round(amount*rate,2,MidpointRounding.AwayFromZero);
Console.WriteLine(converted.ToString("0.00", CultureInfo.InvariantCulture));

InvariantCulture is used for a predictable output string, not because every user should see English-style numeric punctuation. A Turkish screen can format the same numeric value differently. Treating presentation text as an API or persistence contract couples arithmetic to a visual preference.

Understand what decimal does and does not guarantee

Decimal can represent many base-ten fractions, such as 0.1, without the binary representation differences associated with floating-point types. It still has finite range and precision. Converting input through double before using decimal does not undo an earlier loss. The m suffix keeps the constants in the intended decimal arithmetic from the beginning.

Successful parsing is not the whole validation rule. Whether negative amounts, fractional precision or non-positive rates are allowed belongs to the business contract. TryParse is normally more useful for an untrusted form field because failure can become an actionable field error. Parse keeps this controlled, fixed-input demonstration short.

Choose both the rounding rule and its location

1234.50 multiplied by 1.25 is 1543.125. Rounding to two places with AwayFromZero produces 1543.13. ToEven is a different midpoint policy. Leaving that choice implicit makes later discrepancies harder to explain, particularly for negative midpoint values.

Console.WriteLine(Math.Round(1.005m, 2, MidpointRounding.ToEven));
Console.WriteLine(Math.Round(1.005m, 2, MidpointRounding.AwayFromZero));
Console.WriteLine(Math.Round(-1.005m, 2, MidpointRounding.AwayFromZero));

The numeric results are 1.00, 1.01 and -1.01; the number of displayed trailing digits remains a formatting concern. Selecting the right policy is a domain decision. The example demonstrates arithmetic behavior, not a universal accounting or regulatory rule.

Row totals and document totals can differ legitimately

Take two rows of 0.015 each. Rounding both to two decimal places with AwayFromZero and then adding gives 0.04. Adding the original values first and rounding 0.030 at the end gives 0.03. Both results follow their stated operation order. The application must decide which order its report contract requires rather than dismiss the difference as an unexplained rounding error.

Database precision and scale need to support that decision too. If the application retains four fractional places but a database column stores two, persistence may introduce a rounding point earlier than the code suggests. Exercise the same values through the API, database and report pipeline.

Test arithmetic separately from formatting

Include Turkish and invariant text, empty input, incorrect separators, negative amounts, midpoint values and out-of-range input. Compare decimal results before checking their display strings. That separation prevents a correct-looking string from hiding the wrong calculation and avoids mistaking a formatting discrepancy for a numeric defect.

C# decimal and floating-point types; MidpointRounding options.

✳ You have reached the end of this orbit.
Explore more articles →
turgay.A little code, a few pixels, a lot of curiosity.© 2026 · Made on Earth ✳