Wrong DateTime parsing when using other cultures - c#

I am using EF in a multi-language site to map results from SPs to objects.
ctx.Database.SqlQuery<MyDTO>("MySP {0}", Id).SingleOrDefault()
I see that there is an issue with mapping dates when the culture changes.
More specifically, I get the same date either as 16/12/2015 09:06:15 or 12/16/2015 09:06:15, depending on the user culture.
I know two solutions to this:
Get the date as a string and parse it with CultureInfo.InvariantCulture.
Switch the culture to CultureInfo.CultureInvariant before calling the repository methods.
And perhaps there is another option:
I see that we change both: Thread.CurrentThread.CurrentUICulture and Thread.CurrentThread.CurrentCulture to the user's locale, but I think we should only switch the UI one. But I am not sure what will break if I change this...
Is there any alternative, like setting the culture on the EF context?
Update:
Chaning the Thread.CurrentThread.CurrentUICulture and Thread.CurrentThread.CurrentCulture just before doing the query doesn't seem to help either. That is confusing... Perhaps EF caches the culture at an earlier point?

First off, you should avoid calling your stored procedures like that - it's an easy way to get that OWASP Top 10 Sql Injection security issue.
Instead, you should call by passing arguments to the stored procedure as actual parameters, for example something like this:
string dateAsString = "12/16/2015 09:06:15";
string dateFormat = "MM/dd/yyyy HH:mm:ss";
DateTime theValue = DateTime.Parse(dateAsString, dateFormat, CultureInfo.InvariantCulture);
SqlParameter myDate = new SqlParameter("#theDate", theValue);
context.Database.ExecuteSqlCommand("MySP #theDate", theDate);

You Can store the date time either in long (teaks) or real (the number you get when your cast datetime to real). Then you can convert these values to any culture without any loss.

I have figured this one out eventually. :)
I was viewing the values of DateTimes in watches. And that was actually the problem... Looks like watches use the culture of the current thread (and thus switching the order of month and day from culture to culture). Turns out the date was correct (this : 12/16/2015 09:06:15 could not be a valid date anyway if you consider 16 to be the month... Never too late to realize that...).
So, VS watchers disorientated me...
Good to know that the current thread culture does not affect the parsing of SQL data, as I would expect. :)
The actual bug was later-on in the code.

Related

Inconsistent Date Format when writing a CSV

I'm facing a very strange issue. I'm writing to a CSV file like this:
sw.WriteLine($"{posting.publishedOn},{posting.ExpirationDate}");
Posting Date is a DateTime object and Expiration Date is a DateTime? object.
However, when I run this on my production server in Germany, it's very inconsistent as to which date format it prints out. Sometimes I will have dates formatted like this (European style):
Posting Date,Expiration Date
06.08.2018 11:49,08.07.2018 11:49
And sometimes I will have dates formatted like this (U. S. style):
Posting Date,Expiration Date
8/15/2018 7:56:12 AM,10/14/2018 7:56:12 AM
Posting Date and Expiration Date are completely separate .NET Objects, but each line will be consistent - i.e. if one column is in European format, the other one will be as well.
I tried setting the culture like this:
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
but it didn't seem to make a difference.
This happens when I run the console application on my server in Germany.
What could be causing this? Is there a way to fix it without having to explicitly call ToString with a format every time I write a date?
Set the format explicitly, for example:
sw.WriteLine($"{posting.publishedOn.ToString("MM/dd/yyyy hh:mm tt")},{posting.ExpirationDate?.ToString("MM/dd/yyyy hh:mm tt")??""}");
EDIT: Just realized you explicitly said you don't want this solution. I'm going to leave my answer in case others find your question and ToString is a suitable solution.
Are you absolutely sure that the serialization is always happening in the same thread whose culture is being set?
Because if not, that may be the issue.
Just to debug it, please set the current thread culture immediately before the serialization code and check if the issue still happens, i.e.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
sw.WriteLine($"{posting.publishedOn},{posting.ExpirationDate}");
I believe you need to just set the specific culture like so:
CultureInfo.CurrentUICulture = CultureInfo.CreateSpecificCulture("en-US");

DateTime.TryParse fails for one user

I need to parse dates in my program, but it fails on the machine of one user (in denmark). It works for his colleagues who all has the same settings as far as I can tell.
The code looks as follows:
DateTime result;
if (DateTime.TryParse(InputBox.Text, out result))
YyyymmddField.Text = result.ToString("yyyyMMdd");
else
YyyymmddField.Text = "(invalid)";
CurrentCulture is da-DK and his configured format is: yyyy.MM.dd. The date string I want to parse is 2015.07.14.
This works on our machines here (in sweden) regardless of current culture. It also works for his colleagues, but not for him.
We have hundreds of users worldwide and as far as we know, his is the only computer that fails.
Could something other than the current CultureInfo affect how TryParse operates?
This works on our machines here (in sweden) regardless of current
culture
No. There is no such a thing. If you use DateTime.TryParse without any IFormatProvider, it will use the CurrentCulture settings of the current machine.
From documentation;
The string s is parsed using formatting information in the current
DateTimeFormatInfo object, which is supplied implicitly by the current
thread culture.
I'm using .NET Framework 4.5 and there are only 7 culture inside of AllCultures that doesn't have this as standard date and time format. If you won't/can't tell us what is your other colleague's CurrentCulture, I would assume he will use one of these from my perspective.
ar
bn
ml
ar-SA
bn-IN
ml-IN
bn-BD
Instead of that confusion, you can use InvariantCulture is your string has a stable format like yyyy.MM.dd instead of hoping his CurrentCulture settings will parse it or not.
use CultureInfo.InvariantCulture
DateTime result;
if (DateTime.TryParse(InputBox.Text, out result))
YyyymmddField.Text = result.ToString("yyyyMMdd",CultureInfo.InvariantCulture);
else
YyyymmddField.Text = "(invalid)";
In principle, it can be a good idea to have reusable methods (such as extension methods) for parsing DateTimes and numerics, which use the invariant culture.

