CultureInfo nb-NO DateTime.TryParse difference in VS2019 and on dotnetfiddle.net - c#

On my machine when I run and output the following
string locale = "nb-NO";
CultureInfo culture = CultureInfo.CreateSpecificCulture(locale);
string shortDateFormatString = culture.DateTimeFormat.ShortDatePattern;
string shortTimeFormatString = culture.DateTimeFormat.ShortTimePattern;
I got the following output
shortDateFormatString "dd.MM.yyyy"
ShortTimePattern "HH:mm"
But on dotnetfiddle.net I got the following
shortDateFormatString "dd.MM.yyyy"
ShortTimePattern "HH.mm"
I suppose C# uses CLDR, so according to
https://github.com/unicode-cldr/cldr-dates-full/blob/1af902b749bef761f07281f80241250053b4313d/main/nb/ca-gregorian.json#L323
Both short time pattern should be valid.
And on dotnetfiddle it is possible to parse nb-NO datetime looking as following
06.12.2017 12:34
06.12.2017 12.34
However in VS2019 on my machine it is only possible to parse
06.12.2017 12:34
How is it possible it is different? both is using .NET 4.7.2.
You can check my fiddle here https://dotnetfiddle.net/68DDYz

How is it possible it is different?
Because culture information is loaded from the operating system, and changes over time. Unless two machines are on the exact same version of Windows (same set of updates, hotfixes etc), it's entirely possible for them to have different values for things like short time patterns. (And yes, that's annoying, but it's part of life.)

Jon is quite right (duh!)
Culture settings are tricky. Since they are stored on the windows registry, they can be different/change over .net framework versions, operating system versions, windows updates, hotfixes etc. That means even if both server uses same .NET Framework version, that doesn't mean that every culture settings will be same for both.
I can show you the it-IT culture for example.
See: .NET (3.5) formats times using dots instead of colons as TimeSeparator for it-IT culture?
For .NET Framework 3.5, it-IT culture has . as a TimeSeparator but with .NET Framework 4.0 version, it changed to : which is stated on Wikipedia.
This changes are not end of the world of course, but it was not pleasant either.

Related

Where does the mathematical minus sign come from?

I have a C#/.NET library, which works fine in my own environment, but not in a customer's for some reason. In this specific case, .NET Framework 4.8 is used, but they have tried .NET 6 as well with the same results.
I am converting a double with value 0.25 to a string like this:
doubleValue.ToString("E16", CultureInfo.InvariantCulture);
In my environment, I get the expected string
2.5000000000000000E-001
with a hyphen-minus sign (U+002D) in the scientific notation. As seen in the code, I am using InvariantCulture in order to avoid any confusions regarding decimal point signs and minus signs.
In the customer's environment, with the same code they get the string
2.5000000000000000E−001
with a mathematical minus sign (U+2212) in the scientific notation.
We are both running Windows, with the en-SV culture active. I am printing out the details of InvariantCulture and CurrentCulture in a test program, and in both environments, the negative sign for both cultures is hyphen-minus. Not that current culture should affect anything, since I'm explicitly using the InvariantCulture for the conversion.
The customer has tried setting the environment variable DOTNET_SYSTEM_GLOBALIZATION_USENLS to true, in case there were issues with ICU, but it didn't help. Not that it was likely, since ICU isn't used in .NET Framework. I just couldn't find anything else to try.
What else could affect .NET's choice of minus sign in ToString, apart from culture and NLS/ICU?
EDIT: Additional information: This was not an issue in the previous release of my library. I just released a new version where this became a problem. Since the previous release, I have not touched this conversion code at all. I have added support for .NET 6 (new code that the customer is not running above), and migrated my code from VS2019 to VS2022.
EDIT: Clarified the unicode characters used.

Why does String.Equals with InvariantCultureIgnoreCase behave different in .net 4.7.2 and .net 5?

