Discussion: Formalizing approach to storing date and time values
See original GitHub issueCurrent Situation
AllReady stores campaign/event/task dates as the .NET DateTimeOffset type
- DateTimeOffset is a .NET Framework type that represents a particular point in time relative to UTC. It is a Date and Time with an Offset relative to UTC. (https://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx)
- Each Campaign has a Windows/.NET TimeZoneID specifying the timezone where the campaign is located. For example, a campaign in Seattle would have the TimeZoneID = “Pacific Standard Time”
- An Event within a campaign also has a TimeZoneID specifying the timezone where the event is located. The default TimeZoneID is the same as the campaign but can differ when events are located across the country.
- All Tasks for an event inherit the TimeZoneID from the event.
- A Campaign / Event / Task start and end date / time is stored as a DateTimeOffset with the offset set to the UTC offset according to the TimeZoneID of the campaign.
- For example, consider the following campaign located in Seattle
Event | Start Date Time with Offset | End Date Time with Offset |
---|---|---|
Event 1 | 10/23/2016 5:00 PM -7:00 | 10/23/2016 8:00 PM -7:00 |
Event 2 | 12/20/2016 5:00 PM -8:00 | 12/20/2016 8:00 PM -8:00 |
- Note the offset is different depending of whether or not the date and time falls during daylight savings time for the Seattle area. AllReady calculates this offset whenever date/time values are saved by calling TimeZoneInfo.GetUtcOffset for date/time that was specified by the user.
- //TODO: Add example here of how and why the offset if adjusted when values are saved
Potential Risks Thank you to Jon Skeet for pointing out the following potential problems
- Since the offset for a particular DateTimeOffset is calculated and stored when a user creates (or modifies) a Campaign / Event / Task, there is the potential that changes to time zone rules could cause problems. As an example, if an event were scheduled several months in advance and changes to the daylight savings time rules for that timezone changed after the event was created, the offset for that event might not be stored correctly.
- AllReady uses Windows timezones which are updated via regular Windows Updates. These updates happen regularly but updates are typically not as timely as the IANA timezone database which is used by the Noda Time framework
- Both these issues could be resolved if we used the Noda time framework, stored values as local date time values and did time zone conversions on every read. // TODO: Add example if we decide this is the path forward
- Noda Time framework currently does not support .NET Core. Version 2.0 of Noda Time does support .NET core but it is currently in Alpha. It is considered stable but we should expect some API changes.
Display Campaign / Event / Task date time values
- The default behavior in AllReady is to display Campaign / Event / Task dates in the timezone where the campaign is located. Since the values are stored as a
DateTimeOffset
, this means we simply display the value using.ToString()
. No additional timezone adjustments are necessary. - To avoid confusing, we display the TimeZone after any date/time values as shown here:
- Optionally, a user can specify their local TimeZone in their user profile. If a user has specified their local timezone, we also display the Campaign / Event / Task datetimes in their local timezone as shown here:
- TODO: // Add example code showing how this conversion happens
Date Time formats
- AllReady currenlty only supports the en-US culture, meaning that DateTime values are always displayed in MM/dd/yyyy format. This includes the input fields where users enter DateTime values. From Startup.cs
// Configure the HTTP request pipeline.
var usCultureInfo = new CultureInfo("en-US");
app.UseRequestLocalization(new RequestLocalizationOptions
{
SupportedCultures = new List<CultureInfo>(new[] { usCultureInfo }),
SupportedUICultures = new List<CultureInfo>(new[] { usCultureInfo })
});
- This can be extended in the future by adding more supported cultures at startup. The challenge here however is in aligning ASP.NET’s request culture (and associated DateTime format) with the momentjs DateTime format used by the eonasdan-bootstrap-datetimepicker UI component for datetime input fields.
- Currently, the datetimepicker is setup to display in the ‘L’ format for Dates and ‘L LT’ formats for DateTime. Since we don’t include any additional momentjs locales, this forces the DateTime pictures to use the MM/dd/yyyy format.
$(".datepicker").datetimepicker({
format: 'L',
showClose: false,
toolbarPlacement: 'bottom'
});
$(".datetimepicker").datetimepicker({
format: 'L LT',
showClose: false,
sideBySide: true,
toolbarPlacement: 'bottom'
});
- ASP.NET Core request culture: https://docs.asp.net/en/latest/fundamentals/localization.html
- momentjs locales http://momentjs.com/docs/#/i18n/
- Datetimepicker control https://eonasdan.github.io/bootstrap-datetimepicker/#bootstrap-3-datepicker-v4-docs
Issue Analytics
- State:
- Created 7 years ago
- Comments:13 (4 by maintainers)
Top Results From Across the Web
database design - Preferred way to store DateTime
A common way of storing date/time data, employed "behind the scenes" by many products, is by converting it into a decimal value where...
Read more >sql - Efficient way of storing date ranges
It is the best method if you have a lot of product codes in the Products table and few validity ranges for each...
Read more >Date and Time Formats
Abstract. This document defines a profile of ISO 8601, the International Standard for the representation of dates and times. ISO 8601 describes ...
Read more >Database: Should We Store Datetime or Timestamp?
Datetime and timestamp are both used to store date and time information ... date and time values in UTC format is usually the...
Read more >Working With Dates & Times in Your Application
Learn how to work with dates and times when developing applications, including addressing bugs, accounting for time zones and more.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Looks good @dpaquette. What’s really handy is that what you’ve done regarding binding pretty much matches what I’ve job for a work requirement I had and have started writing up for my blog. So at least my approach looks good for that too!
See PR #1416 for current WIP related to this issue. I am proposing a approach that uses a custom model binder to do the adjustment for the Campaign or Event’s timezone. This pulls the logic out of the controllers / command handlers and ensures the date time offsets are set correctly BEFORE they ever reach the controller.
I will be adding some documentation and unit tests later this week but wanted to share what I had working so far.