Decimal ToString F02 becomes Comma - c#

If I open up a Console Application and run this:
decimal urmom = 84.3400m;
Console.WriteLine(urmom.ToString("F02"));
I get 84.34
In a web application I'm running, I have this code:
public static string PayPalJunk(string successURL, string failureURL, decimal total, string currency)
{
NVPCodec encoder = new NVPCodec();
encoder["PAYMENTREQUEST_0_AMT"] = total.ToString("F02");
//...
}
Even if I break before executing that line and do a Watch on total.ToString("F02"), i get 84,34. The Mouseover of total in the parameter list shows 84.34.
Why? decimal is just a value, right? It isn't a reference object with some hidden properties that might have been corrupted with some culture info... right?

It has to do with the culture of the thread that is running. If you want to get the string formatted in en-US regardless of the thread then you need to pass in a specific culture to ToString. If its running under a web server and you want to ignore the culture of the requsting browser/client you can also specify a static culture in the web.config.
How to specify culture in ToString
var formatted1 = total.ToString("F02", System.Globalization.CultureInfo.InvariantCulture);
// or
var formatted2 = total.ToString("F02", new System.Globalization.CultureInfo("en-US"));
See Decimal.ToString Method (String,IFormatProvider)
How to configure web.config
<globalization uiCulture="en" culture="en-US" />
See also How to: Set the Culture and UI Culture for ASP.NET Web Page Globalization
Why? decimal is just a value, right?
No, you are converting the decimal to a string and depending on the culture that string representing the decimal might be displayed differently. For example: in the Netherlands a comma is used to separate a whole value from the partial/fractional part of the value and a period (.) is used to segregate groupings like thousands,millions,billions,trillians etc. In the USA these symbols have the exact opposite meaning.
Detecting the culture of the caller is usually a good thing and returning the data formatted based on the callers culture is usually also desired behavior. If not though then see above for 2 ways to ensure that the code can always return a consistent formatted data.

You are getting these results because the cultures in two environments are different. Try this:
encoder["PAYMENTREQUEST_0_AMT"] = total.ToString("F02", System.Globalization.CultureInfo.InvariantCulture);
or whatever culture you want your string formatted to.

Related

Culture-insensitive VS Culture-sensitive

