We have a Winform application that gets some numeric values from a database. This works fine when the users version of windows is English. So number formats are all perfect. However when the same application is opened in Windows 7 with Portuguese as the base language (Portuguese-Brazil), the numbers are all formatted wrong. This is because US English and Portuguese formats for numbers are totally different.
It appears this change has occurred recently in .NET Framework 4.0 since the application was working perfectly when it was built using 2.0 Framework.
Example, the number "THOUSAND" will show up as 1.000,00 which is being interpreted as ONE in the system running the Portuguese version of windows.
English: 1,000.00 = Thousand
Portuguese: 1.000,00 = Thousand
Can someone point me to any resources on how to work around this or what is the correct method to force an application to use database values instead of formatting them to the local users' system? The users are OK with numbers being displayed in the US Format.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
this will reset the culture, use it at the start of your form/program
or
Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
you can try both as i am not sure which one is gonna work
The format (delimmeters and spaces) of displayed numbers is a matter of their string representation. Decimals are stored in DB or memory without delimeters (obviously), they are just 128bits on your hard disk (roughly saying). The format comes to scope when you try to display them. If your number are stored in DB in correct numeric format, then this should not be a problem.
The problem may occur if somewhere you try to convert a string to number. For instance if you store values in db as string (I hope you dont). In this case you should specify the format provider each time you convert numbers to string and vice versa.
For instance:
decimal.Parse(numberAsString, CultureInfo.InvariantCulture); // 1
decimalNumber.ToString(CultureInfo.InvariantCulture); // 2
reference 1
reference 2
Related
I'm running windows 10 and recently updated my MVC app from 32 bit to 64 bit, including the Oracle client.
I installed ODAC1931_x64 on my machine and am using this nuget:
https://www.nuget.org/packages/Oracle.ManagedDataAccess/
When I run the app on my desktop, everything works fine. I can pass dates to my DB packages like so:
comm.Parameters.Add(Constants.DATABASE_PARAMETERS.FIELDS.START_DATE, OracleDbType.Date).Value = startDate;
And in the DB package the date come through as:
25-NOV-20
I installed the same ODAC on the server, Windows 2016, and moved my app to it. But when I run it, the date is showing up on the DB as:
20-11-25
And now the DB package is throwing the error:
ORA-01858: a non-numeric character was found where a numeric was expected
This did not happen when I was on 32 bit Oracle, the date came through as 25-NOV-20, it only happens with the 64 bit client and only on the server, not my desktop.
Any idea how to fix this?
You are relying on implicit date conversion in order to display it and enter it as a string. You need to use conversion functions with explicit date formats in order to be safe.
Eg. to_char(my_date_column,'dd/mm/yyyy hh24:mi:ss') if you want to display a date as a string
to_date('25/11/2020 21:00:00','hh24:mi:ss') if you have a string and want to set a date column.
Remember 2 digit years are why every software engineer worked around the clock coming up to the year 2000. Always use 4 digits.
Here's a weird one...
I've just seen a (previously passing) test fail because of extra spaces in a string representation of a date. The test in question has previously passed in CI and on my local machine, but is now failing (on my local machine) because of extra spaces between segments of the date.
The same behaviour is exhibited by the following MCVE:
using System;
using System.Globalization;
public class Program
{
public static void Main()
{
var date = new DateTime(2018, 01, 31);
var format = "d/M/yyyy";
var skSK = new CultureInfo("sk-SK");
Console.WriteLine(date.ToString(format, skSK));
}
}
In most places (including .NET Fiddle) this correctly returns:
31.1.2018
But on my machine, I now get:
31. 1. 2018
Note the extra spaces!
I'm confident that this was working as expected on my local PC just earlier this week, as I was using the project with this test in as a starting point for some experimentation with coverage tools. When I've resumed that experimentation this afternoon, the coverage file is no longer being produced due to the newly failing test.
What could have changed on my PC to cause this broken behaviour?
In Windows (like many others System), the source for the Locale date/time formats is the Unicode Common Locale Data Repository (CLDR), which provides internationalization and localization support specific for software developers and linguists.
A Short list of meaningful users:
Microsoft (Windows, Office, Visual Studio etc.)
Apple (macOS, iOS, watchOS, tvOS, Apple Mobile Device Support and iTunes for Windows;
Google (Web Search, Chrome, Android, Adwords, Google+, Google Maps, Blogger, Google Analytics)
IBM (DB2, Lotus, Websphere, Tivoli, Rational, AIX, i/OS, z/OS)
Amazon
See the Online data explorer of the Localizations: Locale Explorer.
The Short Date format, localized to the sk-SK culture as d. M. yyyy, is the one listed in this archive. It's the same for all OS (Windows 7 to Window 10).
A MS Developer related blog: Locale Builder and Finnish or other locales.
Fiddler or other Online code-runners services are not a source of comparison on this matter.
Locales are different from system to system. Also, these international formats change over time and depend on the updates that a system receives (if it receives these updates at all).
In Windows 7 and Windows 10, the default Short Date format for the sk-SK Culture is d. M. yyyy.
But the DateTime patterns do not match, if the formats list is parsed further.
string format = CultureInfo.CreateSpecificCulture("sk-SK")
.DateTimeFormat.GetAllDateTimePatterns()[1];
In Windows 7, the second element in the DateTimePatterns list is d.M.yyyy
In Windows 10, the element at the same index is: dddd d. MMMM yyyy
A Windows update may change the default pattern for any of the Locales (without explicit notification).
It's understood that applications must provide parsing means for special cases. Or refer to the user Locale settings when formatting, without trying to force a specific pattern for internal uses.
Date/Time formats should be used for presentation only. The Locale and the user settings determine that format. An user of a System may decide to use a different format than the default Locale.
This GitHub repository holds an updated JSON of the CLDR database:
CLDR Date Modern
Also interesting, the ECMAScript reference for API internationalization:
ECMAScript® 2017 Internationalization API Specification
MSDN latest guidelines for Globalization and localization (UWP related):
Globalization and localization
Globalize your date/time/number formats
Use the Multilingual App Toolkit 4.0
I had the same issue in my Windows 10 machine, got "31. 1. 208". But using:
var format = "d.M.yyyy";
produces: 31.1.2018
it seams to be something with CultureInfo("sk-SK"):
Console.WriteLine(date.ToString("d", new CultureInfo("de-DE")));
produces: 31.01.2018
and
Console.WriteLine(date.ToString("d/M/yyyy", new CultureInfo("de-DE")));
produces: 31.1.2018
(in Windows Control Panel - Region, mine is set as "English - Canada" and short date: "dd/MM/yyyy".
It seems to be defined in the .Net Framework - see the spaces there:
I hope that helps.
I set the culture for an .NET web app in order to use specific format for numbers, currency and date:
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("fr-BE");
On an Windows 2008 server machine with IIS 7 I get "d/m/yy" as short date format (what I want).
On my (new) Windows 8.1 pro machine (developer and test) I get "d-m-yy" format for the same CultureInfo..."dash" instead of "slash" separator.
I've checked also in Control Panel -> Region and the settings for French(Belgium) are as mentioned above, different in W2k8 server than in W8.1pro...
The .NET version is 4, which is ok. Invariant culture doesn't help, as far as I need specific culture to display in the UI and the problem was there. It is true, changes came with Windows 8... Finally I used to override some settings for the Thread culture, like the Date Separator:
DateTimeFormatInfo dtfi = Thread.CurrentThread.CurrentCulture.DateTimeFormat; if (dtfi.DateSeparator != "/") dtfi.DateSeparator = "/";
This ensure that slash will be the date separator all the time in the current thread.
Thank you.
Does anybody knows about it? Belgium changed national standards? Or, Microsoft did for them? Any idea?
Thanks.
Thanks for the answers. .NET version is 4, which is ok. Invariant culture doesn't help, as far as I need specific culture to display in the UI and the problem was there. It is true, changes came with Windows 8...
Finally I used to override some settings for the Thread culture, like the Date Separator:
DateTimeFormatInfo dtfi = Thread.CurrentThread.CurrentCulture.DateTimeFormat;
if (dtfi.DateSeparator != "/") dtfi.DateSeparator = "/";
This ensure that slash will be the date separator all the time in the current thread.
Thank you.
I was looking at similar issue for CultureInfo 'en-NZ', as it been changed for the same culture setting in different Windows version, and cause my web service saved different strings for the same CultureInfo, and it turns out it is provided by Windows since .Net Framework 4, and was a combination of Windows and .Net before that.
Lucky for me, I can make use of Invariant culture, which was recommended by Microsoft to make sure the string I saved into Database not going to be changed because of Windows or future .Net Framework update. The thing is, for my case it was the AM\PMDesignator changed from a.m.\p.m. to AM\PM, and the Invariant culture will make sure it saves to AM\PM I assume it will not change in the future, but if I want it save to a.m.\p.m. as it was for older version of Windows, Invariant culture wouldn't be able to do that, I will probably need define my own custom culture or overwrite the current culture as you did.
See the other question about Microsoft specified that CultureInof are subject to change without notice
Well I am looking for a method to change the default windows 7 time format for a system.
So if a system uses like 10PM or 10 AM as default time notation, then i like to change that system to 10:00 or 22:00.
I know how to do it through the GUI, but in my case our software (C#) has to check if time notation is OK and if it is not change it by usage of
C#, registry editing, vbscript, commanline or Powershell, or some specific .exe file
The software we wrote allready makes usage of external progs / languages (vbscript/powershell).
But the problem is so far i have not found a method to do this other then taking over a remote screen.
Perhaps someone knows how to do this ?
The same counts for time zone, and date notation.
You may change the system time format using following code:
RegistryKey rk = Registry.CurrentUser.OpenSubKey(#"Control Panel\International", true);
rk.SetValue("sTimeFormat", "hh:mm:ss"); // HH for 24hrs, hh for 12 hrs
But IMO, this would not be a good practice for an application to change the system user's settings without the consent of the user.
I found this link that shows it being done via vb.net but you would have to translate it. or you could compile this to an exe and run it from a shell. http://www.access-programmers.co.uk/forums/showthread.php?t=152624
The property way to do this in .NET is with code such as the following:
CultureInfo newCultureInfo = (CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
newCultureInfo.DateTimeFormat.ShortDatePattern = shortDateFormat;
newCultureInfo.DateTimeFormat.LongTimePattern = longTimeFormat;
Thread.CurrentThread.CurrentCulture = newCultureInfo;
Regarding the solution using the "Control Panel\International" registry key (sorry, can't comment due to not have a 50 reputation):
This doesn't appear to affect the existing process, only new processes created after changing the registry. And obviously code assuming registry values (i.e. implementation details) could break in a future version of windows.
Also the code should Dispose the RegistryKey object. It would be better written with a using block.
Regarding if you should do this, while it would be unlikely an app would want to change the time date format (maybe an app that's an improved way of setting system info), it would be very reasonable to need to do this in an automated test. It's a common bug for code to depend on the default time/date format, so setting them to non-default values, or testing code with various time/date formats could be a good idea.
I am developing a software that uses number precision, but I have this problem, it happens that when I take a string to convert to double it outputs me with a different culture.
For example I use
Convert.ToDouble("4089.90"); // it outputs 40.899,00
Is strange cause in my computer it works OK but on the client's PC (with the same culture in regional settings) shows me the latter output. I know I can fix it using
Convert.ToDouble("4089.90", System.Globalization.CultureInfo.InvariantCulture);
But there is a lot of code in the program using "Convert.ToDouble" and I wouldn't like to change all of it, on the other hand I want to understand why this happens.
You can set the culture for your thread with:
Thread.CurrentThread.CurrentCulture =
System.Globalization.CultureInfo.InvariantCulture;
You don't say where you are based, but the output is consistent with the current culture being one that has "." as the thousands separator and a decimal comma rather than a decimal point.
However, you state that the culture is the same - which contradicts this. Have you or the client changed (or customised) the "Standards and formats" on the Regional and Language Options? If the setting has been customised it will still read as "English (United Kingdom)" (or where ever) but will produce different results to the default.
I know neither c# nor asp.net, but I think the problem is this: You are performing the operation in a culture where the dot . is the thousands separator and not the decimal separator. The very output you quote is the proof: 40.899,00.
What culture/locale are you working in?
Culture could be based on where the ASP.Net application is running, and not the client PC that is running the browser. While their desktop PC might have similar culture settings, the server may differ.
It is your computer that is not giving the correct answer, not theirs. Your culture states that "4089.90" is the same as 4089900, since the dot (.) is used for separating thousands (and thus there should be three numbers after the dot).
It appears you want to use the dot as a decimal-separator, contrary to your culture settings; so you have to use System.Globalization.CultureInfo.InvariantCulture in your program. Sorry.
Actually is very rare this behaviour cause all the machines have the same culture settings, however I think that the best solution would be to modify the web.config like this:
configuration>
<system.web>
<globalization culture = "es-HN" />
</system.web>
</configuration
And apply the settings for the entire application.
Thanx everyone for your assistance.