简体   繁体   中英

Storing date time in culture neutral format + C#

I accept date info from the user, via date picker. I need to store them in a culture neutral way. The problem I am facing is, if I store the date as per en-US format (based on calendar settings), namely 11/20/1990 it will fail to parse when the culture is en-GB.

And vice versa happens when culture is en-US, date stored as per UK format, dd/mm/yyyy refuses to parse. How do I store date info in a culture neutral way in a file so that, I get the date to work in both locations?

DateTime.TryParse(userEnteredValue, out result);
result.ToShortDateString(); //this is what I am doing 

tried this code for invariant culture

string input = "20/10/1983";
DateTime userInput;

bool result = DateTime.TryParse(input, out userInput);

string invariantCulture = userInput.Date.ToString(CultureInfo.InvariantCulture);

DateTime storedValue;

result = DateTime.TryParse(invariantCulture, out storedValue);

tried this code with en-GB calendar settings, second statement DateTime.TryParse fails infact.

@Soner Gönül's answer is spot on if you are saving the dates to a database. However, you mention that you are looking to round-trip a DateTime to and from a file .

As the file is presumably a text file you'll need to write the DateTime in a culture neutral manner. You can do this by using the "O" format specified on the DateTime.ToString method. This will output a string representation that complies with ISO 8601. The resultant string can be parsed using DateTime.Parse without the need for culture information.

As an example:

string filename = @"c:\temp\test.txt";
string usDateString = "11/18/2014 12:32"; // MM/dd/yyyy
string ukDateString = "18/11/2014 12:33"; // dd/MM/yyyy

//I'm mimicking you getting the DateTime from the user here    
//I'm assuming when you receive the date(s) from the front
//end you'll know the culture - if not then all bets are off. 
DateTime usDate = 
      DateTime.Parse(usDateString, CultureInfo.GetCultureInfo("en-US"));
DateTime ukDate = 
      DateTime.Parse(ukDateString, CultureInfo.GetCultureInfo("en-GB"));

//write the dates to a file using the "o" specifier
File.AppendAllText(filename, usDate.ToString("o") + Environment.NewLine);
File.AppendAllText(filename, ukDate.ToString("o") + Environment.NewLine);

//read them back in as strings
string[] contents = File.ReadAllLines(filename);
        
foreach (var date in contents)
{
    //prove we can parse them as dates.
    Console.WriteLine(DateTime.Parse(date).ToString());
}

This creates a file with the contents:

2014-11-18T12:32:00.0000000

2014-11-18T12:33:00.0000000

and on my system (in the UK) it prints:

18/11/2014 12:32:00

18/11/2014 12:33:00

if I store the date as per en-US format...

Please stop! Looks like you try to save your DateTime values with their string representations.

A DateTime doesn't have any implicit format. It has just date and time values. String representations of them can have a format. Generate your insert queries and pass your DateTime values directly with parameterized way .

Please read;

If you want to get string representations of your DateTime values with specific format, you can always useDateTime.ToString() method and it's overloads.

Your en-GB culture can parse MM.dd.yyyy (since you use / format specifier which replaces itself supplied culture DateSeparator ) and en-US culture can parse MM/dd/yyyy as well.

But since you use .ToShortDateString() method, this represents your datetime based your CurrentCulture settings. As a solution, you can set this property which culture you want and ToShortDateString works based on it.


 result = DateTime.TryParse(invariantCulture, out storedValue);

tried this code with en-UK calendar settings, second statement DateTime.TryParse fails infact.

Because this DateTime.TryParse uses your CurrentCulture and since your invariantCulture variable is 10/20/1983 00:00:00 , that means this is not a standard date and time format for your CurrentCulture .

There is no such a culture as en-UK by the way.


10/20/1983 00:00:00 is MM/dd/yyyy HH:mm:ss format. But en-GB culture doesn't have this format as a standard date and time format, that's why your method returns false .

As an alternative, you can use custom format strings like;