I've seen a lot of time about Culture-insensitive and Culture-sensitive i don't Knew exactly what are The difference between them.
In some books they divide the Specifiers into Two categories:
Culture-insensitive date/time format strings and
Culture-sensitive date/time format strings
I knew the specifiers but I have no idea abut sensitive and insensitive.
could anyone guide me in this?
To start, I would refer you to .NET Globalization & Localization for more information.
There are certain values/entities that get treated differently in different countries and regions. Such entities include currency symbol, digit separators, dates and more. When displaying this data to your user, you have to format it in a way that makes sense to them. If for instance you display money in a loan amortization application as follows:
Console.WritLine("$" + amount.ToString());
this will only work well in countries that use dollars. And there's no other formatting. To make this culture sensitive, you will have to do it this way...
Console.WriteLine(amount.ToString("C"));
By doing it that way, .NET will use the correct currency symbol, digit separator and decimal point for the culture the application is run in.
There are cases in which you will need to show such data in a specific culture. Doing it this way will change the way it is displayed, you can however provide the culture to use in the following way...
static void Main(string[] args)
{
decimal foo = 23434534.53M;
Dump(foo);
var culture = CultureInfo.CreateSpecificCulture("en");
CultureInfo.CurrentCulture = culture;
Dump(foo);
culture = CultureInfo.CreateSpecificCulture("es");
CultureInfo.CurrentCulture = culture;
Dump(foo);
culture = CultureInfo.CreateSpecificCulture("en-ZA"); // South Africa
CultureInfo.CurrentCulture = culture;
Dump(foo);
}
static void Dump(decimal value)
{
Console.WriteLine(value.ToString("C"));
Console.WriteLine(DateTime.Now.ToLongDateString());
}
When you change the culture at run time, subsequent calls to display the value as money will change the currency symbol, the location of said currency symbol in some cases, the digit separators and the decimal point.
This also affects how dats are displayed as you can see.
You can also use this to change the text displayed in your UI. If you have an app that supports multiple languages, for instance US English, British English, Spanish and French you are not required to know these languages beforehand. Also, you can no longer hard code you string literals like "First name:". Some simple things may differ like the spelling of color (UK English colour). Such things might be inconsequential to someone who doesn't speak English but are taken seriously in the respective countries. If your app is showing children the correct spellings for instance, you want it to get it right for the place it is in.
In this case you can set a UI culture and use resource (resx) files to place your strings in. At runtime you load your strings from the resource files and the .NET runtime can load the correct resx file based on the culture it detects the PC is set to. If there is no match, it will fall back to your default culture.
In my test app I created 2 resource files, one called Strings.resx and the other Strings.es.resx. The first will be the default language, and the other is for Spanish. When greeting a user, I won't have to hard code the greeting but can use it as follows
static void Main(string[] args)
{
Console.WriteLine(ConsoleApp1.Strings.HelloString);
CultureInfo.CurrentUICulture = CultureInfo.CreateSpecificCulture("es");
Console.WriteLine(ConsoleApp1.Strings.HelloString);
}
resulting in the following
Together these techniques can help you create an application that is sensitive to the language and culture of the user. If you need to override that, you can also do that knowingly by specifying which culture to use when presenting your data. Hard coding the entities that vary is not culture sensitive and will display the same regardless of the locale of the machine it is run on.
Culture-sensitive operations should be used when interacting directly with users. Culture-insensitive operations should always be used when interacting with back-end processes and interchange systems, including persisting data. The data that backs culture specific operations can change for many reasons. The data that backs culture-insensitive operations never changes and so is safe to persist and interchange.

CultureInfo.InvariantCulture in .ToString()

I am currently fixing FxCop issues so I encountered issue where I have to provide cultureinfo when converting a string using ToString() .
Currently in my code nothing we are passing as IFormatProvider so I have read some msdn articles saying that when you don't pass any value for cultureinfo it will assign a default value and when you specify CultureInfo as InvariantCulture it will be independent of any culture.
My question is, "Are default and CultureInfo.InvariantCulture one and the same? Can I replace all my code from default to InvariantCulture?"
Ex :
int st = 123;
String s = st.ToString(123); // this will be taken as default
String s = st.ToString(123, CultureInfo.InvariantCulture); // culture is specified externally
Are the second and third lines equivalent?
Is default and CultureInfo.InvariantCulture are one and the same?
No, absolutely not. The default culture depends (initially) on the operating system settings. The invariant culture is meant to be a "neutral" culture.
Your example of 123 isn't a great one, because most (all?) cultures will represent integers the same way - at least until you get into formats with grouping separators etc. (I don't think .NET supports non-Arabic numerals when formatting integers.)
Compare that with formatting a decimal value, for example:
decimal x = 123.45m;
Console.WriteLine(x.ToString()); // Might be 123,45
Console.WriteLine(x.ToString(CultureInfo.InvariantCulture)); // Always 123.45
If you run the above code in (say) France, the default culture will be French, which uses a comma as a decimal separator - so it will print out "123,45".
The rule of thumb to remember is that the invariant culture is suitable for machine-to-machine communications (e.g. formatting values in JSON or XML) whereas other cultures are more suitable for displaying information directly to users.
Although the default culture is originally based on the operating system settings, it can be changed using Thread.CurrentCulture and Thread.CurrentUICulture; the latter is used for looking up translated resources, whereas the former is used for formatting decisions like the above. You can set these properties on any thread, but typically you'd use Thread.CurrentThread.CurrentCulture = ...
No, they are not the same.
The first will take the regional settings from the computer or the culture settings from the application thread running.
The second one will take the English language, according to MSDN:
The invariant culture is culture-insensitive; it is associated with the English language but not with any country/region.

