2013-04-12 6 views
17

ISO 8601 definisce una sintassi per la rappresentazione di un intervallo di tempo.Analisi intervallo di tempo ISO 8601 in Java

Ci sono quattro modi per esprimere un intervallo di tempo:

  • di inizio e fine, come "2007-03-01T13: 00: 00Z/2008-05-11T15: 30: 00Z"
  • inizio e la durata, come ad esempio "2007-03-01T13: 00: 00Z/P1Y2M10DT2H30M"
  • durata e alla fine, come ad esempio "P1Y2M10DT2H30M/2008-05-11T15: 30: 00Z" solo
  • durata, come ad esempio " P1Y2M10DT2H30M ", con ulteriori informazioni contestuali

Se alcuni elementi mancano dal valore finale, si presume che siano gli stessi del valore iniziale incluso il fuso orario. Questa caratteristica dello standard consente rappresentazioni concise di intervalli di tempo. Ad esempio, la data di una riunione di due ore compresi gli orari di inizio e fine potrebbe essere semplicemente indicata come "2007-12-14T13: 30/15: 30", dove "/ 15: 30" implica "/ 2007-12- 14T15: 30 "(la stessa data dell'inizio) o le date di inizio e fine di un periodo di fatturazione mensile come" 2008-02-15/03-14 ", dove"/03-14 "implica"/2008-03 -14 "(lo stesso anno dell'inizio).

Inoltre, gli intervalli di ripetizione si formano aggiungendo "R [n] /" all'inizio di un'espressione di intervallo, dove R viene utilizzato come lettera stessa e [n] viene sostituito dal numero di ripetizioni. Tralasciando il valore di [n] si intende un numero illimitato di ripetizioni. Quindi, per ripetere l'intervallo di "P1Y2M10DT2H30M" cinque volte a partire da "2008-03-01T13: 00: 00Z", utilizzare "R5/2008-03-01T13: 00: 00Z/P1Y2M10DT2H30M".

Sto cercando un buon parser Java (se possibile compatibile con la libreria Joda-Time) per analizzare questa sintassi. Qualche suggerimento per una buona biblioteca?

risposta

8

Immagino che tu abbia già provato Joda-Time? L'alimentazione delle stringhe di esempio dalla tua domanda tramite Interval.parse(Object) rivela che può gestire "inizio e fine", "inizio e durata" e "durata e fine", ma non campi impliciti né ripetizioni.

2007-03-01T13:00:00Z/2008-05-11T15:30:00Z => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z 
2007-03-01T13:00:00Z/P1Y2M10DT2H30M  => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z 
P1Y2M10DT2H30M/2008-05-11T15:30:00Z  => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z 
2007-12-14T13:30/15:30     => java.lang.IllegalArgumentException: Invalid format: "15:30" is malformed at ":30" 
R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M => java.lang.IllegalArgumentException: Invalid format: "R5" 

L'unica altra libreria completa di data/ora, che io sappia è JSR-310, che non sembra per gestire intervalli di come questi.

A questo punto, costruire i propri miglioramenti in cima a Joda-Time è probabilmente la scelta migliore, mi dispiace. Esistono formati di intervallo ISO specifici che è necessario gestire oltre a quelli già supportati da Joda-Time?

+0

Grazie Barend. La documentazione di Joda-Time era davvero scarsa su questa capacità. Sono contento di vedere che supportano questo formato. Userò Joda. – fellahst

+2

Non riesco a votare fino a quando non ottengo 15 punti, ma non appena li ottengo :) – fellahst

10

Per chiunque in un progetto che potrebbe essere limitato dall'utilizzo di librerie di terze parti (motivi di licenza o altro), Java fornisce almeno una parte di questa funzionalità, dal momento che Java 1.6 (o precedente?), Utilizzando il metodo javax.xml.datatype.DatatypeFactory.newDuration(String) e Duration classe. Il metodo DatatypeFactory.newDuration (String) analizzerà una stringa nel formato "PnYnMnDTnHnMnS". Queste classi sono destinate alla manipolazione XML, ma poiché XML utilizza la notazione ISO 8601, esse servono anche come utility di analisi della durata conveniente.

Esempio:

import javax.xml.datatype.*; 

Duration dur = DatatypeFactory.newInstance().newDuration("PT5H12M36S"); 
int hours = dur.getHours(); // Should return 5 

non ho usato personalmente qualsiasi formato di durata, tranne il 4 ° quello di avere una lista, quindi non posso garantire per se li analizza con successo o no.

+0

Per questo esempio ho ottenuto un'eccezione: 'java.lang.IllegalArgumentException: PT5h12m36s \t su com.sun.org.apache.xerces .internal.jaxp.datatype.DurationImpl.organizeParts (DurationImpl.java:612) ' – takacsot

+1

@takacsot Avevi ragione! La "m" e la "s" nella stringa di esempio erano minuscole e avrebbero dovuto essere maiuscole per soddisfare le specifiche ISO 8601. Fisso. –

16

java.tempo

Il quadro java.time integrato in Java 8 e successivamente ha un metodo Duration.parse per l'analisi di un ISO 8601 formatted duration:

java.time.Duration d = java.time.Duration.parse("PT1H2M34S"); 
System.out.println("Duration in seconds: " + d.get(java.time.temporal.ChronoUnit.SECONDS)); 

stampe Duration in seconds: 3754

+2

Inoltre, i lettori potrebbero essere interessati alla classe ['Interval'] (http://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/Interval.html) offerta nel [ThreeTen-Extra] (http://www.threeten.org/threeten-extra/) progetto. Quel progetto estende java.time, scritto dagli stessi ragazzi. Quel progetto funge anche da terreno di prova per eventuali future aggiunte a java.time. La classe 'Interval' definisce un intervallo di tempo come una coppia di oggetti [' Instant'] (http://docs.oracle.com/javase/8/docs/api/java/time/Instant.html). La classe analizza le stringhe ISO 8601 come "" 2007-03-01T13: 00: 00Z/2008-05-11T15: 30: 00Z "'. –

+4

Sfortunatamente java.time distingue tra durate (basate sul tempo) e Periodi (basati sulla data) e quindi né Duration.parse(), né Period.parse() possono gestire il quarto caso ("P1Y2M10DT2H30M") –

6

l'unica biblioteca che è in grado di modello tutte le caratteristiche di intervallo parsing you want è in realtà la mia libreria Time4J (range-module). Esempi:

// case 1 (start/end) 
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/2014-06-20T16:00Z")); 
// output: [2012-01-01T14:15:00Z/2014-06-20T16:00:00Z) 

// case 1 (with some elements missing at end component and different offset) 
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/08-11T16:00+00:01")); 
// output: [2012-01-01T14:15:00Z/2012-08-11T15:59:00Z) 

// case 1 (with missing date and offset at end component) 
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/16:00")); 
// output: [2012-01-01T14:15:00Z/2012-01-01T16:00:00Z) 

// case 2 (start/duration) 
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/P2DT1H45M")); 
// output: [2012-01-01T14:15:00Z/2012-01-03T16:00:00Z) 

// case 3 (duration/end) 
System.out.println(MomentInterval.parseISO("P2DT1H45M/2012-01-01T14:15Z")); 
// output: [2011-12-30T12:30:00Z/2012-01-01T14:15:00Z) 

// case 4 (duration only, in standard ISO-format) 
Duration<IsoUnit> isoDuration = Duration.parsePeriod("P2DT1H45M"); 

// case 4 (duration only, in alternative representation) 
Duration<IsoUnit> isoDuration = Duration.parsePeriod("P0000-01-01T15:00"); 
System.out.println(isoDuration); // output: P1M1DT15H 

Alcune osservazioni:

  • Altre classi di intervalli esistono con funzionalità di analisi simili, per esempio DateInterval o TimestampInterval nel pacchetto net.time4j.range.

  • Solo per la gestione delle durate (che possono comprendere anche le unità di calendario e di orologio), vedere anche javadoc. Esistono anche funzioni di formattazione, vedere la classe nidificata Duration.Formatter o la versione localizzata net.time4j.PrettyTime (in realtà in 86 lingue).

  • L'interoperabilità è offerta con Java-8 (java.time -package) ma non con Joda-Time. Ad esempio: il componente iniziale o finale di un MomentInterval può essere interrogato facilmente da getStartAsInstant() o getEndAsInstant().

Gli intervalli di ripetizione sono supportati dalla classe IsoRecurrence. Esempio:

IsoRecurrence<MomentInterval> ir = 
    IsoRecurrence.parseMomentIntervals("R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M"); 
ir.intervalStream().forEach(System.out::println); 

uscita:

[2008-03-01T13:00:00Z/2009-05-11T15:30:00Z) 
[2009-05-11T15:30:00Z/2010-07-21T18:00:00Z) 
[2010-07-21T18:00:00Z/2011-10-01T20:30:00Z) 
[2011-10-01T20:30:00Z/2012-12-11T23:00:00Z) 
[2012-12-11T23:00:00Z/2014-02-22T01:30:00Z)