What is the correct end-of-day interpretation?
Asked Answered
Y

5

7

Over the years I have come across different interpretations of the end of a day. But what is the correct way of representing it when comparing dates and intervals?

I have found that some people seem to prefer 23:59:59, while others do use 00:00:00.
Here on StackOverflow I have even found a few instances of questions relating to the use and display of 24:00:00, however the scope of this question is more focused on determining how to split two days.

In other words we are interested in the problem of determining where does exactly a day ends, and where the next begins. This seem to be a common problem in many applications that require even the most basic time intervals comparisons or calculations.

To clarify the above interpretations, below are three examples representing January 1st 2014 under the three different interpretations:

  1. Quasi midnight: 2014-01-01 00:00:00 - 2014-01-01 23:59:59
  2. Midnight sharp: 2014-01-01 00:00:00 - 2014-01-02 00:00:00
  3. Military midnight: 2014-01-01 00:00:00 - 2014-01-01 24:00:00

While I do feel that the quasi midnight interpretation is the most intuitive one, it also seem to requires a fair amount of boilerplate to point the time correctly. Additionally there's the risk of running into edge cases when that last second of the day isn't correctly handled, or the risk of influencing performance when scanning huge collections of intervals for testing around those gaps.

Similarly, the military midnight interpretation also seem to require some boilerplate to setup the dual representation of that division point. Without too much thinking I can't think of many complications using this approach.

Finally the midnight sharp interpretation seems to be good candidate for the the most consistent one. Unlike midnight quasi, it does not require boilerplate to set the time and it naturally behaves with the operators <, <=, > and >=.

It's worth noting that the PHP language already interprets 2014-01-01 24:00:00 as 2014-01-02 00:00:00, which has the effect of converting the date to midnight sharp interpretation.

Are there notable precedents in exemplary FLOSS libraries or standards that would justify use of one interpretation over another?

Yorker answered 7/10, 2014 at 23:1 Comment(9)
What is the definition of 'correct' in this context?Ammoniac
What's your actual application? Won't that have a bearing on which interpretation to use?Matthias
I believe correct in the context of the question implies that the interpretation inherently works with operators, it does not require boilerplate or setup code and that it does not leave space for uncertainty. See @JonathonReinhart's answer for an explanation of undefined time, or gaps.Yorker
The problem with eliminating gaps is that then there can be two 'days' going on at once. If you define things using 'midnight sharp' as written above, for instance, then at 00:00:00 on 'any given day', it is also still the previous day. ('Monday the 1st, at 00:00:00 on the 2nd' would be identical to 'Tuesday the 2nd at 00:00:00 on the 2nd'.)Ammoniac
I have always done all calculations and comparisons under the midnight sharp interpretation, rendering of a date it's a matter of localisation and therefore I relegate the burden of displaying '23:59:59' to the topmost level of my code. However this question seem to deceive most of my fellow programmers in uni and even FLOSS developers. Therefore I wonder if I were wrong all along.Yorker
I don't have a comprehensive answer, but Perl's Date::Manip, the library I've used for years to convert human date time expressions into official timestamps, use the sharp interpretation. "Midnight" = 2014-01-01 00:00:00Clara
That's exactly what I was hoping to read in the answers: examples of precedence in FLOSS software or standards. I should perhaps update the question once more. @JonathanEunice: I would be happy to mark your comment as the accepted answer if formulated as an answer, possibly with more examples :)Yorker
The problem is far more complex than a "correct representation". Solving it with the generic time types found in most platforms is impossible. For example you never consider the timezone, without which you don't really know what time it is (imagine summer time changes). There are libraries like Joda Time in Java or Noda Time in .NET that make such matters explicit, so that End-Of-Time for one date can never be confused with start of time for the next, timezones are always explicit, etcTransmigrate
I'll soon be adding a note to the question to indicate that all calculation are performed on UTC dates, so there's no real timezone issues to worry about. I'll also have a look at the libraries you've mentioned to see how they enforce this distinction, though I'd appreciate a direct pointer since you seem to be familiar with them.Yorker
I
5

First let's recall open and closed intervals from mathematics:

  • An open interval does not include its endpoints, and is indicated with parentheses. For example (0,1) means greater than 0 and less than 1.
  • A closed interval includes its endpoints, and is denoted with square brackets. For example [0,1] means greater than or equal to 0 and less than or equal to 1.

I don't think anyone will disagree that the day starts at time 00:00:00.000000.... That means any second, millisecond, microsecond, etc. prior to that point falls on the previous day.

We express this concept by using a left-closed and right-open interval. So:

The day January 1st 2014 spans the time ["2014-01-01 00:00:00", "2014-01-02 00:00:00")

