2014-10-15 10 views
10

Ho un semplice problema: Voglio analizzare le stringhe Java nel formato "yyyyMMdd" rigorosamente, in modo che "19800229" sia una data valida, ma non lo è "19820229". Si supponga che queste siano date AD del normale calendario gregoriano.Utilizzo del nuovo DateTimeFormatter Java 8 per eseguire un'analisi rigorosa della data

Sto cercando di utilizzare il nuovo pacchetto java.time da JDK 8 per risolvere questo problema, ma si sta dimostrando più complicato di quanto sperato. Il mio codice attuale è:

private static final DateTimeFormatter FORMAT = DateTimeFormatter 
     .ofPattern("yyyyMMdd").withChronology(IsoChronology.INSTANCE) 
     .withResolverStyle(STRICT); 

public static LocalDate parse(String yyyyMMdd) { 
    return LocalDate.parse(yyyyMMdd, FORMAT); 
} 

Tuttavia, l'analisi di una data valida, ad esempio "19.800.228" produce ciò che per me è un errore incomprensibile:

java.time.format.DateTimeParseException: Text '19820228' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {MonthOfYear=2, DayOfMonth=28, YearOfEra=1982},ISO of type java.time.format.Parsed

Come faccio ad usare java.time.format.DateTimeFormatter per risolvere il mio semplice caso d'uso ?

risposta

2

Sto modificando per limitare il tipo di stringa che sarà considerata valida utilizzando un formattatore personalizzato creato con DateTimeFormatterBuilder.

public class DateFormmaterTest { 

    static DateTimeFormatter CUSTOM_BASIC_ISO_DATE = new DateTimeFormatterBuilder() 
      .parseCaseInsensitive().appendValue(YEAR, 4) 
      .appendValue(MONTH_OF_YEAR, 2).appendValue(DAY_OF_MONTH, 2) 
      .optionalStart().toFormatter() 
      .withResolverStyle(ResolverStyle.STRICT) 
      .withChronology(IsoChronology.INSTANCE); 

    public static void main(String[] args) { 

     LocalDate date1 = LocalDate.parse("19800228-5000", 
       CUSTOM_BASIC_ISO_DATE); 

     System.out.println(date1); 

    } 
} 

2/29/1982 non è valido e getterebbe la seguente:

Caused by: java.time.DateTimeException: Invalid date 'February 29' as '1982' is not a leap year 
    at java.time.LocalDate.create(LocalDate.java:429) 

Una data di 19.800.228-5.000 avrebbe funzionato con BASIC_ISO_DATE perché permette opzionale fronte dei quali non si desidera permesso . Il mio CUSTOM_BASIC_ISO_DATE formattatore non permetterà che e gettare il seguente:

Exception in thread "main" java.time.format.DateTimeParseException: Text '19800228-5000' could not be parsed, unparsed text found at index 8. 

nota, se si è sicuri della lunghezza della stringa, aaaaMMgg allora si potrebbe sempre lavorare con la stringa di primi 8 caratteri per negare la necessità di resolver . Tuttavia questo è due cose diverse. Il resolver contrassegna i formati di data non validi sull'input e la sottostringa ovviamente eliminerebbe solo i caratteri extra.

+0

Grazie @Tech Trip. Scusate volevo dire 2/29 in entrambi i casi, come hai sottolineato. Il motivo per cui evito 'DateTimeFormatter.BASIC_ISO_DATE' è che ha una parte facoltativa che non voglio essere analizzabile. Posso creare un formattatore equivalente senza la parte opzionale? – 0xbe5077ed

+0

Ho modificato la risposta per tenere conto del tuo ultimo commento. Si prega di dare un'occhiata! – TechTrip

+0

Abbastanza buono, @Tech Trip. È quello che ho scoperto anche io. Nota che puoi rimuovere "parseCaseInsensitive()" - non necessario perché yyyyMMdd non ha problemi di maiuscole e 'startOptional()' perché non stai iniziando nulla di opzionale. – 0xbe5077ed

1

Provare a utilizzare il formato "uuuuMMdd".

12

Java 8 utilizza uuuu per anno, non yyyy. In Java 8, yyyy significa "anno dell'era" (BC o AD) e il messaggio di errore si riferisce che MonthOfYear, DayOfMonth e YearOfEra non sono informazioni sufficienti per costruire la data perché l'era non è nota.

Per risolvere il problema, utilizzare uuuu nella stringa di formato, ad es. DateTimeFormatter.ofPattern("uuuuMMdd")

Oppure, se si desidera continuare a utilizzare yyyy, è possibile impostare l'era predefinita, ad es.

new DateTimeFormatterBuilder() 
     .appendPattern("yyyyMMdd") 
     .parseDefaulting(ChronoField.ERA, 1 /* era is AD */) 
     .toFormatter() 
Problemi correlati