blob: 084a4b2f6ec486644f4226ef9c37a250886881ec [file] [log] [blame]
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
// * with the License. You may obtain a copy of the License at *
// * *
// * http://www.apache.org/licenses/LICENSE-2.0 *
// * *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
package org.apache.juneau.transforms;
import static java.time.temporal.ChronoField.*;
import static java.time.temporal.TemporalQueries.*;
import java.time.*;
import java.time.format.*;
import java.time.temporal.*;
/**
* Wraps a {@link TemporalAccessor} to provide default values wherever possible instead of throwing unsupported field exceptions.
*
* <p>
* If working correctly, any <c>TemporalAccessor</c> returned by the {@link DateTimeFormatter#parse(CharSequence)} method
* should be able to be passed to any <code>Temporal.from(TemporalAccessor)</code> static method (such as {@link ZonedDateTime#from(TemporalAccessor)}).
*/
public class DefaultingTemporalAccessor implements TemporalAccessor {
private final TemporalAccessor inner;
private final ZoneId zoneId;
private ZonedDateTime zdt;
/**
* Constructor.
*
* @param inner The temporal accessor being wrapped.
* @param zoneId The default zone ID if it's not specified in the accessor.
*/
public DefaultingTemporalAccessor(TemporalAccessor inner, ZoneId zoneId) {
this.inner = inner;
this.zoneId = zoneId;
}
@Override /* TemporalAccessor */
public boolean isSupported(TemporalField field) {
return inner.isSupported(field);
}
@Override /* TemporalAccessor */
@SuppressWarnings("unchecked")
public <R> R query(TemporalQuery<R> query) {
R r = inner.query(query);
if (r != null)
return r;
if (query == zone() || query == zoneId())
return (R)zoneId;
if (query == localTime()) {
if (isSupported(INSTANT_SECONDS))
return (R)zdt().toLocalTime();
int hour = 0;
if (isSupported(HOUR_OF_DAY))
hour = iget(HOUR_OF_DAY);
else if (isSupported(HOUR_OF_AMPM))
hour = iget(HOUR_OF_AMPM) + 12 * iget(AMPM_OF_DAY);
int minute = isSupported(MINUTE_OF_HOUR) ? iget(MINUTE_OF_HOUR) : 0;
int second = isSupported(SECOND_OF_MINUTE) ? iget(SECOND_OF_MINUTE) : 0;
int nano = isSupported(NANO_OF_SECOND) ? iget(NANO_OF_SECOND) : 0;
return (R)LocalTime.of(hour, minute, second, nano);
}
if (query == localDate()) {
if (isSupported(INSTANT_SECONDS))
return (R)zdt().toLocalDate();
int year = isSupported(YEAR) ? iget(ChronoField.YEAR) : 1970;
int month = isSupported(MONTH_OF_YEAR) ? iget(MONTH_OF_YEAR) : 1;
int dayOfMonth = isSupported(DAY_OF_MONTH) ? iget(DAY_OF_MONTH) : 1;
return (R)LocalDate.of(year, Month.of(month), dayOfMonth);
}
if (query == offset()) {
return (R)zoneId.getRules().getOffset(zdt().toInstant());
}
return null;
}
@Override /* TemporalAccessor */
public long getLong(TemporalField field) {
if (isSupported(field))
return inner.getLong(field);
if (field == INSTANT_SECONDS)
return zdt().toEpochSecond();
if (field == EPOCH_DAY)
return zdt().toLocalDate().toEpochDay();
if (field == YEAR) {
if (isSupported(INSTANT_SECONDS))
return zdt().toLocalDate().getYear();
return 1970;
}
if (field == MONTH_OF_YEAR) {
if (isSupported(INSTANT_SECONDS))
return zdt().toLocalDate().getMonthValue();
return 1;
}
return 0;
}
@Override /* TemporalAccessor */
public int get(TemporalField field) {
if (inner.isSupported(field))
return inner.get(field);
return (int)getLong(field);
}
private int iget(TemporalField field) {
return inner.get(field);
}
private ZonedDateTime zdt() {
if (zdt == null)
zdt = ZonedDateTime.from(this);
return zdt;
}
}