Why is adding weeks to java.time.Instant not suppo

2020-04-05 07:14发布

问题:

The following piece of code:

Instant inFourWeeks = Instant.now().plus(4L, ChronoUnit.WEEKS);

Throws an exception:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Weeks

Why are weeks unsupported? I understand why months and years are not supported, because their duration in smaller units may vary. But a week has constant duration (7 days) and I can achieve the same by writing:

Instant inFourWeeks = Instant.now().plus(4L * 7L, ChronoUnit.DAYS);

回答1:

It throws UnsupportedTemporalTypeException 7 days week is not universal and constant. It may vary of different calendar system. For example, look on the Akan calendar system which uses 6 days a week.



回答2:

The Instant class deals with absolute time, and tries to avoid all ambiguities related to how different calendar systems, regions and cultures group and interpret it.

Some calendar systems have different week lengths, some have different month groupings, have years that start on a different date, and adjust for leap years and leap seconds in different ways (if at all, like in the case of the Julian calendar which had too many leap years and drifted from the 'physical' phenomena they were supposed to be in sync with, like the seasons, solstices and equinox).

To avoid these problems the Instant class allows you to use the more precisely defined and standardised units like the seconds, minutes, hours and days.

Leap seconds are 'smoothened' out in Java, over the last 1000 seconds of the day on which they occur, so from a programmer's perspective they do not exist. (Computer clocks are not that accurate anyway, and need to sync frequently with NTP.)

1 day is assumed to be 24 SI hours, with 1 SI hour defined as 60 SI minutes, 1 SI minute defined as 60 SI seconds, and 1 SI second being 9,192,631,770 radiation periods of Caesium-133. 24hrs is actually the mean Solar Day (time elapsed between two successive 'noons'), because due to elliptical orbits, the orbit of the sun itself, and variations in orbit speed, each solar day could be slightly longer or shorter.

One important thing you have to be careful of is Daylight Saving. In those special days, a day is 25 hours or 23 hours, depending on which direction the clock moves. However, the Instant class doesn't care about this, it will still move 24 hours if you add 1 day over the daylight savings boundary. It doesn't carry any timezone or regional information (DST is country specific).



回答3:

ChronoUnit.WEEKS may be used for weeks in other calendar systems than the ISO calendar. And such weeks may be for example 6 or 10 days long. So while it may be argued that it makes sense that Instant supports days, the same is not true for weeks.

From the documentation:

Unit that represents the concept of a week. For the ISO calendar system, it is equal to 7 days.

When used with other calendar systems it must correspond to an integral number of days.

It clearly follows from this that WEEKSdoes not generally assume the ISO calendar system and may be used with other calendars too.

The other part of the argument is that Instant does not assume one calendar system but can be used with different calendar systems too. (By contrast, ZonedDateTime, for example, assumes the ISO-8601 calendar system so does support weeks.)

PS I’d rather put the question the other way around: why does Instant support days? A day may be 23, 23.5, 24, 24.5 or 25 hours, and historically other durations too.

Link: Documentation of ChronoUnit.WEEKS.



回答4:

If you look at the code for plus(long, TemporalUnit) , it does not support WEEK,

 @Override
     public Instant plus(long amountToAdd, TemporalUnit unit) {
         if (unit instanceof ChronoUnit) {
             switch ((ChronoUnit) unit) {
                 case NANOS: return plusNanos(amountToAdd);
                 case MICROS: return plus(amountToAdd / 1000_000, (amountToAdd % 1000_000) * 1000);
                 case MILLIS: return plusMillis(amountToAdd);
                 case SECONDS: return plusSeconds(amountToAdd);
                 case MINUTES: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_MINUTE));
                 case HOURS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_HOUR));
                 case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
                 case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
             }
             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
         }
         return unit.addTo(this, amountToAdd);
     }

From code it is clear that results are calculated by multiplying seconds representation of units, a Week/Month/year can not be logically and consistently represented by seconds as these are not universal contants according to javadoc.



回答5:

Other Answers are correct. I am adding this bit of clarification.

Instant is basic building-block

The Instant class is a basic building-block in the java.time classes. It represent a moment, a point on the timeline. Internally it is simply a count of whole seconds since the epoch reference of first moment of 1970 in UTC. So this class is deserving of little functionality.

This building-block may be used to track a moment in any of many possible calendaring systems. Making sense of an Instant, to treat it as a date, week, month, and so on is up to the definitions of a particular calendaring system. A calendaring system can define any number of days in a week, or any number of months in a year, and so on, or may not even have such concepts as week or month.

The most obvious calendar system is the modern ISO 8601 used throughout the West and other parts of the world. The OffsetDateTime & ZonedDateTime classes built on top of Instant to make up key parts of this ISO calendaring system. These classes are bundled with Instant merely because they are expected to be commonly used by many Java programmers. But they are by no means the only calendaring system.

Look to the java.time.chrono package for these various calendar systems:

  • HijrahChronology
    The Hijrah calendar is a lunar calendar supporting Islamic calendars.
  • IsoChronology
  • JapaneseChronology
    The Japanese Imperial calendar system.
  • MinguoChronology
    The Minguo calendar system.
  • ThaiBuddhistChronology
    The Thai Buddhist calendar system.

The ThreeTen-Extra project provides additional functionality to the java.time classes. This includes more calendaring systems:

  • AccountingChronology
    A proleptic 52/53-week Accounting calendar system per IRS Publication 538 and the International Financial Reporting Standards.
  • BritishCutoverChronology
    The British Julian-Gregorian cutover calendar system.
  • CopticChronology
    The Coptic calendar system.
  • DiscordianChronology
    The Discordian calendar system.
  • InternationalFixedChronology
    The International Fixed calendar system. Also known as the Eastman Kodak calendar.
  • JulianChronology
    The proleptic Julian calendar system, forerunner to the modern Gregorian and ISO calendars.
  • PaxChronology
    The Pax calendar system.
  • Symmetry010Chronology
  • Symmetry454Chronology
    The Symmetry454 calendar system.

There may be yet more from third-parties that I am not aware of.