2014-06-30 4 views
31

della classe Duration nel nuovo JSR 310 Data API (java.time package) disponibili in Java 8 e versioni successive, il javadoc dice:Perché non riesco a ottenere una durata in minuti o ore in java.time?

Questa classe modelli una quantità o quantità di tempo in termini di secondi e nanosecondi. È possibile accedervi utilizzando altre unità basate sulla durata, ad esempio come minuti e ore. Inoltre, l'unità DAYS può essere utilizzata ed è considerata esattamente uguale a 24 ore, ignorando quindi gli effetti dell'ora legale.

Quindi, perché il seguente codice si blocca?

Duration duration = Duration.ofSeconds(3000); 
System.out.println(duration.get(ChronoUnit.MINUTES)); 

Questo solleva una UnsupportedTemporalTypeException:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Minutes 
    at java.time.Duration.get(Duration.java:537) 

Allora, qual è il metodo consigliato per estrarre minuti e ore da un oggetto di durata? Dobbiamo calcolare noi stessi dal numero di secondi? Perché è stato implementato in questo modo?

+2

http://stackoverflow.com/questions/20827047/formatting-a-duration-in-java-8-jsr310 (la risposta non accettata) –

+1

FY Io, c'è un progetto per estendere java.time, [ThreeTen Extra] (http://www.threeten.org/threeten-extra/). Ma non penso che al momento abbia qualcosa per aiutarti. –

+2

Sembra che JSR 310 java.time non sia tutto ciò che speravamo. Non è un sostituto completo e superiore per [Joda-Time] (http://www.joda.org/joda-time/). Mentre java.time ha i suoi punti di forza, così fa Joda-Time. Joda-Time offre tre classi per gestire un intervallo di tempo (Durata, Periodo, Intervallo), ha un buon supporto integrato per la rappresentazione della stringa ISO 8601 di span e un buon supporto per la definizione dei propri formattatori. –

risposta

44

"Perché è stato implementato in questo modo?"

Altre risposte trattano i metodi toXxx() che consentono di interrogare ore/minuti. Proverò ad affrontare il perché.

L'interfaccia TemporalAmount e il metodo get(TemporalUnit) sono stati aggiunti abbastanza tardi nel processo. Personalmente non ero del tutto convinto che avessimo abbastanza prove del modo giusto di lavorare il design in quell'area, ma che fosse leggermente ritorto per aggiungere TemporalAmount. Credo che nel fare ciò abbiamo leggermente confuso l'API.

Con il senno di poi, credo che TemporalAmount contenga i giusti metodi, ma credo che get(TemporalUnit) avrebbe dovuto avere un nome di metodo diverso. Il motivo è che lo standard get(TemporalUnit) è essenzialmente un metodo a livello di framework: non è progettato per l'utilizzo giornaliero. Sfortunatamente il nome del metodo get non implica questo, causando bug come chiamare get(ChronoUnit.MINUTES) su Duration.

Quindi, il modo di pensare di get(TemporalUnit) è quello di immaginare un quadro di basso livello Verifica della quantità come Map<TemporalUnit, Long> dove Duration è un Map di dimensioni due con i tasti di SECONDS e NANOS.

Allo stesso modo, Period visto dalla quadri basso livello come Map di tre dimensioni - DAYS, MONTHS e YEARS (che fortunatamente ha meno probabilità di errori).

Nel complesso, il miglior consiglio per il codice dell'applicazione è ignorare il metodo get(TemporalUnit). Utilizzare invece getSeconds(), getNano(), toHours() e toMinutes().

Infine, un modo per ottenere "hh: mm: ss" da un Duration è quello di fare:

LocalTime.MIDNIGHT.plus(duration).format(DateTimeFormatter.ofPattern("HH:mm:ss")) 

Non abbastanza a tutti, ma funziona per durate meno di un giorno.

Nuove to…Part metodi in Java 9

JDK-8142936 problema ora implementate in Java 9, aggiungendo i seguenti metodi per accedere a ogni parte di un Duration.

  • toDaysPart
  • toHoursPart
  • toMinutesPart
  • toSecondsPart
  • toMillisPart
  • toNanosPart
+0

Grazie per l'interessante vista interna sul perché e l'utile piccolo trucco di formattazione :) –

20

Il documentation dice:

Questo restituisce un valore per ciascuno dei due supportate unità, secondi e NANOS. Tutte le altre unità generano un'eccezione.

Quindi, la migliore risposta di indovinare - è così che l'hanno progettata.

È possibile utilizzare alcuni degli altri metodi per ottenere in hours:

long hours = duration.toHours(); 

o minutes:

long minutes = duration.toMinutes(); 
+2

