2014-12-04 2 views
7

Как разбирать ZoneDateTime из строки, которая не содержит zone и других полей?Как разобрать ZonedDateTime с зоной по умолчанию?

Вот тест на Спока воспроизвести:

import spock.lang.Specification 
import spock.lang.Unroll 

import java.time.ZoneId 
import java.time.ZoneOffset 
import java.time.ZonedDateTime 
import java.time.format.DateTimeFormatter 

@Unroll 
class ZonedDateTimeParsingSpec extends Specification { 
    def "DateTimeFormatter.ISO_ZONED_DATE_TIME parsing incomplete date: #value #expected"() { 
     expect: 
     ZonedDateTime.parse(value, DateTimeFormatter.ISO_ZONED_DATE_TIME) == expected 
     where: 
     value       | expected 
     '2014-04-23T04:30:45.123Z'  | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneOffset.UTC) 
     '2014-04-23T04:30:45.123+01:00' | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneOffset.ofHours(1)) 
     '2014-04-23T04:30:45.123'  | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneId.systemDefault()) 
     '2014-04-23T04:30'    | ZonedDateTime.of(2014, 4, 23, 4, 30, 0, 0, ZoneId.systemDefault()) 
     '2014-04-23'     | ZonedDateTime.of(2014, 4, 23, 0, 0, 0, 0, ZoneId.systemDefault()) 
    } 
} 

Первые два испытания прошли все другие потерпели неудачу с DateTimeParseException:

  • '2014-04-23T04: 30: 45,123' не может быть анализируется с индексом 23
  • «2014-04-23T04: 30» не может быть разобранной с индексом 16
  • «2014-04-23» не может быть проанализирован с индексом 10

Как я могу разобрать неполные даты со временем и зоной, установленной по умолчанию?

ответ

11

Поскольку форматер ISO_ZONED_DATE_TIME ожидает информацию о зоне или смещении, синтаксический анализ не выполняется. Вам нужно будет сделать DateTimeFormatter, который имеет дополнительные детали как для информации о зоне, так и для временной части. Это не слишком сложное обратное проектирование ZonedDateTimeFormatter и добавление дополнительных тегов.

Затем вы разобрали String, используя метод форматирования parseBest(). Затем для субоптимальных результатов синтаксического анализа вы можете создать ZonedDateTime, используя любой желаемый по умолчанию.

DateTimeFormatter formatter = new DateTimeFormatterBuilder() 
     .parseCaseInsensitive() 
     .append(ISO_LOCAL_DATE) 
     .optionalStart()   // time made optional 
     .appendLiteral('T') 
     .append(ISO_LOCAL_TIME) 
     .optionalStart()   // zone and offset made optional 
     .appendOffsetId() 
     .optionalStart() 
     .appendLiteral('[') 
     .parseCaseSensitive() 
     .appendZoneRegionId() 
     .appendLiteral(']') 
     .optionalEnd() 
     .optionalEnd() 
     .optionalEnd() 
     .toFormatter(); 

TemporalAccessor temporalAccessor = formatter.parseBest(value, ZonedDateTime::from, LocalDateTime::from, LocalDate::from); 
if (temporalAccessor instanceof ZonedDateTime) { 
    return ((ZonedDateTime) temporalAccessor); 
} 
if (temporalAccessor instanceof LocalDateTime) { 
    return ((LocalDateTime) temporalAccessor).atZone(ZoneId.systemDefault()); 
} 
return ((LocalDate) temporalAccessor).atStartOfDay(ZoneId.systemDefault()); 
+0

Спасибо, это выглядит лучше, но не решает проблему:

 Caused by: java.time.DateTimeException: Unable to obtain ZoneId from TemporalAccessor: {},ISO resolved to 2014-04-23T04:30:45.123 of type java.time.format.Parsed 
Таким образом, он не раз, потому что я не могу установить Часовой пояс по умолчанию для парсера. То же самое для других частей, для даты показа. Например, как можно проанализировать строку типа «23: 45» в ZonedDateTime с текущей датой и системным часовым поясом? – stokito

+0

Он отлично работал с использованием java 8u25 для всех 5 примерной строки в вопросе. Итак, не уверен, в чем проблема. – bowmore

+1

Проблема в том, что я хотел бы получить ZonedDateTime insted из LocalDateTime – stokito

8

Форматирование имеет withZone()method, который может быть вызван для обеспечения отсутствующей временной зоны.

ZonedDateTime.parse(
    value, 
    DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(ZoneId.systemDefault())) 

Имейте в виду, что произошла ошибка, поэтому вам нужно 8u20 или более поздней версии, чтобы она полностью работала.

+0

, что, кажется, не работает (пробовал с 8u25) – bowmore

+0

Метод 'withZone()' всегда перекрывает зону, даже если она содержит в строку – stokito

+0

@stokito: проблема возникает на строках, которые не имеют никакой информации зоны в анализироваться. – bowmore

Смежные вопросы