Storing date time in culture neutral format + C# - 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;
Bad habits to kick : choosing the wrong data type
If you want to get string representations of your DateTime values with specific format, you can always use DateTime.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"));
en-AU (English Austrailia): 24/11/2001
en-IA (English India): 24-11-2001
en-ZA (English South Africa): 2001/11/24
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 (e.g. "en")
3) culture specific (e.g "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
}

Related

Convert english Date with parse exact

I try to convert a english date to an german, but my format is not good.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
DateTime currentCultureDate = DateTime.Now;
string format = "dd.MM.yyyy HH:mm:ss";
Console.WriteLine("Format: " + format);
Console.WriteLine("Original Date: " + currentCultureDate);
DateTime convertedDate = DateTime.ParseExact(currentCultureDate.ToString(), format, new CultureInfo("de-DE"));
Console.WriteLine("Converted Date: " + convertedDate);
FormatException.....
DateTime.ParseExact is used to create a DateTime from a string. You can pass a DateTimeFormat or CultureInfo which will be used to convert that string to DateTime.
The method does not convert it to a string in another CultureInfo, say de-DE. Therefore you can use DateTime.ToString:
string germanFormat = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss", new CultureInfo("de-DE"));
You are not doing what you say: Your code actually tries to parse the date in German format:
// This is German format
string format = "dd.MM.yyyy HH:mm:ss";
// This takes a date and parses it using the ABOVE FORMAT - which is German
DateTime convertedDate = DateTime.ParseExact(currentCultureDate.ToString(), format, new CultureInfo("de-DE"));
If you already have a DateTime you want to output in German format, you don't need ParseExact, but ToString:
string german = DateTime.Now.ToString(format, new CultureInfo("de-DE"));
A DateTime itself doesn't have any culture formatting attached. It is just a date and a time. Only when you output a DateTime, it somehow needs to be converted into a string and to do so, culture information is required. So the rule of thumb is:
If you get a string that represents a date and time value, you need to parse it into a DateTime, either using a fixed format and ParseExact or relying on the framework, passing the source culture information to Parse or TryParse.
If you have a DateTime and want to output it, you need to format it using ToString, providing either a fixed format string and culture information, or use ToString only for the current thread's culture.

Convert(change) current DateTime as per culture in c#

if (!IsPostBack && !Page.IsCallback)
{
double OffsetHrs = GetTimeZoneOffsetFromCookie();
string dateFormat = ServiceManager.LocalizationService.GetString("AppHeaderTop", "DateFormat", "g");
CultureSelected CultureSelected = GetCultureSelected();
ASPxLabelCurrentTime.Text = DateTime.Now.ToUniversalTime().AddHours(-OffsetHrs).ToString(dateFormat);
if (CultureSelected.CultureCode != "en-US")
{
DateTimeFormatInfo usDtfi = new CultureInfo("en-US", false).DateTimeFormat;
DateTimeFormatInfo currentDtfi = new CultureInfo(CultureSelected.CultureCode, false).DateTimeFormat;
ASPxLabelCurrentTime.Text = Convert.ToDateTime(ASPxLabelCurrentTime.Text, usDtfi).ToString(currentDtfi.ShortDatePattern); //what can i Use here ?
}
Let say Output of ASPxLabelCurrentTime.Text
for en-US culture is 11/2/2015 4:14 PM (70)
If I select specific culture I want this datetime 11/2/2015 4:14 PM (70) to appear in that specific culture format.
Your question seems unclear but I try to give a shot.
First of all, what is this (70) exactly? Where is this came from? en-US culture can't parse this string without using it in a string literal delimiter with ParseExact or TryParseExact methods. On the other hand, since you assing ASPxLabelCurrentTime.Text the result of the DateTime.Now.ToUniversalTime().AddHours(-OffsetHrs).ToString(dateFormat) code, I don't believe this (70) part is really an issue on this question.
Second, If I understand clearly, the problem seems the usage of DateTime.ToString(string) method.
ASPxLabelCurrentTime.Text = Convert.ToDateTime(ASPxLabelCurrentTime.Text, usDtfi)
.ToString(currentDtfi.ShortDatePattern);
// ^^^ Problem seems here
Okey let's say you successfully parse this ASPxLabelCurrentTime.Text with usDtfi culture (which is en-US), but with this .ToString(string) method, you are not using currentDtfi settings actually, you are using CurrentCulture settings when you generate formatted string representation of your DateTime.
From DateTime.ToString(String) doc;
Converts the value of the current DateTime object to its equivalent
string representation using the specified format and the formatting
conventions of the current culture.
Since we don't know what GetCultureSelected method returns exactly, it may or may not be the same culture with currentDtfi.
I strongly suspect, you can solve this problem to using that culture as a second parameter in ToString method as;
ASPxLabelCurrentTime.Text = Convert.ToDateTime(ASPxLabelCurrentTime.Text, usDtfi)
.ToString(currentDtfi.ShortDatePattern, currentDtfi);
IF this (70) is really part of on your string, you need to ParseExact or TryParseExact methods to supply exact format of it.
string s = "11/2/2015 4:14 PM (70)";
DateTime dt;
if(DateTime.TryParseExact(s, "MM/d/yyyy h:mm tt '(70)'", CultureInfo.GetCultureInfo("en-US"),
DateTimeStyles.None, out dt))
{
ASPxLabelCurrentTime.Text = dt.ToString(currentDtfi.ShortDatePattern, currentDtfi);
}

DateTime.TryParseExact only working in "One Way"

Scope:
I have been trying to develop a super-tolerant DateTime.Parse routine, so I decided to give most "widely-used" formats a try to better understand the format masks.
Problem:
I have defined a specific format (String) which I use as myDate.ToString(format), and it works wonders. The problem is, If I get this same String (result of the .ToString(format) operation), and feed it back to DateTime.TryParseExact (...) it fails.
Code / Test:
System.Globalization.CultureInfo provider = System.Globalization.CultureInfo.InvariantCulture;
// Defining Format and Testing it via "DateTime.ToString(format)"
string format = "MM/dd/yyyy HH:mm:ss tt";
string dtNow = DateTime.Now.ToString (format);
Console.WriteLine (dtNow);
// Trying to Parse DateTime on the same Format defined Above
DateTime time;
if (DateTime.TryParseExact (dtNow, format, provider, System.Globalization.DateTimeStyles.None, out time))
{
// If TryParseExact Worked
Console.WriteLine ("Result: " + time.ToString ());
}
else
{
// If TryParseExact Failed
Console.WriteLine ("Failed to Parse Date");
}
Output is : "Failed to Parse Date".
Question:
Why can I use the format string to format a certain date as text, but I can't use the same format to feed the string back to a date object ?
EDIT:
I have added part of my method to this example, and I would like to know why the "ParseDate" method fails to return a proper date, given that the "String" is in the right format.
Since you use DateTime.ToString() method without any IFormatProvider, this method will use your CurrentCulture settings.
That's why your
string dtNow = DateTime.Now.ToString (format);
line might generate a different string representation than MM/dd/yyyy HH:mm:ss tt format.
Three things can cause this issue;
Your CurrentCulture has a different DateSeparator than /
Your CurrentCulture has a different TimeSeparator than :
Your CurrentCulture has a different or empty string as a AMDesignator and/or PMDesignator
Since you try to parse your string with provider (which is InvariantCulture) on your DateTime.TryParseExact method, generate your string based on that provider as well.
string dtNow = DateTime.Now.ToString(format, provider);
You told your CurrentCulture is pt-BR and this culture has empty string "" as a AMDesignator and PMDesignator. That's why your dtNow string will not have any AM or PM designator on it's representation part.
Here a demonstration.

convert DateTime to string according to customCultureInfo in G((combination of date and Time) format

I have changed my system date format to Faeroese.
I want to convert DateTime to String according to customCulture with G format (combination of date and Time)
check the below code.
namespace TestDateConvertion
{
class Program
{
static void Main(string[] args)
{
object value = new DateTime(2003,12,23,6,22,30);
DateTime dateTimeValue = (DateTime)value;
CultureInfo customCulture = MySettings.getCustomCulture();
//for getting custom culture in my app
//in custom culture i have changed shortDateFormat according to the user preference.
//value in shortDateFormat = dd/MM/yyyy
string result = string.Format(customCulture, "{0:G}", result);
Console.WriteLine(result);
Console.ReadLine();
}
}
}
but i get the output with sepertators according to system DateTime not with users given format in customCulture,
i even dont find any method overloaded in string.Format() or DateTime.ToString() to do this.
If i pass CultureInfo.InvariantCulture then i cant get output in G format.
try this:
DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);
Console.WriteLine(date1.ToString("G", DateTimeFormatInfo.InvariantInfo));
// Displays 04/10/2008 06:30:00
Console.WriteLine(date1.ToString("G", CultureInfo.CreateSpecificCulture("en-us")));
// Displays 4/10/2008 6:30:00 AM
Console.WriteLine(date1.ToString("G", CultureInfo.CreateSpecificCulture("nl-BE")));
According to Standard Date and Time Format Strings "G" uses short date format (as you claim to specify). So most likely reason of using local culture separator is covered in The "/" Custom Format Specifier portion of ""Custom Date and Time Format Strings".
Since your "short date format" is "dd/MM/yyyy" than instead of "/" it will use corresponding separator from the culture info (which you are likely picking from default culture).
Escaping with \ is covered in the Using the escape character portion of the same "Custom Date and Time Format Strings" article.
So you want your shortDateFormat = #"dd\/MM\/yyyy" or properly specify DateTimeSeparator in corresponding part of your custom CultureInfo.

How to Convert a Date String with Format "dd/MM/yyyy" to OS Current Culture Date Format

A string has the value in "dd/MM/yyyy" format like "04/10/2012". This should be converted to a Date w.r.t Current Culture of OS.
I have tried below string with Korean as Current Culture of OS in which date format is yyyy-MM-dd, my code is not getting correct Month value, it interchange the month value with day:
Input: "04/10/2012"
Output: 2012-04-10
Code:
DateTime DT;
string dt = "04/10/2012";
DateTimeFormatInfo DateInfo = CultureInfo.CurrentCulture.DateTimeFormat;
DT = Convert.ToDateTime(String.Format ("{0:"+DateInfo .ShortDatePattern +"}", dt.Trim ()), CultureInfo .CurrentCulture);
MessageBox.Show("Date: " + DT.ToShortDateString());
How I can fix that ?
It looks to me like you need to parse it with a fixed format, I think you are currently parsing it with a format other than "dd/MM/yyyy" and because the date is ambiguous (as in, month and day can be interchanged without causing invalid dates) the format is simply switching the month and day value. When you then go to output it, it looks reversed.
Use DateTime.ParseExact to force the parsing format and then use the built-in current culture sensitive string output methods on DateTime to get a formatted string:
var date = DateTime.ParseExact("04/10/2012", "dd/MM/yyyy", CultureInfo.InvariantCulture);
MessageBox.Show("Date: " + date.ToShortDateString()); // Assumes current culture is controlling format
Since your input string is in a fixed format, you should parse it in that format:
DateTime.ParseExact(dt, "dd/MM/yyyy", CultureInfo.InvariantCulture);
If you string has the format dd/MM/yyyy then you have to use DateTime.ParseExact with the specified format:
DateTime.ParseExact(dt, "dd/MM/yyyy", CultureInfo.InvariantCulture);
Anything else will try an interpret the string according to the current culture's rules - which, as you have found, will fail.
why not use ToShortDateTimeString()

Categories

Resources