Why is DateTime.TryParse() returning true for the culture "en-NZ" when MMddyyyy is passed in?

I have the following code:
DateTime.TryParse("06-28-2012", new System.Globalization.CultureInfo("en-NZ"),
System.Globalization.DateTimeStyles.AssumeLocal, out date);
I'm not sure why this is returning true since if I go into my Regional Settings in Windows, I only see the following date formats under short date:
d/MM/yyyy
d/MM/yy
dd/MM/yy
d.MM.yy
yyyy-MM-dd
So then why is a short date format like MM-dd-yyyy returning true? Shouldn't it return false?
I'm using this similar post as a source: DateTime c# parsing
Important:
Please note that I also have my regional settings set to use English (New Zealand) and chose
yyyy-MM-dd as my short date format.
Having your short date format set to yyyy-MM-dd is the cause of this behavior (I do not know if that the standard in New Zealand, but New Zealand's short date is set to d/MM/yyyy on my computer). I do not know if Dot Net, or the underlying Windows APIs are to blame, but it seems like it's smart enough to understand that the 4-digits part represents the year, and after that it just preserves the month-day order (Note that calling DateTime.TryParse("28-06-2012") will actually fail).
You can try using ParseExact, but be warned that will fail on a slightest change of the string (for example, when using a dot or a slash as a separator, instead of a dash.
In my opinion, it's probably best to leave the behavior as is, as it can handle more cases, but if you really must check if a date string was in a specified (yet flexible) format, Regex is the best option. For example Regex.IsMatch("2012/06/28", #"[0-9][0-9][0-9][0-9][./\\][0-9][0-9]?[./\\][0-9][0-9]?"); should suit your needs, while still allowing some flexibility.
You could try DateTime.ParseExact
Could you execute and post the result from the code below?
System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern;
System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.DateSeparator;

Check environments timezone settings

I want to be able to check against the environments timezone settings and if its not a US timezone then I will handle the datetime with a more global format. For example. I have a user in America their settings is MM-DD-YYYY now if I have another user in Canada they want to see DD-MM-YYYY but instead of just giving them different versions I would rather have some logic that grabs the timezone and compares it against something and then that determines how the datetime will be handled.
if(System.TimeZone.StandardTime = US)
{
objOrderEntryItemUsageReport.VarShipDate = Convert.ToDateTime(datpkrShipDate.Value).ToString("MM/DD/YYYY");
}
else
{
objOrderEntryItemUsageReport.VarShipDate = Convert.ToDateTime(datpkrShipDate.Value).ToString("DD/MM/YYYY");
I just don't know the best way to check the environments timezone settings and even how to compare it to see if its a US timezone?
Would I need to create a dictionary with the American timezones in it and then do a while loop through that dictionary to see if the current timezone matches and if not then handle it like an international user?
The user's time zone and the user's culture are entirely separate matters.
It's not clear where this code is running, but basically you want to use the appropriate CultureInfo, and then you can use DateTime.TryParse specifying the culture. You can use TryParseExact specifying a standard format of d for "short date format". (Likewise for calls to ToString... just pass in the culture and a format of d.)
Alternatively - and preferably - use a DateTimePicker so you don't need to parse the value at all. (Given your names, it's possible that you're already using a DateTimePicker, so it's unclear why you're calling Convert.ToDateTime - the Value property is already of type DateTime.
Then, don't convert it to a string later either - your VarShipDate property shouldn't be a string property, it should be a DateTime property. That's what you're trying to represent, after all. Avoid string conversions as far as you possibly can. They are error-prone, culturally sensitive, and basically full of potential fail.
Additionally, I would strongly advise against using System.TimeZone - use System.TimeZoneInfo, which is effectively the replacement for TimeZone.

Change datetime to different culture

I have a datetime in this format "Wednesday, December 04, 2013". I want to translate it to different cultures at runtime so that i am able to store that in database according to culture.
This is my code:
dysMngmt.Day = curntDate.ToString("D");
The one line code above is getting the day.
So,please help me.
You can use the second argument of the ToString function, which enables you to pick a culture you see fit:
curntDate.ToString("D", CultureInfo.GetCultureInfo("en-US"))
As a side note, why are you saving the date in your database as a string? Why not use a native date date type? It will take less space and allow you comparisons etc., and then you'd just use the currect culture when reading it out of the database.
Unless you have a very good reason for handling the culture of each date seperatly within the application you should set this at the application level so that the default ToString() works with your intended culture.
http://support.microsoft.com/kb/306162
Also, you should probably also not store dates as text in your database.

Categories