This would imply midnight sharp is correct. However this would require your machine to have infinite resolution to represent all of those really, really small units of time just before 00:00:00 the next day.

Since no digital system can have infinite resolution, we are forced to concede to a quasi midnight, which would be a closed interval. The exact value of right endpoint depends on the resolution of your system.

As MikeW put it:

The day January 1st 2014 spans the time
["2014-01-01 00:00:00", "2014-01-02 00:00:00"-system_resolution]

If your environment / language / data structures provide only one-second resolution, then the last moment of the day is at 23:59:59. For one-millisecond resolution, that would be 23:59:59.999.

So in essence, both quasi midnight and midnight sharp are correct, but your endpoint for quasi midnight depends on your resolution.


In practice, I don't think you need to worry about it! Simply use the DateTime-like objects/APIs your language provides, and the appropriate conditional operators (pseudo-code):

if DateTime.Now() < DateTime("2000-01-01 00:00:00"):
    // Worry about Y2K bugs
Isopropanol answered 7/10, 2014 at 23:8 Comment(11)
There's no reason why you can't measure the last second as, for example, 23:59:59.999 (last millisecond). The problem with midnight sharp is that you have an ambiguity.Alrich
@user2864740 Why would it be wrong? < 2014-01-02 00:00:00 would be before January 2nd.Dace
In that case, you'r not using midnight sharp, you're using quasi midnight.Alrich
It's an open interval on the "end of" time. That means every micro-fractional second up to 00:00:00 falls on the previous day.Isopropanol
I completely re-wrote my answer, basically forming a compromise between what we were all saying. I appreciate the constructive criticism. Please let me know if that makes more sense.Isopropanol
Good points here. So would we need the language itself to give us the ability to obviate whether we are considering the left or right limit of the end-of-the-day point, before we can consider midnight sharp interpretation the correct one?Yorker
@Andrea Basically, I think you're thinking too hard about the problem. We can express in PHP and .NET exactly what we mean when we say "before midnight" in English. The time "00:00:00" always only occurs at the start of a day. Any sub-unit prior to that time falls on the previous day.Isopropanol
@JonathonReinhart: I think figuring out on which side of a 00:00:00 is not much of a problem so long the code consistently treats that particular date+time as the right extreme of the interval.Yorker
@Andrea To be honest, I'm not sure of any language/library that doesn't do so. I'll try to dig up some examples.Isopropanol
Notwithstanding the impossibility of having an infinitely precise resolution, IMO midnight sharp would still be the correct interpretation, provided we use <, >= operators consistently as pointed out by @jbx.Yorker
@JonathonReinhart semantics are a dangerous thing when time calculations matter,eg when calculating travel times, arrivals and departures across timezones. Libraries like Joda Time and Noda time solve the problem by making all assumptions explicit (dates, timezones, intervals, periods, calculations etc) so there is no way you can confuse the end-of-day for one date with the start-of-date for the nextTransmigrate
D
5

00:00:00 is the start of the new day.

23:59:59 is the last second of the old day, but there is still a second to go, so 23:59:59.999 is the last millisecond of the old day. Its still not the end-of-day though, there is still 1 millisecond to go.

It depends on what you need to do. If you want to check if an event happened before midnight sharp (for example you are querying a MySQL database), the < operator on the start of the new day would do because it caters for whatever granularity you have (nanoseconds, microseconds, whatever).

If you want to check if something happened in the new day, it has to be >= the start of the new day, i.e. 00:00:00

Dace answered 7/10, 2014 at 23:7 Comment(2)
In what timezone? A simple time type is not enough to handle this problem. There are industries like travel, transportation, where such issues are very important and there is no room for assumptions and ambiguitiesTransmigrate
You are right, but the issue here is not timezone related. OP's question is about the exact boundary that delimits one day from another, without any mention of timezone differences. If you are treating different timezones for travel etc. then you need to take it into consideration too. Depending on what your problem is you could either normalise to one timezone such as UTC, or adjust to the user's timezone if you know it. It depends on your problem.Dace
I
5

First let's recall open and closed intervals from mathematics:

  • An open interval does not include its endpoints, and is indicated with parentheses. For example (0,1) means greater than 0 and less than 1.
  • A closed interval includes its endpoints, and is denoted with square brackets. For example [0,1] means greater than or equal to 0 and less than or equal to 1.

I don't think anyone will disagree that the day starts at time 00:00:00.000000.... That means any second, millisecond, microsecond, etc. prior to that point falls on the previous day.

We express this concept by using a left-closed and right-open interval. So:

The day January 1st 2014 spans the time ["2014-01-01 00:00:00", "2014-01-02 00:00:00")