Converting string to decimal: how to handle the decimal separator in different cultures

I need to write decimal value to ms access database, but i have a problem with conversion values to decimal in different cultures. Have a values from file, which separates by commma. I try:
public decimal CSingleCulture (string str)
{
string sep = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
string s = str.Replace(",", sep);
return decimal.Parse(s);
}
if NumberDecimalSeparator = "." then work is good, but if NumberDecimalSeparator = "," problems begin... decimal.Parse(s) always return vlaues separates by dot. In this situation, when inserted into a database error occurs.
The recommended way to deal with this is to store the value as a number rather than a string. Both in the database and in your program. When you do that, your current problem simply never arises.
The only time you deal with numbers in string format is when you display them, or accept user input. In those scenarios you can use the user's culture settings to let them see and use their preferred separator.
Should you ever need to convert between string and number for persistence then you must use culture invariant conversion. This appears to be where you are falling down. I suspect that the file you read has no well-defined format. Make sure that when you read and write the file you use CultureInfo.InvariantCulture. If the file does have a well-defined format that differs from the invariant culture, then use an appropriate specific CultureInfo.
Can't actually understand what is it you're trying to accomplish, and I have to agree with the other answer. But one other thing that's good to know is you can use invariant culture like so:
double.Parse("15.0", CultureInfo.InvariantCulture)
This will always expect dot character to delimit your decimal digits regardless of what is set in current thread's culture.

Formatting Currency to ALWAYS use USD regardless of users culture

This should be simple but I cannot find the answer anywhere.
On our asp.net MVC site, we show currency values and I need these currency values to Always be in USD regardless of the users culture settings.
If I use string.format("{0:C}",value) then it shows the value in what ever culture the use has set.
This is incorrect for us as $1000.00 is not the same thing as 1000.00 euro
I still need to use the language side of this, meaning if they are in France I want to use the French localization resource, so I don't want to completely disregard their culture settings, but how can I make sure the currency is always shown in USD?
Explicitly pass culture to the Format call:
string.Format(new CultureInfo("en-US"), "{0:C}",value)
If you have to mix it with other languages - save result of formatting currency value and insert into other places as string.
Side note: using "en-US" (or any other hard-coded culture) will lead to potentially mismatched representation of negative values i.e. some cultures use -100, while other (100) for negative amounts.
You would have to specify CurrentCulture to be en-US and leave CurrentUICulture as is.
I usually do this in global.asax.cs in the Application_BeginRequest event
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo("en-US", false);
It is possible to specify the culture in web.config file but that has one drawback - it takes into account the customized regional settings of the server (if the administrator changed the currency or date format on the server for the en-US culture, it would get picked up this way) - so you can't ever be sure that the application will behave exactly the same as when you created/tested it.

Monetary symbol (not $) in DataGridView field values

I'm building an application that is for a non-profit in Guatemala. Everything in the system is in Quetzales, which is denoted with a Q (i.e. Q100.00) is 100 Quetzales.
I need to be able to modify the monetary values in any DataGridView column, but I've been unable to figure out an easy way to do it with formatting like you can with a dollar sign. I don't want to use computer region settings because some people using the system, use computers from the US.
Not sure if it's important, but values come out of a sql server database from a 'money' type field.
When formatting a string you can specify which culture you want to use:
decimal cost = 1500m;
string s = cost.ToString("C", CultureInfo.GetCultureInfo("es-GT"));
Result
Q1,500.00
If you do not want to rely on the Regional settings you can force the application to execute using the Guatamala culture regardless of the regional settings.
CultureInfo culture = new CultureInfo("es-GT");
decimal amount = 123.43M;
// Set the culture for the thread
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
// Uses the thread culture for formatting
MessageBox.Show(amount.ToString("c"));
// Alternatively if you do not want to set the thread culture
// you can explicitly format using the passed culture
MessageBox.Show(amount.ToString("c", culture));

Categories