What is best practice for the scenario listed below?
We have an application which we would like to support multiple currencies. The software will respect the users locale and regional settings to dictate the correct number format, i.e. $10,000.00 or 10.000,00₴ etc.
We would however like to be able to format different numbers based upon a currency ID (perhaps the three letter ISO4217 code). Our idea is to store a table in the database with each currency and then request from the user to select the currency symbol which will be used. The program will then format all numbers based upon the locale/region setting but will use the currency symbol as defined in our program.
So, given the following values and currencies
10000 AUD
5989.34 USD
450 EUR
the program would output
$10,000.00
$5,989.34
€450.00
or with a regional setting that formated numbers as #####,##$ the result would be;
10000,00$
5989,34$
450,00€
Respecting locale/region number formatting but displaying different currencies, what is best practice for this?
I hope this makes sense.
Technology used is c# .NET 2.0.
I think this Q is an excellent and clear answer as to WHAT you should be doing
SO - Proper currency format when not displaying the native currency of a culture
And this Q has a good answer of HOW to do this in C#
SO - Currency formatting
It sounds like you have a handle on the best practices for formatting data. If I were you I would worry less about what is technically the standard but focus more on what it is your users are accustomed to.
If you are operating in markets where users are fairly savvy about different currencies it is a very different thing than having more monocultural users. Depending on the case, you will need to design your interface in a different way.
Moreover, if your requirement is to display any currency to any locale, the ISO4217 standard is your best bet. It is what is shown at currency exchange shops across the world, on currency exchanges, invoices, etc. Otherwise, displaying currency symbols could be rather confusing to some users and the symbol by itself does not indicate what currency the amount actually is.
I would also reference the following SO questions. Not all of them directly relate to your problem, but they have very good meta discussions about the issues involved in supporting multiple currencies.
How do I round up currency values in Java
Representing Monetary Values in Java
What to do with Java BigDecimal performance?
Rather than storing just the currency symbol, you could store the culture string for each currency code, so AUD --> en-AU
CultureInfo ci = new CultureInfo("en-AU");
currencyValue.ToString( "c", ci );
I'm not sure how much flexibility there is in formatting available.
Not sure if this helps:
Formatting Numeric Data for a Specific Culture
You could store the money value as a decimal, then append the currency symbol on the UI.
Fowler discusses the Money pattern in Patterns of Enterprise Application Architecture here: http://www.martinfowler.com/eaaCatalog/money.html
I faced a similar situation. I found a way, dont know how useful it will be for you. But it solved my problems. I set a session string for each place like Session["cur"]="0.000" or "0.00" for each login authentication. And where ever currency comes in the system I used .ToString[Session["cur"].ToString()] to the model variables. It did the trick for me . Hope it helps you too .
Related
Well... i search the web and found many solutions for the other way, but none for these.
I have a application which gets different currencys by the user. I dont know the currencys in before, it could be everything (russian rubels, usd, €, Yen...)
I need to convert the amount into a decimal, for that i need the current culture. My current solution is very bad 8and incomplete, cause i cant cover all cultures that way), it just checks the currency sign.
if (currency.Contains("zł"))
{
cult = CultureInfo.GetCultureInfo("PL-pl")
}
else if (currency.Contains("$"))
{
//blah blah blah
}
Is there a possiblility to get Culture base on the currency sign. Another maybe difficult thing is, that i dont know if the currency symbol is before or beyond the amount (varys by culture i.E: $45.00 <-> 45.00€)
Create a lookup once and use it for fast access. Notice that a particular currency symbol may be used by multiple cultures:
ILookup<string, CultureInfo> cultureByCurrency =
CultureInfo.GetCultures(CultureTypes.AllCultures)
.ToLookup(_ => _.NumberFormat.CurrencySymbol);
Then to lookup $ for example:
IEnumerable<CultureInfo> culturesThatUseDollar = cultureByCurrency["$"];
There is no exact mapping from a currency code or symbol to a culture. Consider basic examples like EUR (€), which is used as the official currency in 18 countries. There are many issues arising from this mere fact, like whether the symbol is placed before or after the value etc. You should ask the user about the specific formatting to use instead of trying to deduce it from the currency symbol.
Also, a single currency symbol is used for many currencies. Consider that $ can denote both USD, CAD, AUD and other currencies that call themselves as 'dollars'. You should use currency codes if you want an exact specification of a currency.
It is not possible.
EUR for example would map to de-DE, fr-FR, nl-NL and other countries.
There is no mapping from Currency to culture, because multiple countries share currencies
In your else if block, which culture would you assign after finding the $? en-US? fr-CA?
I would suggest a different approach that would remove any sort of ambiguity. Have the user specify their nationality before entering this chunk of code. Consider having the culture information given to you instead of attempting to guess it.
return CultureInfo.GetCultures(CultureTypes.AllCultures).Where(c => c.NumberFormat.CurrencySymbol.Equals("$"));
I want to gracefully convert phone number input from my users into a specific phone number format.
I would like convert this with a dataAnnotation, Just as
[dataType(dataType.Date)] displays a dateTime as a string
Ie:
0205938472 into +61205938472
02 0593 8472 into +61205938472
0593 8472 into +61205938472 (I will assume the area code from where
they live or if its a mobile)
02-0593-8472 into +61205938472
Etc, I also want to convert the other direction:
+61205938472 into 02 0593 8472 (Or whatever format i choose)
I want to do this to promote readability for the user but retain a strict data type in the database.
Questions
Is using a dataAnnotation in this manner considered bad practice?
How would I actually write the dataAnnotation( /However you would do it)?
(please include some code)
Edit: to clarify, i do not want someone to write the extension for me, I would just like an example of key pieces of code and implementation.
Please Note
These are Australia, New Zealand and internationally formatted
numbers being stored as internationally formatted numbers.
And International Formatted numbers being converted to Australia, New Zealand or internationally formatted depending on the user's location (which i can determine)
Depending on the UI you're using, you might be able to do this using a:
ASP.NET: Custom binding code (see example)
ASP.NET MVC: ModelBinder
WPF: CustomBinder
Windows Forms: Custom Converters/Editors
As parsing and formatting usually happens in the UI layer, I doubt you will find a solution that works at the data/model layer and which will work universally or which can do more than just validation.
In the data annotations namespace, there is a DataType.PhoneNumber which you can attach to your properties. Though you, yourself, remain responsible to do the parsing and the formatting using the appropriate display technology.
Data annotations and datatype are used for validation, not for converting values. The datatype is mostly used so that the validation knows where to start guessing.
2. That is asking too much for someone to code an extension like that, especially without showing any effort.
You can use DataTypeAttribute like so:
[DataType(DataType.PhoneNumber)]
public string PhoneNumber{get; set;}
Assume i want to create an alias of a type in C# using a hypothetical syntax:
Currency = float;
Then i go away and create a few thousand files that use Currency type.
Then i realize that i prefer to use FCL types:
Currency = System.Single;
Excellent, all code still works.
...months later...
Wait, i'm getting some strange rounding errors. Oh that's why, System.Single only has 7 digits of precision. Lets up that to 15 digits:
Currency = System.Double;
...years later...
Ohhhh, floating point isn't exact; multiplying $0.0011/unit * 217,384 units exposes some limitations of using floating point. And accountants are sticklers against "accounting irregularities". No problem:
Currency = System.Decimal;
...years later...
International applications? Currency codes. Hmmmm. Thank you CodeProject:
Currency = Money;
...later...
Ooo, patterns and practices. Let's obfuscate some of that code:
Currency = ICurrency;
And during all this nonsense code didn't break.
i know C# doesn't support this level of encapsulation and resilency with the syntax i made up.
But can anyone suggest a syntax that can simulate what people have been trying to accomplish (including myself)?
Create a class called Currency and implement (or delegate) the appropriate operators, then just change the class used to store the data internally when desired.
You can use using like so: using Currency = System.Single;, but you must do it in every single file. But still easier to change, than searching for single in whole application.
I'm currently doing an app, that needs to be able to work with the US number layout (123,456.78) as well as with the German layout (123.456,78).
Now my approach is to use NumberFormatInfo.InvariantInfo about like this:
temp = temp.ToString(NumberFormatInfo.InvariantInfo);
this works great when for example reading a number from a textbox. When System is set to English format it will take the . as separator, when it's set to German it will use the ,.
So far so good....but here's the problem: I have a device that returns info in the American format, and that won't change (transmitted via RS232). So I receive something like 10.543355E-00.
Now when on German setting the . will be discarded since it's just the group separator
and the number I will end up with is 10543355....which is a lot more :)
I tried with the same technique thinking this would make the whole thing kind of 'cultureless' to be able to process it independently from the system language but it didn't work :)
I hope you can maybe help me here...I'd love to use a way without having to implement the whole culture stuff etc since all I need here is really numbers that get calculated the right way.
You should use CultureInfo.InvariantCulture when parsing strings from the device. This will cause it to use the invariant culture, which has the US rules for decimal separation.
Edit in response to comments:
The issue is not when you call .ToString(), but rather when you read the string from the device, and convert it to a number:
string inputFromRS232Device = GetDeviceInput();
double value;
// You need this when converting to the double - not when calling ToString()
bool success = double.TryParse(
inputFromRS232Device,
NumberStyles.Float,
CultureInfo.InvariantCulture,
out value);
I am attempting to save financial transactions to a database using NHibernate and have come across a number of blog posts suggesting the use of a Money Type whereby the amount is stored as a double and the currency is stored as a string - i.e. there will be two fields in the database.
For my purposes, I will have multiple financial records in the same table - e.g. Unit Price, Tax in dollars, savings in dollars, etc. The above approach will work, but will result in duplicated data as there will be a column for the currency type of each of these (in this example 3) fields. This is unnecessary as the currency will always be the same for savings as it is for price, etc. - if it is dollars for one, it will be dollars for the other...
Has anyone run into a similar issue and, if so, can you tell me the solution you ended up with?
Thanks
JP
I have seen the same thing many places too, so far I have seen no explanation of why. What good is it? This is not how people do business or how a logical system works. If I am doing international business from the US, my systems will still have an internal basis of the dollar.
Currency is important as a boundary condition for an event, where you need an exchange rate. Even an international bank. I currently send all my drug money, USD, to the Caymans where my money is available to me also accounted in dollars. Maybe yours is in euros. So they get it, and what they do is convert both to whatever currency they use internally, sea shells whatever. Now they have to keep up with this stuff, but what they have to know at any given time is the exchange rate between dollars/sea shells to know how much they are in to me for, and sea shells/euros to know how much they are in to you for. This little goody does not do squat for them either it is a value object, how could it? Currency in this case would be fixed at the account level, not a bunch of these things floating around.
In general currency will be fixed by something else, like you observe, at a row level. A row of data is related, you should be able to do math on money values, in which case the currency in a row would have to be the same. Maybe I do business in Europe and have to quote in euros. I might want to record for historical purposes a quote versus payment in both currencies. I question if this is a single row design but if I decided it were, a Money object you describe is a single value object with two components. It should be considered a single entity, and I think what I am describing here is semantically different from a "Money" object and might as well be described explicitly by decimal/currency columns that we do not try to composite as a sing;e Money value because they cannot be compared or have math done on them.
I would just not go this route because leads to confusing subtle inconsistencies in semantics, and probably adds nothing. Where are you ever really going to use it that a row-wise currency would not give you the same thing, typically in a more rational fashion?
But if a manager insists you do something that is fundamentally pointless or worse, in terms of NHibernate you have declared a single atomic entity, Money that happens to have 2 components, a decimal and string. Because Money is now a single atomic unit, you have to always have both columns for each money, there is no workaround for avoiding the duplicate columns.