I have the following line of code:
String.Equals("strasse", "straße", StringComparison.InvariantCultureIgnoreCase)
In .net 4.7.2, this returns true.
In .net 5 (and .net 6), this returns false.
Why?
I'm currently learning how comparing strings works in C#. NET. and have come across an unexpected result that I do not fully understand.
When using the overloaded method String.Equals(string,string,Stringcomparison) to compare string :"strasse" and string : "straße" with the following Stringcomparison :
Console.WriteLine(String.Equals("strasse", "straße", StringComparison.OrdinalIgnoreCase));
Console.WriteLine(String.Equals("strasse", "straße", StringComparison.CurrentCultureIgnoreCase));
Console.WriteLine(String.Equals("strasse", "straße", StringComparison.InvariantCultureIgnoreCase));
I get the following result :
False
False
False
I expected the first one to return false but both the second and third line to return true.
I first though maybe my CurrentCulture was the issue, so to be sure is et both the CurrentCulture and CurrentUICulture to :
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("de-DE");
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("de-DE");
Did I incorrectly understand String comparison ? or am I missing something obvious here ?
Thanks in advance for anyone willing to help me understand
When you target .NET Framework 4.x you are implicitly targeting a Windows Platform. Windows platforms handle Unicode and Cultures in their specific way, which is the direct byproduct of the evolution of the platform during the last 30 years. The standard for Windows platforms is using NLS Apis.
However, this is not the case for other platforms.
During the past years the ICU project tried to provide a unified, de-facto standard for handling Unicode characters (and more). Since .NET Core runs by design on Windows, Linux, Mac and (possibly) Android devices, you expect your application to behave consistently regardless the platform it runs on
For this reason, .Net Core 5 switched to ICU libraries as a breaking change. You can find more information on Globalization APIs use ICU libraries on Windows. ICU libraries are available for many languages and are interoperable, thus allowing better integration.

Different formatting on different computers when using the same CultureInfo, why?

I'm having an issue when using CultureInfo.
This is basically my code:
Console.WriteLine(0.5.ToString("P2", new CultureInfo("en-US")));
When running it, this is what I get on two different computers:
As you can notice, the formatting isn't the same. The Australia VPS ( running Windows Server 2016) having a space before the percent symbol compared to my computer (Windows 10).
Why that? How can I "really" use the same CultureInfo/formatting everywhere?
The CultureInfo on Windows uses machine/user level locale information and does not have any information on its own. This information is updated relatively frequently by OS versions and updates. As result machines with different levels of patches or different versions of OS will likely have differences, usually minor as you see but sometime critical if something like decimal separator changes between '.' and ',' or currency symbol for a region changes.
Usually it is not a problem as such formatting is used only to show/parse values from the user and not to store data anywhere (which uses InvariantCulture). Most individual users would not ever use enough machines to notice difference in desktop apps. And for server side code (i.e. ASP.Net) running multiple servers with different versions of OS is even less likely.
If you really must show identical formats independent of OS you would have to build your own CultureInfo objects for locales you interested in. In many cases you can just create your own CultureInfo based on existing one and just patch properties you care about.

CultureInfo("ar") returns English on server

Running this code should yield the Arabic representation of current month and it does on my local machine, however when running on server I always get English.
new CultureInfo("ar").DateTimeFormat.AbbreviatedMonthNames[System.DateTime.Now.Month]
At first I suspected it has something to do with request localization hence I tried to just new up a new culture info and see what it outputs, so the above code returns English regardless.
Set of supported cultures is OS specific - you get different sets even between flavors of Windows - desktop and server editions are different, generally with server having less supported cultures. Also the older version of Windows you use smaller list of cultures is supported. The same applies to running .NET core on other OS (including Linux in Kubernetes containers) - it's OS that essentially drives list of supported cultures.
Note that some OS (Windows 10 in particular) will happily provide you with "culture info" for any string you pass - it will try the best to construct something that may make sense (i.e. for "ru-GB" it may try to give "en-GB" culture as the closest one), but for something that has no information whatsoever you likely get invariant/neutral culture (which generally resembles en-US).

