简体   繁体   中英

The best way to save DateTime in string and the parse it back

The code below seems to be ok but it fails when it comes to save/parse Thai calendar, eg 08/31/2555 will fail and will be parsed as 31/8/3108. Why it so? If I specify "Thai Culture" then it will fail with US/EU time.

DateTime time = DateTime.Now.AddYears(-10);
String timeString = time.ToString("MM/dd/yyyy HH:mm:ss");

DateTime newTime = DateTime.ParseExact(timeString, "MM/dd/yyyy HH:mm:ss", CultureInfo.InvariantCulture));

Are you sure you get 3108 and not 3098?

Your string will be in the local calendar (the Thai calendar is 543 years ahead so is 2022 - 10 + 543 = 2555) - then you're reading that date in using the invariant culture (which uses the Gregorian calendar ).

2555 in the Gregorian calendar is then converted to the Thai calendar when it's being printed, and should result in a second conversion: 2555 + 543 = 3098.

Your code is equivalent to:

const string desiredFormat = "MM/dd/yyyy HH:mm:ss";
Thread.CurrentThread.CurrentCulture = new CultureInfo("th-TH");

// {31/8/2555 15:32:04} - original
var time = DateTime.Now.AddYears(-10);

// "08/31/2555 15:32:04" (Thai calendar string)
var timeStringLocal = time.ToString(desiredFormat);

// {31/8/3098 15:32:04} - incorrect
// 2555 is treated as a Gregorian date, then converted to 3098 in the Thai calendar when displayed
var newTimeFromLocal = DateTime.ParseExact(timeStringLocal, desiredFormat, CultureInfo.InvariantCulture);

What I'd instead suggest that you do is to have the string for parsing use the invariant (Gregorian) calendar instead, which will avoid any such issues.

const string desiredFormat = "MM/dd/yyyy HH:mm:ss";
Thread.CurrentThread.CurrentCulture = new CultureInfo("th-TH");

// {31/8/2555 15:32:04} - original
var time = DateTime.Now.AddYears(-10);

// "08/31/2012 15:32:04" - (invariant - Gregorian - calendar string)
var timeStringInvariant = time.ToString(desiredFormat, CultureInfo.InvariantCulture);

// {31/8/2555 15:32:04} - correct
var newTimeFromInvariant = DateTime.ParseExact(timeStringInvariant, desiredFormat, CultureInfo.InvariantCulture);

If you have full control over both saving and parsing, you could use a specific culture for both.

Eg using "en-US" culture:

CultureInfo DATETIME_CULTURE = CultureInfo.GetCultureInfo("en-US");
const string DATETIME_FORMAT = "yyyy/MM/dd_HH:mm:ss";

DateTime time = DateTime.Now.AddYears(-10);
string timeString = time.ToString(DATETIME_FORMAT, DATETIME_CULTURE);
DateTime newTime = DateTime.ParseExact(timeString, DATETIME_FORMAT, DATETIME_CULTURE, DateTimeStyles.None);

Now time should be identical to newTime .

Use a culture-invariant format O :

var th = new CultureInfo("th-TH");
var us = new CultureInfo("en-US");
var str = DateTime.Now.AddYears(-10).ToString("O");
Console.WriteLine(str);
var dt_th = DateTime.Parse(str, th);
var dt_us = DateTime.Parse(str, us);
Console.WriteLine(dt_th);
Console.WriteLine(dt_us);
Console.WriteLine(dt_th == dt_us);
2012-08-31T14:24:14.4710048+00:00
8/31/2012 2:24:14 PM
8/31/2012 2:24:14 PM
True

If you are saving the string in specific format, then while parsing you have to convert it into the same format first and then parse it to another format. You can refer this answer for help Read date using system locale and convert it to a new 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