This would imply midnight sharp is correct. However this would require your machine to have infinite resolution to represent all of those really, really small units of time just before 00:00:00 the next day.

Since no digital system can have infinite resolution, we are forced to concede to a quasi midnight, which would be a closed interval. The exact value of right endpoint depends on the resolution of your system.

As MikeW put it:

The day January 1st 2014 spans the time
["2014-01-01 00:00:00", "2014-01-02 00:00:00"-system_resolution]

If your environment / language / data structures provide only one-second resolution, then the last moment of the day is at 23:59:59. For one-millisecond resolution, that would be 23:59:59.999.

So in essence, both quasi midnight and midnight sharp are correct, but your endpoint for quasi midnight depends on your resolution.


In practice, I don't think you need to worry about it! Simply use the DateTime-like objects/APIs your language provides, and the appropriate conditional operators (pseudo-code):

if DateTime.Now() < DateTime("2000-01-01 00:00:00"):
    // Worry about Y2K bugs
Isopropanol answered 7/10, 2014 at 23:8 Comment(11)
There's no reason why you can't measure the last second as, for example, 23:59:59.999 (last millisecond). The problem with midnight sharp is that you have an ambiguity.Alrich
@user2864740 Why would it be wrong? < 2014-01-02 00:00:00 would be before January 2nd.Dace
In that case, you'r not using midnight sharp, you're using quasi midnight.Alrich
It's an open interval on the "end of" time. That means every micro-fractional second up to 00:00:00 falls on the previous day.Isopropanol
I completely re-wrote my answer, basically forming a compromise between what we were all saying. I appreciate the constructive criticism. Please let me know if that makes more sense.Isopropanol
Good points here. So would we need the language itself to give us the ability to obviate whether we are considering the left or right limit of the end-of-the-day point, before we can consider midnight sharp interpretation the correct one?Yorker
@Andrea Basically, I think you're thinking too hard about the problem. We can express in PHP and .NET exactly what we mean when we say "before midnight" in English. The time "00:00:00" always only occurs at the start of a day. Any sub-unit prior to that time falls on the previous day.Isopropanol
@JonathonReinhart: I think figuring out on which side of a 00:00:00 is not much of a problem so long the code consistently treats that particular date+time as the right extreme of the interval.Yorker
@Andrea To be honest, I'm not sure of any language/library that doesn't do so. I'll try to dig up some examples.Isopropanol
Notwithstanding the impossibility of having an infinitely precise resolution, IMO midnight sharp would still be the correct interpretation, provided we use <, >= operators consistently as pointed out by @jbx.Yorker
@JonathonReinhart semantics are a dangerous thing when time calculations matter,eg when calculating travel times, arrivals and departures across timezones. Libraries like Joda Time and Noda time solve the problem by making all assumptions explicit (dates, timezones, intervals, periods, calculations etc) so there is no way you can confuse the end-of-day for one date with the start-of-date for the nextTransmigrate
A
1

Well, "what is the correct way of representing it?" is a subjective question, so it's impossible to answer. That said, most 'clock' apps and system clocks represent it as 'Quasi Midnight' above, so you should probably go with that if you want consistency in representing time to users.

But if you aren't showing the time directly to users and are instead using it as part of some other calculation, it's likely application-specific.

This page and this page provide quite a few examples of how problematic time is, and how subjective 'correctness' could get depending on your application.

Ammoniac answered 7/10, 2014 at 23:5 Comment(0)
D
1

IMO, it mainly comes down to * what requirements you actually have for the problem at hand and * time resolution in the tools/languages at your disposal.

After all, it is very easy to overthink any problem in abstract terms.

Having said that, I'd personally prefer strict less-than (<) 00:00:00

Ditzel answered 7/10, 2014 at 23:7 Comment(2)
I totally agree with you. It seems 'wrong' to create any discontinuity in an otherwise continuous interval of time, be it any submultiple of a minute.Yorker
But at some point, you can't represent time continually. Even if you sample in microseconds, you are ignoring the space between microseconds. Time is continuous, computation is discrete.Ammoniac
I
1

A datetime data type has traditionally been represented as floating point number. The whole number portion is the number of day from a predetermined epoch and the mantissa or decimal portion makes up the time offset. There are many different epochs and many different ways to store a date time. I have mostly observed start of day as 01/01/2001 12:00:00 AM and end of day treated as 01/01/2001 11:59:59 PM.

A good way to think about it would be that subtracting one second from midnight will yeild 11:59:59 of the previous day and then adding the second back it would again be midnight.

A value for midnight of a specific day would be stored the same way using the epoch mentioned above. The 12 hour 24 hour Zulu semantics are just chosen display settings of a Date Time value.

Ionia answered 7/10, 2014 at 23:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.