001/* 002 * The MIT License 003 * 004 * Copyright (c) 2013-2016, Ninja Squad 005 * 006 * Permission is hereby granted, free of charge, to any person obtaining a copy 007 * of this software and associated documentation files (the "Software"), to deal 008 * in the Software without restriction, including without limitation the rights 009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 * copies of the Software, and to permit persons to whom the Software is 011 * furnished to do so, subject to the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be included in 014 * all copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 022 * THE SOFTWARE. 023 */ 024 025package com.ninja_squad.dbsetup.generator; 026 027import javax.annotation.Nonnull; 028import java.sql.Timestamp; 029import java.time.LocalDate; 030import java.time.LocalDateTime; 031import java.time.ZoneId; 032import java.time.ZonedDateTime; 033import java.time.temporal.ChronoUnit; 034import java.time.temporal.TemporalUnit; 035import java.util.Calendar; 036import java.util.Date; 037import java.util.TimeZone; 038 039import com.ninja_squad.dbsetup.util.Preconditions; 040 041/** 042 * A {@link ValueGenerator} that returns a sequence of dates, starting at a given zoned date time and incremented by a 043 * given time, specified as an increment and a temporal unit. 044 * @author JB 045 */ 046public final class DateSequenceValueGenerator implements ValueGenerator<ZonedDateTime> { 047 048 // the number of chars in yyyy-mm-dd hh:mm:ss 049 private static final int MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP = 19; 050 051 /** 052 * The available units for the increment of this sequence 053 * @deprecated use ChronoField instead. This enum is only kept to maintain backward compatibility 054 */ 055 @Deprecated 056 public enum CalendarField { 057 YEAR(ChronoUnit.YEARS), 058 MONTH(ChronoUnit.MONTHS), 059 DAY(ChronoUnit.DAYS), 060 HOUR(ChronoUnit.HOURS), 061 MINUTE(ChronoUnit.MINUTES), 062 SECOND(ChronoUnit.SECONDS), 063 MILLISECOND(ChronoUnit.MILLIS); 064 065 private TemporalUnit unit; 066 067 CalendarField(TemporalUnit unit) { 068 this.unit = unit; 069 } 070 071 private TemporalUnit toTemporalUnit() { 072 return unit; 073 } 074 } 075 076 private ZonedDateTime next; 077 private int increment; 078 private TemporalUnit unit; 079 080 DateSequenceValueGenerator() { 081 this(LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()), 1, ChronoUnit.DAYS); 082 } 083 084 private DateSequenceValueGenerator(ZonedDateTime next, int increment, TemporalUnit unit) { 085 this.next = next; 086 this.increment = increment; 087 this.unit = unit; 088 } 089 090 /** 091 * Restarts the sequence at the given date, in the given time zone 092 * @return this instance, for chaining 093 * @deprecated use one of the other <code>startingAt()</code> methods taking java.time types as argument 094 */ 095 @Deprecated 096 public DateSequenceValueGenerator startingAt(@Nonnull Date startDate, @Nonnull TimeZone timeZone) { 097 Preconditions.checkNotNull(startDate, "startDate may not be null"); 098 Preconditions.checkNotNull(timeZone, "timeZone may not be null"); 099 next = startDate.toInstant().atZone(timeZone.toZoneId()); 100 return this; 101 } 102 103 /** 104 * Restarts the sequence at the given date, in the default time zone 105 * @return this instance, for chaining 106 * @deprecated use one of the other <code>startingAt()</code> methods taking java.time types as argument 107 */ 108 @Deprecated 109 public DateSequenceValueGenerator startingAt(@Nonnull Date startDate) { 110 return startingAt(startDate, TimeZone.getDefault()); 111 } 112 113 /** 114 * Restarts the sequence at the given date 115 * @return this instance, for chaining 116 * @deprecated use one of the other <code>startingAt()</code> methods taking java.time types as argument 117 */ 118 @Deprecated 119 public DateSequenceValueGenerator startingAt(@Nonnull Calendar startDate) { 120 Preconditions.checkNotNull(startDate, "startDate may not be null"); 121 next = startDate.toInstant().atZone(startDate.getTimeZone().toZoneId()); 122 return this; 123 } 124 125 /** 126 * Restarts the sequence at the given date, in the default time zone 127 * @param startDate the starting date, as a String. The supported formats are the same as the ones supported by 128 * {@link com.ninja_squad.dbsetup.bind.Binders#timestampBinder()}, i.e. the formats supported by 129 * <code>java.sql.Timestamp.valueOf()</code> and <code>java.sql.Date.valueOf()</code> 130 * @return this instance, for chaining 131 */ 132 public DateSequenceValueGenerator startingAt(@Nonnull String startDate) { 133 Preconditions.checkNotNull(startDate, "startDate may not be null"); 134 if (startDate.length() >= MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP) { 135 return startingAt(new Date(Timestamp.valueOf(startDate).getTime())); 136 } 137 else { 138 return startingAt(new Date(java.sql.Date.valueOf(startDate).getTime())); 139 } 140 } 141 142 /** 143 * Restarts the sequence at the given local date, in the default time zone 144 * @return this instance, for chaining 145 */ 146 public DateSequenceValueGenerator startingAt(@Nonnull LocalDate startDate) { 147 return startingAt(startDate.atStartOfDay()); 148 } 149 150 /** 151 * Restarts the sequence at the given local date time, in the default time zone 152 * @return this instance, for chaining 153 */ 154 public DateSequenceValueGenerator startingAt(@Nonnull LocalDateTime startDate) { 155 return startingAt(startDate.atZone(ZoneId.systemDefault())); 156 } 157 158 /** 159 * Restarts the sequence at the given zoned date time 160 * @return this instance, for chaining 161 */ 162 public DateSequenceValueGenerator startingAt(@Nonnull ZonedDateTime startDate) { 163 next = startDate; 164 return this; 165 } 166 167 /** 168 * Increments the date by the given increment of the given unit. 169 * @return this instance, for chaining 170 * @deprecated use the other {@link #incrementingBy(int, TemporalUnit)} method 171 */ 172 @Deprecated 173 public DateSequenceValueGenerator incrementingBy(int increment, @Nonnull CalendarField unit) { 174 Preconditions.checkNotNull(unit, "unit may not be null"); 175 return incrementingBy(increment, unit.toTemporalUnit()); 176 } 177 178 /** 179 * Increments the date by the given increment of the given unit. One of the constants of ChronoField is typically 180 * used for the unit. 181 * @return this instance, for chaining 182 */ 183 public DateSequenceValueGenerator incrementingBy(int increment, @Nonnull TemporalUnit unit) { 184 Preconditions.checkNotNull(unit, "unit may not be null"); 185 this.increment = increment; 186 this.unit = unit; 187 return this; 188 } 189 190 @Override 191 public ZonedDateTime nextValue() { 192 ZonedDateTime result = next; 193 next = next.plus(increment, unit); 194 return result; 195 } 196 197 @Override 198 public String toString() { 199 return "DateSequenceValueGenerator[" 200 + "next=" + next 201 + ", increment=" + increment 202 + ", unit=" + unit 203 + "]"; 204 } 205}