001 /*
002 * The MIT License
003 *
004 * Copyright (c) 2013, 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
025 package com.ninja_squad.dbsetup.generator;
026
027 import com.ninja_squad.dbsetup.util.Preconditions;
028
029 import javax.annotation.Nonnull;
030 import java.sql.Timestamp;
031 import java.util.Calendar;
032 import java.util.Date;
033 import java.util.TimeZone;
034
035 /**
036 * A {@link ValueGenerator} that returns a sequence of dates, starting at a given date and incremented by a given
037 * time, specified as an increment and a calendar field.
038 * @author JB
039 */
040 public final class DateSequenceValueGenerator implements ValueGenerator<Date> {
041
042 // the number of chars in yyyy-mm-dd hh:mm:ss
043 private static final int MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP = 19;
044
045 /**
046 * The available units for the increment of this sequence
047 */
048 public enum CalendarField {
049 YEAR(Calendar.YEAR),
050 MONTH(Calendar.MONTH),
051 DAY(Calendar.DATE),
052 HOUR(Calendar.HOUR),
053 MINUTE(Calendar.MINUTE),
054 SECOND(Calendar.SECOND),
055 MILLISECOND(Calendar.MILLISECOND);
056
057 private int field;
058
059 CalendarField(int field) {
060 this.field = field;
061 }
062
063 private int getField() {
064 return field;
065 }
066 }
067
068 private Calendar next;
069 private int increment;
070 private CalendarField unit;
071
072 DateSequenceValueGenerator() {
073 this(today(), 1, CalendarField.DAY);
074 }
075
076 private DateSequenceValueGenerator(Calendar next, int increment, CalendarField unit) {
077 this.next = next;
078 this.increment = increment;
079 this.unit = unit;
080 }
081
082 private static Calendar today() {
083 Calendar result = Calendar.getInstance();
084 result.set(Calendar.HOUR_OF_DAY, 0);
085 result.set(Calendar.MINUTE, 0);
086 result.set(Calendar.SECOND, 0);
087 result.set(Calendar.MILLISECOND, 0);
088 return result;
089 }
090
091 /**
092 * Restarts the sequence at the given date, in the given time zone
093 * @return this instance, for chaining
094 */
095 public DateSequenceValueGenerator startingAt(@Nonnull Date startDate, @Nonnull TimeZone timeZone) {
096 Preconditions.checkNotNull(startDate, "startDate may not be null");
097 Preconditions.checkNotNull(timeZone, "timeZone may not be null");
098 next = Calendar.getInstance(timeZone);
099 next.setTime(startDate);
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 */
107 public DateSequenceValueGenerator startingAt(@Nonnull Date startDate) {
108 return startingAt(startDate, TimeZone.getDefault());
109 }
110
111 /**
112 * Restarts the sequence at the given date
113 * @return this instance, for chaining
114 */
115 public DateSequenceValueGenerator startingAt(@Nonnull Calendar startDate) {
116 Preconditions.checkNotNull(startDate, "startDate may not be null");
117 next = (Calendar) startDate.clone();
118 return this;
119 }
120
121 /**
122 * Restarts the sequence at the given date, in the default time zone
123 * @param startDate the starting date, as a String. The supported formats are the same as the ones supported by
124 * {@link com.ninja_squad.dbsetup.bind.Binders#timestampBinder()}, i.e. the formats supported by
125 * <code>java.sql.Timestamp.valueOf()</code> and <code>java.sql.Date.valueOf()</code>
126 * @return this instance, for chaining
127 */
128 public DateSequenceValueGenerator startingAt(@Nonnull String startDate) {
129 Preconditions.checkNotNull(startDate, "startDate may not be null");
130 if (startDate.length() >= MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP) {
131 return startingAt(Timestamp.valueOf(startDate));
132 }
133 else {
134 return startingAt(java.sql.Date.valueOf(startDate));
135 }
136 }
137
138 /**
139 * Increments the date by the given increment of the given unit.
140 * @return this instance, for chaining
141 */
142 public DateSequenceValueGenerator incrementingBy(int increment, @Nonnull CalendarField unit) {
143 Preconditions.checkNotNull(unit, "unit may not be null");
144 this.increment = increment;
145 this.unit = unit;
146 return this;
147 }
148
149 @Override
150 public Date nextValue() {
151 Date result = next.getTime();
152 next.add(unit.getField(), increment);
153 return result;
154 }
155
156 @Override
157 public String toString() {
158 return "DateSequenceValueGenerator["
159 + "next=" + next
160 + ", increment=" + increment
161 + ", unit=" + unit
162 + "]";
163 }
164 }