How to translate between Windows and IANA time zones?

As described in the timezone tag wiki, there are two different styles of time zones.
Those provided by Microsoft for use with Windows and the .Net TimeZoneInfo class (when running on Windows) are identified by a value such as "Eastern Standard Time".
Those provided by IANA in the TZDB, and used by the .NET TimeZoneInfo class when running on Linux or OSX, are identified by a value such as "America/New_York".
Many Internet-based APIs use the IANA time zones, but for numerous reasons one might need to convert this to a Windows time zone id, or vice-versa.
How can this be accomplished in .Net?
Current Status:
Starting with .NET 6, both forms of time zones are supported on any platform that has both time zone data and ICU installed, which is most installations of Windows, Linux, and MacOS. See Tobias's answer.
Original Answer:
The primary source of the data for conversion between Windows and IANA time zone identifiers is the windowsZones.xml file, distributed as part of the Unicode CLDR project. The latest dev version can be found here.
However, CLDR is released only twice annually. This, along with the periodic cadence of Windows updates, and the irregular updates of the IANA time zone database, makes it complicated to just use the CLDR data directly. Keep in mind that time zone changes themselves are made at the whim of the world's various governments, and not all changes are made with sufficient notice to make it into these release cycles before their respective effective dates.
There are a few other edge cases that need to be handled that are not covered strictly by the CLDR, and new ones pop up from time to time. Therefore, I've encapsulated the complexity of the solution into the TimeZoneConverter micro-library, which can be installed from Nuget.
Using this library is simple. Here are some examples of conversion:
string tz = TZConvert.IanaToWindows("America/New_York");
// Result: "Eastern Standard Time"
string tz = TZConvert.WindowsToIana("Eastern Standard Time");
// result: "America/New_York"
string tz = TZConvert.WindowsToIana("Eastern Standard Time", "CA");
// result: "America/Toronto"
There are more examples on the project site.
It's important to recognize that while an IANA time zone can be mapped to a single Windows time zone, the reverse is not true. A single Windows time zone might be mapped to more than one IANA time zone. This can be seen in the above examples, where Eastern Standard Time is mapped to both America/New_York, and to America/Toronto. TimeZoneConverter will deliver the one that CLDR marks with "001", known as the "golden zone", unless you specifically provide a country code and there's a match for a different zone in that country.
Note: This answer has evolved over the years, so comments below may or may not apply to the current revision. Review the edit history for details. Thanks.
Starting with .NET 6, it is finally possible to work with time zones in a cross-platform manner, so these manual workarounds are no longer needed.
The TimeZoneInfo.FindSystemTimeZoneById(string) method automatically accepts either Windows or IANA time zones on either platform and converts them if needed.
// Both of these will now work on any supported OS where ICU and time zone data are available.
TimeZoneInfo tzi1 = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo tzi2 = TimeZoneInfo.FindSystemTimeZoneById("Australia/Sydney");
Note that, as specified on the link, the .NET Core Alpine Linux-based Docker images do not have the necessary tzdata installed by default, so it must be installed in your Dockerfile for this to work correctly.
I know this is an old question, but I had a use case I though I would share here, since this is the most relevant post I found when searching. I was developing a .NET Core app using a docker linux container, but for deployment on a windows server. So I only needed my docker linux container to support the windows timezone names. I got this working without changing my application code by doing the following:
cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
cp /usr/share/zoneinfo/America/New_York "/usr/share/zoneinfo/Eastern Standard Time"
cp /usr/share/zoneinfo/America/Denver "/usr/share/zoneinfo/Mountain Standard Time"
cp /usr/share/zoneinfo/America/Los_Angeles "/usr/share/zoneinfo/Pacific Standard Time"
Then, in my .NET code, the following worked without any modification: TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")

Categories

Resources