Philippe Marschall
Philippe Marschall

Reputation: 4604

Period with hours, minutes and seconds

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.

Upvotes: 7

Views: 7288

Answers (2)

steffen
steffen

Reputation: 17048

The reason why there is no such class is that there are actually two different concepts of a time span. In Java, these two concepts are implemented in two different classes:

  • a fixed number of (e.g.) seconds is a Duration in the Java world (think of a bag of seconds)
  • a variable number of seconds in a larger time unit (like a month) which is called a Period

While a duration has always the same time length, the actual time length of a period depends on when and where it is applied. A period of one month can be 28, 29, 30 or 31 days - it's actual duration depends on the context. A period of one day may have 23, 24 or 25 hours (and more) when there's daylight savings in a given timezone.

Here's a small and likely incomplete list of factors that have an effect on the conversion of a period to a duration.

  • 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 and years seperately and Duration just seconds (and nano seconds). They do share the same time unit DAY, but a Duration day is considered to be 24h and is directly converted to 86,400 seconds.

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, twice per month, every day at 2:00 am)?

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]

Upvotes: 5

kostya
kostya

Reputation: 9569

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.

Upvotes: 6

Related Questions