001/* 002 * Copyright 2019 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.core.util.date; 017 018import java.time.LocalDate; 019import java.time.LocalDateTime; 020import java.time.temporal.TemporalUnit; 021 022/** 023 * This represents an advanced {@link LocalDateTime}, allowing to be a static one, 024 * or a relative one to the moment the {@link #resolveDateTime} method is called. 025 * <br>A single instance of {@link AdaptableDate} can be {@link #resolveDateTime() resolved} mutliple times, without being a problem at all, it just can lead to different results. 026 * <br> 027 * <br>You can get an {@link AdaptableDate} with: 028 * <ul> 029 * <li>{@link #fromDateTime} to have a static one, always resolved as the same given {@link LocalDateTime}</li> 030 * <li>{@link #fromDate} to have a static one, always resolved as the same given {@link LocalDate} (at the start of the day)</li> 031 * <li> {@link #now} to have one resolved as the current {@link LocalDateTime} when {@link #resolveDateTime} is called</li> 032 * <li> {@link #future} to have one resolved with the given amount of given {@link TemporalUnit} added to the current {@link LocalDateTime} when {@link #resolveDateTime} is called</li> 033 * <li> {@link #past} to have one resolved with the given amount of given {@link TemporalUnit} subtracted to the current {@link LocalDateTime} when {@link #resolveDateTime} is called</li> 034 * </ul> 035 */ 036public final class AdaptableDate 037{ 038 private static enum AdaptableDateType 039 { 040 STATIC, 041 RELATIVE_TO_NOW, 042 } 043 044 private static enum OffsetType 045 { 046 NOW, 047 PAST, 048 FUTURE, 049 } 050 051 private static final AdaptableDate __NOW = new AdaptableDate(OffsetType.NOW, 0, null); 052 053 private final AdaptableDateType _type; 054 private final LocalDateTime _staticValue; 055 private final TemporalUnit _relativeUnit; 056 private final long _relativeAmount; 057 private final OffsetType _relativeOffsetType; 058 059 private AdaptableDate(LocalDateTime date) 060 { 061 _type = AdaptableDateType.STATIC; 062 _staticValue = date; 063 _relativeUnit = null; 064 _relativeAmount = 0; 065 _relativeOffsetType = null; 066 } 067 068 private AdaptableDate(OffsetType offsetType, long amount, TemporalUnit unit) 069 { 070 _type = AdaptableDateType.RELATIVE_TO_NOW; 071 _staticValue = null; 072 _relativeUnit = unit; 073 _relativeAmount = amount; 074 _relativeOffsetType = offsetType; 075 } 076 077 /** 078 * Gets a static {@link AdaptableDate}, always resolved as the given {@link LocalDateTime} 079 * @param dateTime The {@link LocalDateTime} 080 * @return The {@link AdaptableDate} 081 */ 082 public static AdaptableDate fromDateTime(LocalDateTime dateTime) 083 { 084 return new AdaptableDate(dateTime); 085 } 086 087 /** 088 * Gets a static {@link AdaptableDate}, always resolved as the given {@link LocalDate} 089 * @param date The {@link LocalDate} 090 * @return The {@link AdaptableDate} 091 */ 092 public static AdaptableDate fromDate(LocalDate date) 093 { 094 return new AdaptableDate(date.atStartOfDay()); 095 } 096 097 /** 098 * Gets an {@link AdaptableDate}, resolved as the current {@link LocalDateTime} at the moment of the {@link #resolveDateTime() call} 099 * @return The {@link AdaptableDate} 100 */ 101 public static AdaptableDate now() 102 { 103 return __NOW; 104 } 105 106 /** 107 * Gets an {@link AdaptableDate}, resolved as the current {@link LocalDateTime} at the moment of the {@link #resolveDateTime() call}, 108 * minus the given amount of the given {@link TemporalUnit}, so as to get a {@link LocalDateTime} in the past 109 * @param amount The amount to subtract 110 * @param unit The {@link TemporalUnit} of the amount to subtract 111 * @return The {@link AdaptableDate} 112 */ 113 public static AdaptableDate past(long amount, TemporalUnit unit) 114 { 115 return new AdaptableDate(OffsetType.PAST, amount, unit); 116 } 117 118 /** 119 * Gets an {@link AdaptableDate}, resolved as the current {@link LocalDateTime} at the moment of the {@link #resolveDateTime() call}, 120 * plus the given amount of the given {@link TemporalUnit}, so as to get a {@link LocalDateTime} in the future 121 * @param amount The amount to add 122 * @param unit The {@link TemporalUnit} of the amount to add 123 * @return The {@link AdaptableDate} 124 */ 125 public static AdaptableDate future(long amount, TemporalUnit unit) 126 { 127 return new AdaptableDate(OffsetType.FUTURE, amount, unit); 128 } 129 130 /** 131 * Resolves this {@link AdaptableDate} 132 * @return The resolved {@link LocalDateTime} 133 */ 134 public LocalDateTime resolveDateTime() 135 { 136 switch (_type) 137 { 138 case RELATIVE_TO_NOW: 139 LocalDateTime now = LocalDateTime.now(); 140 LocalDateTime computed; 141 switch (_relativeOffsetType) 142 { 143 case NOW: 144 computed = now; 145 break; 146 case PAST: 147 computed = now.minus(_relativeAmount, _relativeUnit); 148 break; 149 case FUTURE: 150 default: 151 computed = now.plus(_relativeAmount, _relativeUnit); 152 break; 153 } 154 return computed; 155 156 case STATIC: 157 default: 158 return _staticValue; 159 } 160 } 161 162 /** 163 * Resolves this {@link AdaptableDate} 164 * @return The resolved {@link LocalDate} 165 */ 166 public LocalDate resolveDate() 167 { 168 return resolveDateTime() 169 .toLocalDate(); 170 } 171 172 @Override 173 public String toString() 174 { 175 switch (_type) 176 { 177 case STATIC: 178 return _staticValue.toString(); 179 case RELATIVE_TO_NOW: 180 default: 181 switch (_relativeOffsetType) 182 { 183 case NOW: 184 return "Now"; 185 case PAST: 186 return _relativeAmount + " " + _relativeUnit + " ago"; 187 case FUTURE: 188 default: 189 return "In " + _relativeAmount + " " + _relativeUnit; 190 } 191 } 192 } 193} 194