9

I'm reading a lot about timezone, offset, utc, local time, javascript functions, DST, bacon and I 'm trying to put this all together to build a solid/correct structure for my app.

Suppose my app is something like StackOverflow.

That is how I'm doing ...

  • The server is in another country, so I set it to UTC 00:00.
  • I'm storing date as DateTimeOffset.
  • I'm not storing TimeZoneID.
  • Date is being sent to the client in this format: 2012-07-19T14:30:00-03:00.
  • I'm using angular filter to convert it to local time.

I have a few questions about it ...

1º Server TimeZone?

About my server (single server) ... should it be running with a "neutral" UTC (+00:00)? And what if, in the future, we move to a farm where servers run on different locations?

2º What should I store?

Currently, I'm storing just date as DateTimeOffset. I'm reading about saving the TimeZoneID but I'm seeing no use at all for this. Am I missing something?

Or should I store date as DateTimeUtc with a TimeZoneID and manually convert every date with the TimeZone class?

3º How to convert to local time?

Is it safe to convert data on the client? Or date conversions should be always on the server side?

4º About DST.

Using my current approach. Will DST be respected?

Community
  • 1
  • 1
Felipe Miosso
  • 7,309
  • 6
  • 44
  • 55
  • What are you trying to store? Does the original time zone matter? (For example, would someone in a different time zone need to see the original time zone?) Why are you storing the culture? – Jon Skeet Dec 09 '13 at 13:37
  • No, it's not important. And the culture is being used just to date format. – Felipe Miosso Dec 09 '13 at 13:39
  • 1
    Shouldn't you be letting the client determine the date format though? If I (as a UK resident) see a date that a US user entered, I'd still want to see it in a UK format. – Jon Skeet Dec 09 '13 at 13:40
  • My english is not so good so I guess I wrote it in a bad way to understand. But, the culture is part of my session object and it's defined by the user. I'm going to remove it from the question since it's not really important. Sorry about that – Felipe Miosso Dec 09 '13 at 13:44
  • What's the bit about bacon?? – Matt Johnson-Pint Dec 09 '13 at 16:12
  • All these stuff are making me cry (think I overcomplicating things) and I know I'm not alone. So, since everybody love bacon, it is for everyone who are with me (cyring) ... – Felipe Miosso Dec 09 '13 at 16:27
  • Nice. :) Working on an answer for you. will have it posted shortly. :) – Matt Johnson-Pint Dec 09 '13 at 17:53

2 Answers2

10

One very important thing to understand about date/time is that there is no one right way for doing everything. The common answer "use UTC" is not always applicable. Context is very important, and there are different techniques and approaches based on what the values you are working with are representing. If you could elaborate on what they are used for in your application, I will update my answer accordingly. In the meantime, I'll try to address the specific points you have brought up already:

#1 - Server Time Zone

Keeping your server at UTC is a best practice, and it is what you can expect from cloud providers like Azure or AWS also. But it isn't something that you should be dependent on. Your server should be able to be set to any time zone without it affecting your application. As long as the clock is in sync with an NTP server, choice of time zone should not matter.