Interessante. In realtà non ho visto i metodi toXXX. Ma convertono il numero totale di secondi in un numero dell'unità richiesta, senza prendere in considerazione le unità superiori. Ad esempio: per una durata di '10000' secondi, il metodo' toMinutes() 'restituirà 166. Non è così utile se è necessario mostrare' hh: mm: ss', ma può essere usato come parte di un metodo di calcolo più completo . –

+0

@PierreHenry Beh, non è esattamente nel formato che desideri, ma puoi usare 'duration.toString()' per ottenere la durata come valore leggibile dall'uomo – blgt

+0

Per ottenere solo il componente ore (senza i giorni): 'int hours = (int) (durata.toHours()% 24L); ' – MT0

5

per ottenere la seconda componenti/ora/minuto in un modo "normalizzato" , è necessario calcolarli manualmente: il codice riportato di seguito viene essenzialmente copiato dal metodo Duration#toString:

Duration duration = Duration.ofSeconds(3000); 
long hours = duration.toHours(); 
int minutes = (int) ((duration.getSeconds() % (60 * 60))/60); 
int seconds = (int) (duration.getSeconds() % 60); 
System.out.println(hours + ":" + minutes + ":" + seconds); 
+0

Non riesco a trovare l'API [Durata] (http://docs.oracle.com/javase/8/docs/api/java/time/Duration.html) per fare ciò. Quindi seguo questa risposta. –

6

Vorrei aggiungere alla risposta di bigt (+1) che ha evidenziato l'utile toHours, toMinutes e altri metodi di conversione. Il Duration specification dice:

Questa classe modella una quantità o quantità di tempo in termini di secondi e nanosecondi. [...]

L'intervallo di una durata richiede la memorizzazione di un numero maggiore di un lungo. Per ottenere ciò, la classe memorizza un long che rappresenta secondi e un int che rappresenta un nanosecondo di secondo, che sarà sempre compreso tra 0 e 999.999.999.

Ci sono una varietà di getter metodi come getSeconds, getNano e get(TemporalUnit). Dato che una durata è rappresentata come una coppia (secondi, nanos), è chiaro il motivo per cui get(TemporalUnit) è limitato a secondi e nanos. Questi metodi getter estraggono i dati direttamente dall'istanza di durata e sono senza perdita di dati.

Per contro, v'è una varietà di metodi per-compreso toDays, toHours, toMillis toMinutes e toNanos che fanno conversione sul valore di durata. Queste conversioni sono in perdita poiché implicano il troncamento dei dati oppure possono generare un'eccezione se il valore della durata non può essere rappresentato nel formato richiesto.

È chiaramente parte del progetto che i metodi get estraggono i dati senza conversione e i to-metodi eseguono conversioni di qualche tipo.

0

Con codice qui sotto ho ottenuto questo output Durata:

1 giorno, 2 ore, 5 minuti

esempio di codice:

private String getDurationAsString(Duration duration) 
{ 
    StringBuilder durationAsStringBuilder = new StringBuilder(); 
    if (duration.toDays() > 0) 
    { 
     String postfix = duration.toDays() == 1 ? "" : "s"; 
     durationAsStringBuilder.append(duration.toDays() + " day"); 
     durationAsStringBuilder.append(postfix); 
    } 

    duration = duration.minusDays(duration.toDays()); 
    long hours = duration.toHours(); 
    if (hours > 0) 
    { 
     String prefix = Utils.isEmpty(durationAsStringBuilder.toString()) ? "" : ", "; 
     String postfix = hours == 1 ? "" : "s"; 
     durationAsStringBuilder.append(prefix); 
     durationAsStringBuilder.append(hours + " hour"); 
     durationAsStringBuilder.append(postfix); 
    } 

    duration = duration.minusHours(duration.toHours()); 
    long minutes = duration.toMinutes(); 
    if (minutes > 0) 
    { 
     String prefix = Utils.isEmpty(durationAsStringBuilder.toString()) ? "" : ", "; 
     String postfix = minutes == 1 ? "" : "s"; 
     durationAsStringBuilder.append(prefix); 
     durationAsStringBuilder.append(minutes + " minute"); 
     durationAsStringBuilder.append(postfix); 
    } 

    return durationAsStringBuilder.toString(); 
} 

Spiegazione:

Utilizzando l'interfaccia Durata si può facilmente trovare l'esatto Visualizzazione delle stringhe che si desidera. hai solo bisogno di ridurre il più grande TemporalUnit dalla durata corrente.

ad esempio:

  1. giorni Calcolare
  2. ridurre giorni dalla durata
  3. ore Calcolare
  4. ridurre le ore di durata ecc ... fino a quando u get durata = 0