string s = "10/20/1983 00:00:00";
string format = "MM/dd/yyyy HH:mm:ss";
DateTime dt;
if (DateTime.TryParseExact(s, format, CultureInfo.GetCultureInfo("en-GB"),
                           DateTimeStyles.None, out dt))
{
    Console.WriteLine(dt);
}

I bumped into this question and figured I'd bring in some other way nobody has mentioned yet:

DateTime.ToBinary() for serializing and DateTime.FromBinary(Int64) for deserialization.

What these do is the following: ToBinary() returns a long which can be easily stored in a culture invariant way. FromBinary(Int64) will return a DateTime object from the long parameter supplied. (They even take the date time Kind property into consideration).

And here's some code to go with it:

DateTime d1l = DateTime.Now;
long dl = d1l.ToBinary();
DateTime d2l = DateTime.FromBinary(dl);

DateTime d1u = DateTime.UtcNow;
long du = d1u.ToBinary();
DateTime d2u = DateTime.FromBinary(du);

Console.WriteLine("Local test passed: " + (d1l == d2l).ToString());
Console.WriteLine("d2l kind: " + d2l.Kind.ToString());
Console.WriteLine("Utc test passed: " + (d1u == d2u).ToString());
Console.WriteLine("d2u kind: " + d2u.Kind.ToString());

And the console output:

Local test passed: True
d2l kind: Local
Utc test passed: True
d2u kind: Utc

I find this to be pretty neat!

String s = "24. 11. 2001";
d = DateTime.Parse(s, CultureInfo.CreateSpecificCulture("sk-SK"));
  1. en-AU (English Austrailia): 24/11/2001
  2. en-IA (English India): 24-11-2001
  3. en-ZA (English South Africa): 2001/11/24
  4. en-US (English United States): 11/24/2001

i suspect you prefer English (India) (en-IA).

But if you really can't decide what culture to use when converting dates to strings and vice-versa, and the dates are never meant to be shown to a user, then you can use the Invariant Culture:

String s = "11/24/2001" //invariant culture formatted date

d = DateTime.Parse(s, CultureInfo.InvariantCulture); //parse invariant culture date

s = d.ToString(CultureInfo.InvariantCulture); //convert to invariant culture string

I tried to figure out a solution via this approach, please let me know if its correct.

The code which I use is below.

For Saving date time I use ticks as below.

DateTime userInput;

bool result = DateTime.TryParse(this.dpSave.Text, out userInput);

if (result)
{
   long ticks = userInput.Ticks;

   System.IO.File.WriteAllText(@"D:\folder\Ticks.txt", ticks.ToString());
 }
 else
 {
   MessageBox.Show("Date time parse failed");
 }

For loading it back, I use

if (System.IO.File.Exists(@"D:\folder\Ticks.txt"))
{
   string contents = System.IO.File.ReadAllText(@"D:\Sandeep\Ticks.txt");

   long ticks;

   if (long.TryParse(contents, out ticks))
   {
     DateTime storedDateTime = new DateTime(ticks);
     MessageBox.Show("Stored Date" + storedDateTime.ToShortDateString());
   }
   else
   {
     MessageBox.Show("Unable to obtain stored dates");
   }
}

this seems to work, provided, I save using en-US culture and load using en-GB culture.

please let me know if this is the right approach!

a) Exchange data shall always be stored culture invariant (xml etc)

b)You've gotta to be careful with the terminology. What you exactly mean is culture INVARIANT (and not 'culture neutral'). There are three types of cultures: 1) invariant 2) culture neutral (eg "en") 3) culture specific (eg "en-US")

public DateTime getdate3()
{

    CultureInfo Invc = CultureInfo.InvariantCulture;    //culture
    string cul = Thread.CurrentThread.CurrentCulture.Name;

    CultureInfo us = new CultureInfo(cul);
    string shortUsDateFormatString = us.DateTimeFormat.ShortDatePattern;//pattern


    DateTime dt = Convert.ToDateTime(DateTime.Now);

    TimeZoneInfo myZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time"); //india zone
    DateTime dateindia = TimeZoneInfo.ConvertTime(dt, myZone);

    string dt1 = Convert.ToDateTime(dateindia).ToString(shortUsDateFormatString); //string format

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM