Quirk in the DateTime class

Jan 5, 2008

I experienced a strange behaviour with the DateTime class and formatting today. For some reason this error only occurs when you format a DateTime in certain cultures like Italian. The error is not present in English, Danish and most other cultures.

It happens when you use the DateTime.ToString and DateTime.ParseExact methods. When you write the following:

String date = DateTime.Now.ToString("yyyy-MM-dd HH:mm")

You would expect the date variable to be formatted like so 2008-01-05 11:30. In Italian it doesn’t. Instead it replaces the colon with a period which produces this 2008-01-05 11.30. This might be correctly formatted for the Italian culture, but I explicitly wrote I wanted the colon delimiter in the format string. However, there is a workaround.

All you need is to change the format string into a less obvious one. The following produces the right colon delimited date and time string:

String date = DateTime.Now.ToString("yyyy-MM-dd HH\\:mm")

Strangely enough, you have to escape the colon with two backslashes for it to work. This trick seems to work in all cultures.

* $4.95/month BlogEngine.net Hosting – Click Here!

Comments (13) -

Jakob Andersen
Jakob Andersen Denmark
1/5/2008 8:49:20 PM #

The escaping isn't so strange the first slash is to escape the second \ from the C# compilers string handling so this would also work:

string date = DateTime.Now.ToString(@"yyyy-MM-dd HH\:mm")

The reason for ":" needed to be escaped is that it is the way you specify a timeseparator in a DateTime format string, the same goes for "/" which is the date seperator in a formatstring. The time and dateseparators can be found on CultureInfo.DateTimeFormat.TimeSeperator and CultureInfo.DateTimeFormat.DateSeperator and they are different that ":" and "/" for many cultures which easily can be determined by looping over the specific cultures using the following code:

foreach(CultureInfo ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures)){
        if(ci.DateTimeFormat.TimeSeparator != ":"){
          Console.WriteLine("Time: " + ci.Name + " " + ci.DateTimeFormat.TimeSeparator);
        }
        if(ci.DateTimeFormat.DateSeparator != ":"){
          Console.WriteLine("Date: " + ci.Name + " " + ci.DateTimeFormat.DateSeparator);
        }
      }

Mads Kristensen
Mads Kristensen Denmark
1/5/2008 9:41:04 PM #

It is not correct that it will work with a single backslash. That's what makes it strange. It needs an escaped backslash.

Mads Kristensen
Mads Kristensen Denmark
1/5/2008 10:43:45 PM #

...also, I know that there are different delimiters for different cultures as you write, but the problem is that I requested a specific formatting and the DateTime class didn't deliver it. This should have nothing nothing to do with how cultures format date and time, since I explicitly requested a colon.

ck
ck United States
1/5/2008 11:24:27 PM #

If you read the documentation:
msdn2.microsoft.com/en-us/library/w2sa9yss.aspx

You see that the culture's settings are taken into account, which is why it removed the : for you.  Where as the strait tostring does not.

So it was doing what it was supposed to do.

The other issue (the need for a double escape) is just poor programming on somebody's part at Redmond.

Tommy Carlier
Tommy Carlier Belgium
1/6/2008 6:32:37 AM #

If you want culture-independent formatting, you could use the invariant culture, like this:
string date = DateTime.Now.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);

Jakob Andersen
Jakob Andersen Denmark
1/6/2008 10:48:12 AM #

Escaping with the single slash would work if you Add @ before the string as i wrote, the first escaping is for C# to understand that you have a backslash in you string.

Mads Kristensen
Mads Kristensen Denmark
1/6/2008 10:50:47 AM #

@Jakob
I know, but it still doesn't change the fact that the DateTime class didn't return the format I provided.

Jakob Andersen
Jakob Andersen Denmark
1/6/2008 10:56:27 AM #

The problem is you used ":" which is special in datatime format string, the same is "/" so i would argue it returned correctly. What you want is to format it using no culture specific settings and that is done using Tommy's suggestion.

Cristiano
Cristiano Italy
1/6/2008 12:08:08 PM #

I have linked the post near the Italian forum of BlogEngine.Net:
www.italianbloggers.it/forum/viewforum.php?f=19

Thanks a lot to all Wink

Nicolas Cadilhac
Nicolas Cadilhac Canada
1/8/2008 1:47:27 PM #

as other specified, this is not an error at all that your ':' character has been replaced. This is the way it is supposed to work. The ':' character is parsed and understood as "the time separator for the current culture" the same way as 'd' is understood as the day of the month. If you want explicitely a particular character you can put it inside single quotes, so your format string would be yyyy-MM-dd HH':'mm.

Krzysztof Koźmic
Krzysztof Koźmic Poland
1/18/2008 6:26:59 AM #

If you don't specify which culture should be used, the CultureInfo.CurrentCulture will be used to display the string, and basically, what Nicolas said happends. If you want to make sure that ALWAYS string will look the same you should use Tommy Carlier's solution: it's the most right and the most elegant. Your character escaping is more of a hack ;)

Krzysztof Koźmic
Krzysztof Koźmic Poland
1/18/2008 9:11:50 AM #

You may be interested in blog post I wrote regarding this issue: kozmic.pl/.../...-datetime.tostring-explained.aspx

Lucas
Lucas Puerto Rico
1/19/2008 12:58:35 AM #

the colon is considered a special code, same with "d", "m", etc. for example, if you wanted an actual "d" in the string output, you would have to escape them as "\d" (plus any escaping needed for the backslashes)

"yyyy-M-d" => "2008-1-18"
"yyyy-\M-\d" => "2008-M-d"

the colon is replaced with the culture's time separator the same way 'M' and 'd' are replaced.

Comments are closed

About the author

Mads Kristensen

Mads Kristensen
Program Manager at the Microsoft Web Platform team and founder of BlogEngine.NET.

More...

Month List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.