views:

173

answers:

4

once again I have to create a date module, and once again i live the horror of perfecting it, is it me or are date and time the filthiest animals in programming profession, its the beast lurking behind the door that I wish I never have to deal with :(

does anyone know of a great source I can learn from that deals with dates in the following aspects:

  • user enters datetime and time zone
  • system translates to universal time and saves in data source
  • system retrieves universal time converted to local time chosen by developer (not by server or client location which may not be the right zone to display)
  • system should consider daylight time saving differences
  • cannot rely on "DateTime" parsing as it parses bohemiangly with respect to local server time
  • must give ability to developer to deal in both shapes: datetime and string objects

i looked at blogengine.net to see how they deal with but its too nieve, they save the time difference in hours in the settings datasource, it is absoluteley inaccurate... any sources to help?

i already went far in creating the necessary methods that use CultureInfo, TimeZoneInfo, DateTimeOffset ... yet when i put it to the test, it failed! appreciate the help

EDIT:

After squeezing some more, i narrowed it down to this:

public string PrettyDate(DateTime s, string format)
{
    // this one parses to local then returns according to timezone as a string
    s = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(s, "AUS Eastern Standard Time");
    CultureInfo Culture = CultureInfo.CreateSpecificCulture("en-au");
    return s.ToString(format , Culture);
}

problem is, I know the passed date is UTC time because im using

DateTimeOffset.Parse(s, _dtfi).UtcDateTime;
// where dtfi has "yyyy-MM-ddTHH:mmzzz" as its FullDateTimePattern

when i call the function on my datetime, like this:

AuDate.Instance.PrettyDate(el.EventDate,"yyyy-MM-dd HH:mm zzz");

on my machine i get:

2009-11-26 15:01 +11:00

on server I get:

2009-11-26 15:01 -08:00

I find this very peculiar! why is the timezone incorrect? everything else is in place! have i missed something?

+2  A: 

I feel your pain - which is why I'm part of the Noda Time project to bring a fully-featured date and time API to .NET. However, that's just getting off the ground. If you're still stuck in a year's time, hopefully Noda Time will be the answer :)

The normal .NET situation is better than it was now that we've got DateTimeOffset and TimeZoneInfo, but it's still somewhat lacking.

So long as you use TimeZoneInfo correctly twice, however, it should be fine. I'm not sure that DateTime parsing should be too bad - I think it should parse it as DateTimeKind.Unspecified unless you specify anything else in the data. You can then convert it to UTC using TimeZoneInfo.

Could you provide a short but complete program which shows the problems you're having?

Jon Skeet
Noda Time, good find! +1
o.k.w
+3  A: 

My comments for your pointers.

  • user enters datetime and time zone
    @ OK no issue

  • system translates to universal time and saves in data source
    @ OK no issue

  • system retrieves universal time converted to local time chosen by developer (not by server or client location which may not be the right zone to display)
    @ Is this s requirement? Why not just retrieve as universal time

  • system should consider daylight time saving differences
    @ Can be handled by DaylightTime Class, TimeZone Class etc

  • cannot rely on "DateTime" parsing as it parses bohemiangly with respect to local server time
    @ Then do not rely on DateTime Parsing

  • must give ability to developer to deal in both shapes: datetime and string objects
    @ DateTime Class as the basis should be good enough, use TimeZone / TimeZoneInfo / DaylightTime / DateTimeOffset etc to augment it

o.k.w
Basically exactly what I was trying to say, but you said it more succinctly and thus got it in a minute earlier... :-)
Daniel Pryden
@Daniel, guess I owe you a +1 then :)
o.k.w
response to #3: it is a requirement because we use a us-based server to server australian market :( is ia very nagging requirement#4: if i dont use datetime parsing, how do i retrieve the string representationg of datetime?
Ayyash
@Ayyash: I guess my comments are based on the context that it was for the developer to view and not for them to present to the user for dsiplay. For #4, my point is: until you manipulated to the actual datetime value and ready for use at the presentation layer, do not parse to string.
o.k.w
+2  A: 

Actually, I find the .NET date/time functionality to be quite nice. I'm puzzled by your troubles with it.

What exactly are you trying to do that DateTimeOffset and TimeZoneInfo can't do for you?

  • "User enters datetime and timezone" -- Check! Either DateTime or DateTimeOffset would work here.
  • "System translates to universal time and saves in data source" -- Check! Again, either DateTime or DateTimeOffset would work for you, although most database backends will need some special handling if you want to store timezone offsets. If you're already converting it to UTC, just store it as a datetime field in SQL Server or the equivalent in another RDBMS and don't worry about storing the fact that it's UTC.
  • "System retrieves universal time converted to local time chosen by the developer" -- Check! Just construct a TimeZoneInfo for your desired local time, and then call TimeZoneInfo.ConvertTime.
  • "System should consider daylight time saving differences" -- Check! That's what TimeZoneInfo.AdjustmentRule is for.
  • "Cannot rely on "DateTime" parsing as it parses bohemiangly with respect to local server time" -- ??? First off, "bohemiangly" isn't even a word. And you can customize how the datetime gets parsed with DateTime.ParseExact.
  • "Must give ability to developer to deal in both shapes: datetime and string objects" -- Why? What's wrong with just keeping one internal representation and then transforming only on input and output? I can't think of any operation on date/time values that would be made easier by doing it against a string.

In short, I think you're just griping about the complexities of handling date/time data in general.

Daniel Pryden
The date/time functionality in .NET is *sorely* lacking, mostly due to the lack of different types. It should be enough for this particular situation, but that doesn't mean it's anything like good enough. There's no type to represent a date without a time, or a time without a date, etc - you just have to use DateTime or TimeSpan *very carefully*. A better API will prevent you from accidentally doing the wrong thing, through strong typing. I'm staggered it took us until .NET 3.5 to get access to time zones other than the local one, for another example...
Jon Skeet
@Daniel, my anguish rises from the fact that i have to use a server with US time, to serve non US time, and my datasource is: XML FILES so i has to be string formats, and unfortunately i still cant "smoothly" turn a DateTime to a string without it transfering the date to the server US time, and there is one more problem: nullability, i couldnt null a date! and i couldnt check if its null :(
Ayyash
Ayyash: Nullability is easy - just use `Nullable<DateTimeOffset>` aka `DateTimeOffset?`
Jon Skeet
@Jon, thanks for the tip, i think it makes sense to switch my date into datetimeoffset all over if im going to travel between timezones like that
Ayyash
A: 

Thanks to Jon Skeet who put me on the right track, i never knew this before but now I know, DateTime object does not hold time zone information in it AT ALL! so whenever i use it i am already losing the datetime offset information, the DateTimeOffset object however, retains the time zone bit, so all my objects should use that, i really thought datetimeoffset object to be a bit limiting, i wanted to post a question about what is different between datetime and datetimeoffset, i should have done that!

now Im using the following code to retrieve the right zone:

string s = "2009-11-26T04:01:00.0000000Z";
DateTimeOffset d = DateTimeOffset.Parse(s);

TimeZoneInfo LocalTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
DateTimeOffset newdate = TimeZoneInfo.ConvertTime(d, LocalTimeZoneInfo);
return newdate.ToString("yyyy-MM-dd HH:mm zzz");

thank you all for your input

Ayyash