2017-11-10 195 views
0

我试图在当前时间添加几年。我的代码如下所示:java.time.Instant.plus(long amountToAdd,TemporalUnit unit)不受支持的单位

// ten yeas ago 
int backYears = 10; 
Instant instant = ChronoUnit.YEARS.addTo(Instant.now(), -backYears); 

但我有一个例外:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Years 
at java.time.Instant.plus(Instant.java:862) 

当我打开方法Instant.plus我看到以下内容:

@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); 
} 

正如你可以看到MONTHSYEARS不受支持。但为什么? 与旧java.util.Calendar我能做到这一点很容易:

Calendar c = Calendar.getInstance(); 
    c.setTime(date); 
    c.add(Calendar.YEAR, amount); 
    return c.getTime(); 

的原因只有一个,我想那是什么,我们不知道有多少天,一个月,一年,因为闰日29二月 但要说实话,我们也有一个leap second。 因此,我认为这是一个错误,应该支持所有的ChronoUnit。 唯一的问题是:我们是否需要考虑闰秒和闰日。 至于我的需要没关系,只是假设该月有30天和365年。 我不需要像Calendar.roll()这样的东西,但这也可以满足我。

+0

我没有设计课程,所以我无法确定。我认为从毫微秒到数天的单位可以明确地转换为秒和毫微秒(忽略闰秒,因为几乎所有计算机都忽略它们),因此得到支持。像“ZonedDateTime”,“OffsetDateTime”和“LocalDateTime”这样的类知道如何处理数月和数年,因此使用它们来添加这样的单位。 –

回答

0

让我们尝试一下。我在ZonedDateTime的瞬间,并在不同时区减去10年。

OffsetDateTime origin = OffsetDateTime.of(2018, 3, 1, 0, 0, 0, 0, ZoneOffset.UTC); 
    Instant originInstant = origin.toInstant(); 
    Instant tenYearsBackKyiv = origin.atZoneSameInstant(ZoneId.of("Europe/Kiev")) 
      .minusYears(10) 
      .toInstant(); 
    long hoursSubtractedKyiv = ChronoUnit.HOURS.between(tenYearsBackKyiv, originInstant); 
    System.out.println("Hours subtracted in Київ: " + hoursSubtractedKyiv); 
    Instant tenYearsBackSaoPaulo = origin.atZoneSameInstant(ZoneId.of("America/Sao_Paulo")) 
      .minusYears(10) 
      .toInstant(); 
    long hoursSubtractedSaoPaulo = ChronoUnit.HOURS.between(tenYearsBackSaoPaulo, originInstant); 
    System.out.println("Hours subtracted in São Paulo: " + hoursSubtractedSaoPaulo); 

的输出是:

Hours subtracted in Київ: 87648 
Hours subtracted in São Paulo: 87672 

正如你可以看到在24小时以上(1天以上)在圣保罗减去相比Київ(基辅,基辅)。你可能已经发现,这是因为我们从3月1日到2月29日闰年三次,在Київ只有两次。

旧的和现在过时的Calendar班总是有一个时区,所以知道在哪个时区减去几年(另一件事是它很高兴给你一个结果,即使在不清楚你是哪个结果的情况下通缉)。现代课程ZonedDateTime,OffsetDateTimeLocalDateTime可以做同样的事情。所以用它们。 Instant概念上没有时区,所以拒绝执行依赖于时区的操作(我知道它是使用UTC实现的,但我们应该将其视为不相关的实现细节,而不是接口规范的一部分到班级)。

无论是旧的还是现代的课程都没有将飞跃考虑在内,并且您是对的,因此只能用Instant加减日,小时和分钟。