Background

Buzz Aldrin on the moon. Source: NASA
Over and over throughout the years as a developer and software architect, I have come across systems having issues when trying to deal with the concept of time. Time after time the issues of representing time and dates as data in the database and code, creates issues, bugs, misunderstandings etc.
But why does this happen, and how can we avoid it?
Common Issues
Say you are representing an interval of dates, say Jun 1 to Jun 30. At which time does this interval really end?
- Jun 30 12:00 AM?
- Jun 30 11:59 PM?
- Jun 30 11:59:59 PM?
- Jun 30 11.59:59.999?
- Jul 1 at 12:00 AM?
This is a really a good question, and the answer may seem simple for some. But then. Perhaps the system was built by someone who did not see this as simple, or perhaps did, but didn’t realize they were “wrong”. Then you are in for trouble trying to develop that system not realizing what definition has been used.
The problems may show up as the wrong date being presented to the user, say for the validity of a parking permit.
Now add to this a system which may both be used in different time zones, and hosted on servers in different time zones, plus daylight savings. Now a reported date may be off by two days in worst case.
This can cause all types of problems, like a driver getting a parking fine for his car, even though the permit is valid. Wrong calculations for how much to charge on something based on usage by time. etc etc.
Difference Between Date and Point in Time
Point in time
A point in time, moment, instant (or just time), is just that, a point. It has no duration, it is not open for interpretation when it occurred.
Let’s say the moment the first man set foot on the moon. That moment was July 21 1969 at 02:56:15 UTC.
Your clock may have shown something. Other clocks around the world may have shown totally different numbers, but it does not matter. Wherever in the world you observed it from, the moment the first man set foot on the moon was one and the same moment no matter your location, timezone, daylight savings, or even calendar system.
It was simply a point in time.
A point in time is the way to tell when something happened, and there are many systems of doing that.
Date
A date is (simplified) by definition an interval between two points in time, adjusted for your time zone. Where I live, in Sweden, the date of July 21 1969 was the time between the two points in time expressed in UTC time and ISO 8601 format as 1969-07-20 23:00 to 1969-07-21 23:00.
(That’s right, the date of 1969-07-21 here in Sweden spanned the two dates of 1969-07-20 and 1969-07-21 expressed in UTC. And we did not have daylight savings back then either. See how things about dates and time may introduce bugs in your systems?)
The point here is that a Date is really an interval in time between two points in time, different intervals at that depending on your time zone.
So Date and point in time cannot really be compared. Just like a dot along a line cannot be compared with a line between two dots.
Where does that bring us when creating software systems for business and people to rely on. When there is no such thing as a Date concept in .Net (and other frameworks, like javascript)? More on that later.
Difference Between Interval of Dates and Interval of Time
Consider the following two date intervals
- June 1 – June 30
- July 1 – July 31
As we think of them as humans, those two intervals do not overlap, and there is no gap between them, even though the end date of the first is different than the start date of the next.
Consider the following two time intervals:
- 10:00 – 12:00
- 12:00 – 14:00
Think about them as schedule. As we think of them, those two intervals do not overlap, and there is no gap between them, even though the end time of the first is equal to the start time of the next.
Do you see the difference here? Both examples show intervals with no gap, and no overlap, yet the date intervals do not share the same end/start, but the time intervals do. Isn’t that a paradox?
Different Definitions of Interval
Mathematically, the perceived paradox is caused by that date intervals and time intervals are defined differently.
A time-interval, as we think of it, is defined as
starttime <= time < endtime
or using mathematical notation:
time ∈ [starttime , endtime)
Similarly, a date-interval, as we think of it, is defined as
startdate <= date <= enddate
or using mathematical notation:
date ∈ [startdate, enddate ]
Expressed this way, the difference can be made quite clear; a date really is the interval of time between 12 am of the given date until 12 am of the following date = [midnightdate, midnightdate+1)
Expressed this way, the date interval date ∈ [startdate, enddate] can be expressed as
t ∈ [midnightstartdate, midnightstartdate+1) ∪ [midnightstartdate+1, midnightstartdate+2) ∪ … ∪ [midnightenddate, midnightenddate+1)
Where t is and point in time belonging to the date interval.
Simplified, this then becomes
t ∈ [midnightstartdate, midnightenddate+1)
so the date interval
date ∈ [startdate, enddate]
is equivalent to the time interval
t ∈ [midnightstartdate, midnightenddate+1)
Choosing the correct Data Type
Many times I have seen systems represent date intervals using DateTime, and the Date interval of 1-30 Jun has been represented by start = “2018-06-01 00:00”, end = “2018-06-30 23:59:59”
But DateTime does not represent a Date. It represents a Date and a Time, either in UTC, or unspecified time zone.
There exists a library, NodaTime, to deal with this issue. The data type that represents a date interval is… DateInterval. It basically has a start date and an end date, on the type of those dates are LocalDate.
Similarly, the concept of a point in time, is in NodaTime represented by an Instant, free of any reference to winter/summer time, calendar system etc.
The corresponding way to represent an interval of time is by using the Interval type, represented by a start Instant and end Instant.
The nice thing now is that DateInterval and Interval are totally different types, so are LocalDate and Instant. If you try to compare any of them to another, you will get compile-time errors, which is absolutely correct. The only way to compare between LocalDate and Instant is by explicitly converting one or the other using a well defined time zone.
So do I endorse using NodaTime? Yes and no. The big point is that you need to always keep in mind what business meaning your data really has, when storing, comparing, and processing it. One way to enforce that is to represent your data using a strong type, enforcing the business meaning. One way to go is using NodaTime, but you could as well use another library (if you find one that suits your needs) or create your own representations.
Leave A Comment