1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.rolling.helper;
15
16 import java.text.SimpleDateFormat;
17 import java.util.Calendar;
18 import java.util.Date;
19 import java.util.GregorianCalendar;
20 import java.util.Locale;
21 import java.util.TimeZone;
22
23 import ch.qos.logback.core.CoreConstants;
24 import ch.qos.logback.core.spi.ContextAwareBase;
25
26
27
28
29
30
31
32
33
34 public class RollingCalendar extends GregorianCalendar {
35
36 private static final long serialVersionUID = -5937537740925066161L;
37
38
39 static final TimeZone GMT_TIMEZONE = TimeZone.getTimeZone("GMT");
40
41 PeriodicityType periodicityType = PeriodicityType.ERRONEOUS;
42
43 public RollingCalendar() {
44 super();
45 }
46
47 public RollingCalendar(TimeZone tz, Locale locale) {
48 super(tz, locale);
49 }
50
51 public void init(String datePattern) {
52 periodicityType = computePeriodicityType(datePattern);
53 }
54
55 private void setPeriodicityType(PeriodicityType periodicityType) {
56 this.periodicityType = periodicityType;
57 }
58
59 public PeriodicityType getPeriodicityType() {
60 return periodicityType;
61 }
62
63 public long getNextTriggeringMillis(Date now) {
64 return getNextTriggeringDate(now).getTime();
65 }
66
67
68
69
70
71
72
73
74
75 public PeriodicityType computePeriodicityType(String datePattern) {
76 RollingCalendar rollingCalendar = new RollingCalendar(GMT_TIMEZONE, Locale
77 .getDefault());
78
79
80 Date epoch = new Date(0);
81
82 if (datePattern != null) {
83 for (PeriodicityType i : PeriodicityType.VALID_ORDERED_LIST) {
84 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
85 simpleDateFormat.setTimeZone(GMT_TIMEZONE);
86
87
88 String r0 = simpleDateFormat.format(epoch);
89 rollingCalendar.setPeriodicityType(i);
90
91 Date next = new Date(rollingCalendar.getNextTriggeringMillis(epoch));
92 String r1 = simpleDateFormat.format(next);
93
94
95 if ((r0 != null) && (r1 != null) && !r0.equals(r1)) {
96 return i;
97 }
98 }
99 }
100
101 return PeriodicityType.ERRONEOUS;
102 }
103
104 public void printPeriodicity(ContextAwareBase cab) {
105 switch (periodicityType) {
106 case TOP_OF_MILLISECOND:
107 cab.addInfo("Roll-over every millisecond.");
108 break;
109
110 case TOP_OF_SECOND:
111 cab.addInfo("Roll-over every second.");
112 break;
113
114 case TOP_OF_MINUTE:
115 cab.addInfo("Roll-over every minute.");
116 break;
117
118 case TOP_OF_HOUR:
119 cab.addInfo("Roll-over at the top of every hour.");
120 break;
121
122 case HALF_DAY:
123 cab.addInfo("Roll-over at midday and midnight.");
124 break;
125
126 case TOP_OF_DAY:
127 cab.addInfo("Roll-over at midnight.");
128 break;
129
130 case TOP_OF_WEEK:
131 cab.addInfo("Rollover at the start of week.");
132 break;
133
134 case TOP_OF_MONTH:
135 cab.addInfo("Rollover at start of every month.");
136 break;
137
138 default:
139 cab.addInfo("Unknown periodicity.");
140 }
141 }
142
143 public long periodsElapsed(long start, long end) {
144 if (start > end)
145 throw new IllegalArgumentException("Start cannot come before end");
146
147 long diff = end - start;
148 switch (periodicityType) {
149
150 case TOP_OF_MILLISECOND:
151 return diff;
152 case TOP_OF_SECOND:
153 return diff / CoreConstants.MILLIS_IN_ONE_SECOND;
154 case TOP_OF_MINUTE:
155 return diff / CoreConstants.MILLIS_IN_ONE_MINUTE;
156 case TOP_OF_HOUR:
157 return (int) diff / CoreConstants.MILLIS_IN_ONE_HOUR;
158 case TOP_OF_DAY:
159 return diff / CoreConstants.MILLIS_IN_ONE_DAY;
160 case TOP_OF_WEEK:
161 return diff / CoreConstants.MILLIS_IN_ONE_WEEK;
162 case TOP_OF_MONTH:
163 return diffInMonths(start, end);
164 default:
165 throw new IllegalStateException("Unknown periodicity type.");
166 }
167 }
168
169 public static int diffInMonths(long startTime, long endTime) {
170 if (startTime > endTime)
171 throw new IllegalArgumentException("startTime cannot be larger than endTime");
172 Calendar startCal = Calendar.getInstance();
173 startCal.setTimeInMillis(startTime);
174 Calendar endCal = Calendar.getInstance();
175 endCal.setTimeInMillis(endTime);
176 int yearDiff = endCal.get(Calendar.YEAR) - startCal.get(Calendar.YEAR);
177 int monthDiff = endCal.get(Calendar.MONTH) - startCal.get(Calendar.MONTH);
178 return yearDiff * 12 + monthDiff;
179 }
180
181 public Date getRelativeDate(Date now, int periods) {
182 this.setTime(now);
183
184 switch (periodicityType) {
185 case TOP_OF_MILLISECOND:
186 this.add(Calendar.MILLISECOND, periods);
187 break;
188
189 case TOP_OF_SECOND:
190 this.set(Calendar.MILLISECOND, 0);
191 this.add(Calendar.SECOND, periods);
192 break;
193
194 case TOP_OF_MINUTE:
195 this.set(Calendar.SECOND, 0);
196 this.set(Calendar.MILLISECOND, 0);
197 this.add(Calendar.MINUTE, periods);
198 break;
199
200 case TOP_OF_HOUR:
201 this.set(Calendar.MINUTE, 0);
202 this.set(Calendar.SECOND, 0);
203 this.set(Calendar.MILLISECOND, 0);
204 this.add(Calendar.HOUR_OF_DAY, periods);
205 break;
206
207 case TOP_OF_DAY:
208 this.set(Calendar.HOUR_OF_DAY, 0);
209 this.set(Calendar.MINUTE, 0);
210 this.set(Calendar.SECOND, 0);
211 this.set(Calendar.MILLISECOND, 0);
212 this.add(Calendar.DATE, periods);
213 break;
214
215 case TOP_OF_WEEK:
216 this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
217 this.set(Calendar.HOUR_OF_DAY, 0);
218 this.set(Calendar.MINUTE, 0);
219 this.set(Calendar.SECOND, 0);
220 this.set(Calendar.MILLISECOND, 0);
221 this.add(Calendar.WEEK_OF_YEAR, periods);
222 break;
223
224 case TOP_OF_MONTH:
225 this.set(Calendar.DATE, 1);
226 this.set(Calendar.HOUR_OF_DAY, 0);
227 this.set(Calendar.MINUTE, 0);
228 this.set(Calendar.SECOND, 0);
229 this.set(Calendar.MILLISECOND, 0);
230 this.add(Calendar.MONTH, periods);
231 break;
232
233 default:
234 throw new IllegalStateException("Unknown periodicity type.");
235 }
236
237 return getTime();
238 }
239
240 public Date getNextTriggeringDate(Date now) {
241 return getRelativeDate(now, 1);
242 }
243 }