So how do you ensure that? Simple, just make sure your application avoids all of the following:

  • DateTime.Now
  • DateTimeKind.Local
  • TimeZone (the entire class)
  • TimeZoneInfo.Local
  • DateTime.ToLocalTime()
  • DateTime.ToUniversalTime() (because it assumes the input is local)
  • Misc. other methods that assume a local input or output, such as TimeZoneInfo.ConvertTimeToUtc(DateTime) (this particular overload doesn't take a time zone, so it assumes the local time zone)

See also my blog post: The Case Against DateTime.Now.

Note that I didn't include DateTimeOffset.Now in the list. Although it's a little bit of a design smell, it is still "safe" to use.

#2 - What to store

I suggest you read my answer to DateTime vs DateTimeOffset. It should clarify some things. Without regurgitating the whole thing, the main point is that while both represent a point in time accurately, a DateTimeOffset provides perspective, while a UTC DateTime does not.

You also asked when you should store a TimeZoneInfo.Id. There are at least two scenarios where this is required:

  • If you are recording events in the past or present, and you plan on allowing modifications to the recorded timestamps. You need the time zone to determine what the new offset should be, or how the new input converts back to UTC.

  • If you are scheduling time out into the future, you will need the time zone as part of the recurrence pattern (even for a single occurrence). See here and here also, (while for other languages, the same principles apply).

Again, the exact answer depends on what exactly the timestamps represent. There is no one ring to rule them all.

#3 - Client Safety

If it's a .NET client, sure you can convert there. But I think you are asking about a JavaScript client browser.

"Safe" is a relative term. If you're asking for exact perfectness, then no. JavaScript isn't safe for that, due to an error in the ECMAScript specification (ES1 through ES5.1. It is being worked on for ES6). You can read more in my blog post: JavaScript Date type is horribly broken.

However, if you are working with relatively current data, and the users of your application are not in a part of the world where time zones are volatile, or you don't require precise results 100% of the time, then you can "safely" use JavaScript to convert to the user's local time zone.

You might avoid some of these issues with libraries that implement the IANA TZDB in JavaScript, such as the ones I list here. But many of them are still dependent on JS Date, so they still have issues. (Side note - I'm working on a JS library that will counter this, but it is not ready to share yet).

Conversions on the server side are a much better choice, as long as you can ask the user for their time zone. Most of the time, I think this is doable.

You might consider asking using a map-based timezone picker, such as this one or this one. Both of which will require you use IANA time zones, which for .NET means using Noda Time, which is a great idea anyway (IMHO).

#4 - Daylight Saving Time

With your current approach, DST will be respected within the definition of the current DST rules for the time zone the user has set for their local browser. (Again, refer to my blog post for why this is the case).

A conversion from any value with an offset (whether -03:00 or Z) that passes through the Date object (which I believe an Angular filter will do), will properly convert to the specific unix timestamp.

The errors that would crop up with DST conversions for prior DST rules are because going from the unix timestamp inside the Date object to the local time zone will always assume that the current DST rule is applicable, even if the time fell into a period that had a different rule.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • you are awesome! The app will be something like Stackoverflow. – Felipe Miosso Dec 09 '13 at 18:35
  • So as long as the timestamps involved are "the time an event took place" (such as a posting time, comment time, etc.) then you can simply store a UTC `DateTime`. Time zone IDs aren't required since you aren't going to modify history, and offsets aren't harmful but aren't necessarily useful either. – Matt Johnson-Pint Dec 09 '13 at 18:39
  • Also note that S.O. avoids time zone conversions by using the "10 minutes ago" style of output, and only showing UTC values. Also, they base their daily cycle for points and other stuff on the UTC day, which has been disputed as possibly being unfair [on meta](http://meta.stackoverflow.com/) a few times, but that's what they've decided on. – Matt Johnson-Pint Dec 09 '13 at 18:42
  • 1
    One place I can think that might change your mind to use `DateTimeOffset` instead, would be if you want to generate statistical reports that show the most active times of day that people post. UTC day is one thing, but you might be interested in more relative local periods, like "morning", "midday", "evening", "nighttime". To do that, you need that "perspective" that `DateTimeOffset` can provide. – Matt Johnson-Pint Dec 09 '13 at 18:45
  • That is exactly what I was looking for. Thank you very much for that! You save me a few days of testing and searching! You sir, deserve all the bacon in the world. Thank you again!! – Felipe Miosso Dec 09 '13 at 18:48
4

This actually depends on the actual application you're writing, but the most simple/robust approach IMO is to store/compute all your dates using UTC, and convert it back to the local time zone when you display it to the user.

ken2k
  • 48,145
  • 10
  • 116
  • 176
  • It is safe to convert using javascript? – Felipe Miosso Dec 09 '13 at 13:40
  • @FelipeMiosso, what would be inherently unsafe about that operation? – Mike Perrenoud Dec 09 '13 at 13:42
  • @FelipeMiosso Not sure what you mean by 'safe', but if your application is a web application, you could convert your UTC dates to the local time zone using javascript. See http://stackoverflow.com/questions/6525538/convert-utc-date-time-to-local-date-time-using-javascript – ken2k Dec 09 '13 at 13:42
  • http://stackoverflow.com/questions/2532729/daylight-saving-time-and-time-zone-best-practices. Maybe I misunderstood that, but ... in the "don't" section. It's saying that it's not good to handle date on the client. – Felipe Miosso Dec 09 '13 at 13:49