001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.fcrepo.search.impl; 019 020import java.time.Instant; 021import java.time.ZoneOffset; 022import java.time.format.DateTimeFormatter; 023import java.time.format.DateTimeFormatterBuilder; 024import java.time.temporal.ChronoField; 025import java.util.ArrayList; 026import java.util.List; 027 028import static java.time.format.DateTimeFormatter.ISO_DATE_TIME; 029import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; 030import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; 031 032/** 033 * A utility class for parsing a variety of different date/time formats into an Instant. 034 * 035 * @author dbernstein 036 */ 037public class InstantParser { 038 039 private static final List<DateTimeFormatter> VALID_DATE_FORMATS = new ArrayList<>(); 040 041 static { 042 VALID_DATE_FORMATS.add(ISO_DATE_TIME); 043 VALID_DATE_FORMATS.add(ISO_OFFSET_DATE_TIME); 044 VALID_DATE_FORMATS.add(RFC_1123_DATE_TIME); 045 final var zoneId = ZoneOffset.UTC; 046 VALID_DATE_FORMATS.add(new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd") 047 .parseDefaulting(ChronoField.NANO_OF_DAY, 0).toFormatter().withZone(zoneId)); 048 VALID_DATE_FORMATS.add(new DateTimeFormatterBuilder().appendPattern("yyyyMMdd") 049 .parseDefaulting(ChronoField.NANO_OF_DAY, 0).toFormatter().withZone(zoneId)); 050 VALID_DATE_FORMATS.add(new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss") 051 .parseDefaulting(ChronoField.NANO_OF_DAY, 0).toFormatter().withZone(zoneId)); 052 VALID_DATE_FORMATS.add(new DateTimeFormatterBuilder().appendPattern("yyyyMMdd HH:mm:ss") 053 .parseDefaulting(ChronoField.NANO_OF_DAY, 0).toFormatter().withZone(zoneId)); 054 } 055 056 private InstantParser() { } 057 058 /** 059 * Parse a datestring into an instant. If timezone or time information is missing, UTC is assumed. 060 * 061 * @param dateString The date string 062 * @return an instant 063 */ 064 public static Instant parse(final String dateString) { 065 for (final DateTimeFormatter formatter : VALID_DATE_FORMATS) { 066 try { 067 final var temporalAccessor = formatter.parse(dateString); 068 return Instant.from(temporalAccessor); 069 } catch (final Exception e) { 070 //ignore failures - if no date string is parsable, an error is thrown below 071 } 072 } 073 throw new IllegalArgumentException("Invalid date format: \"" + dateString + "\""); 074 } 075 076}