2

I'm looking for best practices regarding dates - where it's the date itself that's important rather than a particular time on that day.

An excellent start was this question: Daylight saving time and time zone best practices

I'd like some guidance applying this for my situation. I have medications starting on a particular date, and ending on another. I then need to query medications which are active in a given date range.

I've tried setting start and end dates as midnight local time, then storing in UTC on the database. I could add timezone entries too.

I'm using moment.js on both client and server, and can use moment timezone if needed.

I'm wondering how to deal with the effect of DST on my times - which makes an hour difference in my locally-midnight UTC times between DST and non DST periods.

The problem I have is for example when some medications have end dates set during a DST period, and some which were set in a non-DST period. Then, their UTC times differ by an hour. When a query is made for a particular date range starting at local midnight, it's not accurate as there are two different representations of midnight. The query itself may treat midnight as one of two different times, depending on when in the year the query is made.

The end result is that a medication may appear to end a day later than it should, or start a day earlier.

A simple but wonky workaround would be to consistently set the start date as 1am in standard (non DST) time, and end dates as 11:59pm standard (non DST) time, and query at midnight.

Or, should I check the start and end dates of each query, and work out what the UTC offset would be for each date?

But I'd much prefer to know what best practice is in this situation. Thanks.

Community
  • 1
  • 1
Nick McIntosh
  • 191
  • 1
  • 5
  • 1
    If you're supposed to take medication every _x_ hours, surely you don't want to do it an hour early or wait an extra hour between doses? – Paul S. Nov 24 '14 at 21:32
  • The timing of medication doses is handled separately. I just need to know for which which days to activate those doses. – Nick McIntosh Nov 24 '14 at 21:54

1 Answers1

1

Both the JavaScript Date object and the moment object in moment.js are for representing a specific instant in time. In other words, a date and a time. They internally track time by counting the number of milliseconds that have elapsed since the Unix Epoch (Midnight, Jan 1st 1970 UTC) - ignoring leap seconds.

That means, fundamentally, they are not the best way to work with whole calendar dates. When you have only a date, and you use a date+time value to track it, then you are arbitrarily assigning a time of day to represent the entire day. Usually, this is midnight - but as you pointed out, that leads to problems with daylight saving time.

Consider that in some parts of the world (such as Brazil) the transition occurs right at midnight - that is, in the spring, the clocks jump from 11:59:59 to 01:00:00. If you specify midnight on that date, the browser will either jump forward or jump backward (depending on which browser you are using)!

And if you convert a local date-at-midnight to a different time zone (such as UTC), you could change the date itself! If you must use a date+time to store a date-only value, use noon instead of midnight. This will mitigate most (but not all) of the adjustment issues.

The better idea is to treat whole dates as whole dates. Don't assign them a time, and don't try to adjust them to UTC. Don't use a Date or a moment. Instead, store them either as an ISO-8601 formatted string like "2014-11-25", or if you need to do math on them, consider storing them as an integer number of whole days since some starting value. For example, using the same Jan 1st 1970 epoch date, we can represent November 11th 2014 as 16399 with the following JavaScript:

function dateToValue(year, month, day) {
    return Date.UTC(year, month-1, day) / 86400000;
}

function valueToDate(value) {
    var d = new Date(86400000 * value);
    return { year : d.getUTCFullYear(), 
             month : d.getUTCMonth() + 1,
             day : d.getUTCDate()
           };
}

There are a few other things to keep in mind when working with whole dates:

  • When working with ranges of whole dates, humans tend to use fully-inclusive intervals. For example, Jan 1st to Jan 2nd would be two days. This is different from date+time (and time-only) ranges, in which humans tend to use half-open intervals. For example, 1:00 to 2:00 would be one hour.

  • Due to time zones, everyone's concept of "today" is different around the globe. We usually define "today" by our own local time zone. So normally:

    var d = new Date();
    var today = { year : d.getFullYear(), 
                  month : d.getMonth() + 1,
                  day : d.getDate()
                };
    
    • You usually don't want to shift this to UTC or another time zone, unless your business operates globally under that time zone. This is rare, but it does occur. (Example, StackOverflow uses UTC days for its calculations of badges and other achievements.)

I hope this gets you started. You asked a fairly broad question, so I tried to answer in way that would address the primary concerns. If you have something more specific, please update your question and I'll try to respond.

If you would like even more information on this subject, I encourage you to watch my Pluralsight course, Date and Time Fundamentals.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575