001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package org.gbif.common.parsers.date; 015 016import java.time.temporal.ChronoField; 017import java.time.temporal.TemporalAccessor; 018import java.util.Objects; 019 020import org.apache.commons.lang3.builder.HashCodeBuilder; 021import org.apache.commons.lang3.builder.ToStringBuilder; 022import org.apache.commons.lang3.builder.ToStringStyle; 023 024/** 025 * AtomizedLocalDate is a simple immutable class to hold local date data from a 026 * {@link TemporalAccessor}. 027 * 028 * Thread-Safe, immutable class. 029 */ 030public class AtomizedLocalDate { 031 032 // Maximum resolution for a complete Local Date 033 public static final int COMPLETE_LOCAL_DATE_RESOLUTION = 3; 034 035 private final Integer year; 036 private final Integer month; 037 private final Integer day; 038 039 private final int resolution; 040 041 private AtomizedLocalDate(Integer year, Integer month, Integer day) { 042 this.year = year; 043 this.month = month; 044 this.day = day; 045 046 int res = 0; 047 if (year != null) { 048 res++; 049 } 050 if (month != null) { 051 res++; 052 } 053 if (day != null) { 054 res++; 055 } 056 resolution = res; 057 } 058 059 /** 060 * Build a new instance of {@link AtomizedLocalDate} based on a {@link TemporalAccessor}. 061 * This is done by extracting the {@link ChronoField}. 062 * @param temporalAccessor 063 * @return 064 */ 065 public static AtomizedLocalDate fromTemporalAccessor(TemporalAccessor temporalAccessor) { 066 if (temporalAccessor == null) { 067 return null; 068 } 069 070 Integer y = null, m = null, d = null; 071 if (temporalAccessor.isSupported(ChronoField.YEAR)) { 072 y = temporalAccessor.get(ChronoField.YEAR); 073 } 074 075 if (temporalAccessor.isSupported(ChronoField.MONTH_OF_YEAR)) { 076 m = temporalAccessor.get(ChronoField.MONTH_OF_YEAR); 077 } 078 079 if (temporalAccessor.isSupported(ChronoField.DAY_OF_MONTH)) { 080 d = temporalAccessor.get(ChronoField.DAY_OF_MONTH); 081 } 082 083 return new AtomizedLocalDate(y, m, d); 084 } 085 086 public Integer getYear() { 087 return year; 088 } 089 090 public Integer getMonth() { 091 return month; 092 } 093 094 public Integer getDay() { 095 return day; 096 } 097 098 public int getResolution() { 099 return resolution; 100 } 101 102 /** 103 * Is the resolution of this local date matches the maximum. 104 * @return 105 */ 106 public boolean isComplete() { 107 return COMPLETE_LOCAL_DATE_RESOLUTION == resolution; 108 } 109 110 @Override 111 public int hashCode() { 112 return new HashCodeBuilder().append(year).append(month).append(day).append(resolution).toHashCode(); 113 } 114 115 @Override 116 public boolean equals(Object o) { 117 if (this == o) { 118 return true; 119 } 120 if (!(o instanceof AtomizedLocalDate)) { 121 return false; 122 } 123 124 AtomizedLocalDate that = (AtomizedLocalDate) o; 125 126 return resolution == that.resolution 127 && Objects.equals(year, that.year) 128 && Objects.equals(month, that.month) 129 && Objects.equals(day, that.day); 130 } 131 132 @Override 133 public String toString() { 134 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 135 .append("year", year) 136 .append("month", month) 137 .append("day", day) 138 .append("resolution", resolution) 139 .toString(); 140 } 141}