Question

Is there a sensible way to group Long UTC dates by Day?

I would Mod them by 86400 but that doesn't take leap seconds into account.

Does anyone have any other ideas, I'm using java so I could parse them into Date Objects, but I'm a little worried of the performance overhead of using the date class.

Also is there a more efficient way than comparing the year month and day parts of a Date object?

Was it helpful?

Solution

Does your source data definitely include leap seconds to start with? Some APIs do, and some don't - Joda Time (which I'd recommend over the built-in date/time APIs) doesn't use leap seconds, for example. The Java date and time APIs "sometimes" do - they support 60 and 61 as values of "second in minute" but support depends on the operating system (see below). If you have some good sample values, I'd check that first if I were you. Obviously just dividing is rather simpler than anything else.

If you do need to create Date objects (or DateTime in Joda) I would benchmark it before doing anything else. You may well find that the performance is actually perfectly adequate. There's no point in wasting time optimizing something which is okay for your data. Of course, you'll need to decide data size you need to support, and how quick it needs to be first :)

Even the java.util.Date support for leap seconds is somewhat indeterminate. From the docs:

Although the Date class is intended to reflect coordinated universal time (UTC), it may not do so exactly, depending on the host environment of the Java Virtual Machine. Nearly all modern operating systems assume that 1 day = 24 × 60 × 60 = 86400 seconds in all cases. In UTC, however, about once every year or two there is an extra second, called a "leap second." The leap second is always added as the last second of the day, and always on December 31 or June 30. For example, the last minute of the year 1995 was 61 seconds long, thanks to an added leap second. Most computer clocks are not accurate enough to be able to reflect the leap-second distinction.

There's a rather good blog post about the mess with Java and leap seconds which you may want to read too.

OTHER TIPS

I would Mod them by 86400 but that doesn't take leap seconds into account....

I'm pretty sure that that will be fine. The API documentation for Date really shouldn't include anything about leap seconds, because the fact is that it emulates a standard Unix time ticker which does NOT include leap seconds in its value. What it does instead is to have a 59th second that lasts for two seconds by setting the ticker value back by 1 second at the start of a leap second (as the link in the previous post describes).

Therefore you can assume that the value you get from Date.getTime() IS made up only of 86400-second days. If you really need to know whether a particular day had a leap second, there are several tables available on the Internet (there have only been 23-24 since 1972, and computer dates before that rarely took them into account anyway).

HIH

Winston

tl;dr

Instant.ofEpochSecond( 1_493_367_302L )            // Convert a count of whole seconds from epoch of 1970 into a date-time value in UTC.
       .atZone( ZoneId.of( "Pacific/Auckland" ) )  // Adjust into the time zone as a context for determining a date.
       .toLocalDate()                              // Extract a date-only value by which we can sort/collect/organize our date-time values.

Time zone

The java.util.Date class represents a moment on the timeline in UTC. So asking it for a date gets you a date that only makes sense in UTC. That very same moment may be a date earlier in Québec or a date later in Auckland, New Zealand.

Time zone is crucial in determining a date, and your Question ignores this issue.

Using java.time

The java.util.Date class is part of the troublesome old date-time classes that are now legacy, supplanted by the java.time classes.

As for leap seconds, as the other Answers suggested, most sources of count-from-epoch do not count leap seconds. So verify your source.

If you have a count of whole seconds from epoch of 1970-01-01T00:00:00, then use the static method to create a Instant object.

Instant instant = Instant.ofEpochSecond( 1_493_367_302L ) ;

instant.toString(): 2017-04-28T08:15:02Z

Assign a time zone to create the context in which we can determine a date. For any given moment, the date varies around the world by zone.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ); 
ZonedDateTime zdt = instant.atZone( z );

zdt.toString(): 2017-04-28T01:15:02-07:00[America/Los_Angeles]

With of bunch of these ZonedDateDate objects, you can compare by date. You can extract a LocalDate object. The LocalDate class represents a date-only value without time-of-day and without time zone.

LocalDate ld = zdt.toLocalDate();

ld.toString(): 2017-04-28

So you could make a Map with LocalDate as the key and an List or Set of ZonedDateTime objects as the value. And with the modern lambda syntax, you could use Streams to do that mapping.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top