7

I have need for an interval data type representing years, months, weeks, days, hours, minutes, seconds. The first three (years, months, days) can be done with Period and the last three (hours, minutes, seconds) can be done with Duration however none of them seem to do both. Ideally I'd like to avoid having to implement a custom TemporalAmount.

Philippe Marschall
  • 4,452
  • 1
  • 34
  • 52
  • 2
    I'm voting to close this question as off-topic because this is not a code writing service. – Raedwald Jan 04 '16 at 19:34
  • 3
    Why code writing service? I have trouble understanding an API. "Ideally I'd like to avoid having to implement a custom TemporalAmount". So no, I'm not looking for code, I'm looking for understanding. – Philippe Marschall Jan 05 '16 at 08:19
  • 2
    About the motivation of JSR-310-team to drop the originally planned support for mixed periods (containing months, days, time) see [this old threeten-issue](https://github.com/ThreeTen/threeten/issues/248) I suspect they feared the complexity and had not enough time before releasing Java-8. Well, writing such a class is indeed complex, see also the size of my [Duration-class](https://github.com/MenoData/Time4J/blob/master/core/src/main/java/net/time4j/Duration.java) - more than 5700 rows. By the way, Joda-Time-Period is also such a class (and also complex). – Meno Hochschild Jan 05 '16 at 16:48
  • 3
    A similar [question](http://stackoverflow.com/questions/32366154/how-to-handle-full-period-in-java-time) which is still open was posted some time earlier. – Meno Hochschild Jan 05 '16 at 17:04

2 Answers2

5

There is a reason why there is no such type. There is no well defined time intervals such as "day", "month" or "year":

  • day is not always 24 hours (depends on DST, timezone and leap seconds)
  • every month has different number of days
  • leap years have 366 days

Even if you implement a custom TemporalAmount there is high chance that your code will be incorrect in some cases. If you state your actual requirements you might get a better answer.

kostya
  • 9,221
  • 1
  • 29
  • 36
  • 2
    Yes there is, see the Period class. – Philippe Marschall Jan 04 '16 at 16:41
  • Period only supports years, month and days units. It doesn't support hours, minutes, etc. – kostya Jan 04 '16 at 16:49
  • If you implement a TemporalAmount that supports both date and time units then would 25 hours be equivalent to 1 day and 1 hour? But this is not always true. – kostya Jan 04 '16 at 16:53
  • 2
    Yes I know that Period only supports years, month and days, that's what the question says. As I said, I would go for Period semantics, so 25 hours would be 25 hours. – Philippe Marschall Jan 04 '16 at 16:59
  • What is the actual functionality that you want to implement (from the user point of view)? – kostya Jan 04 '16 at 17:01
  • 2
    I want to model the PostgreS [interval type](http://www.postgresql.org/docs/9.4/static/datatype-datetime.html) – Philippe Marschall Jan 04 '16 at 17:30
  • 2
    @PhilippeMarschall Then you must read the documenation: »Internally interval values are stored as months, days, and seconds. This is done because the number of days in a month varies, and a day can have 23 or 25 hours if a daylight savings time adjustment is involved. The months and days fields are integers while the seconds field can store fractions.« So you need to create a class that consists of a Period and a Duration. You are safe with the years as PostgreSQL has a maximum of `178000000` years whereas Java Period's maximum is `2147483647` years. Why didn't you ask *that* in the beginning? – steffen Jan 04 '16 at 18:15
4

The reason why no such class exists is that there are actually two different concepts of time: (1) a fixed number of (e. g.) seconds which is called a Duration in Java world or (2) a let's say variable number of seconds which is called a Period. The period tries to abstract from changing lengths of

  • minutes (leap seconds, this isn't implemented)
  • days (daylight savings)
  • months (28, 29, 30, 31 days)
  • years (leap years)

That's why Period stores days, months, years and Duration just seconds and nano seconds. Yes, they do share the same time unit DAY, but a Duration day is considered to be 24h and directly converted to seconds.

The period between 2016-02-01 and 2016-03-01 is 1 month. The duration is 696 hours, not 720 hours. You can say that a duration of a period may change.

So you need to define your application. Do you want a duration (fixed amount of seconds) or a period (something that "happens" once in a year)?

Here's an example how they do compute different instants after a daylight savings change:

Duration oneDayDuration = Duration.ofDays(1);
Period oneDayPeriod = Period.ofDays(1);
ZonedDateTime beforeChange = Instant.parse("2015-10-25T00:00:00.00Z").atZone(ZoneId.of("Europe/Berlin"));
System.out.println(beforeChange);
System.out.println(oneDayDuration.addTo(beforeChange));
System.out.println(oneDayPeriod.addTo(beforeChange));

will print

2015-10-25T02:00+02:00[Europe/Berlin]
2015-10-26T01:00+01:00[Europe/Berlin]
2015-10-26T02:00+01:00[Europe/Berlin]
steffen
  • 16,138
  • 4
  • 42
  • 81