1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.archive.wayback.util;
21
22 import java.text.ParseException;
23 import java.util.Calendar;
24 import java.util.Date;
25 import java.util.Locale;
26 import java.util.Map;
27 import java.util.TimeZone;
28
29 import org.archive.util.ArchiveUtils;
30
31
32
33
34
35
36
37
38 public class Timestamp {
39
40 private final static String LOWER_TIMESTAMP_LIMIT = "10000000000000";
41 private final static String UPPER_TIMESTAMP_LIMIT = "29991939295959";
42 private final static String YEAR_DEFAULT_LOWER_LIMIT = "1996";
43 private static String YEAR_LOWER_LIMIT;
44 private final static String MONTH_LOWER_LIMIT = "01";
45 private final static String MONTH_UPPER_LIMIT = "12";
46 private final static String DAY_LOWER_LIMIT = "01";
47 private final static String HOUR_UPPER_LIMIT = "23";
48 private final static String HOUR_LOWER_LIMIT = "00";
49 private final static String MINUTE_UPPER_LIMIT = "59";
50 private final static String MINUTE_LOWER_LIMIT = "00";
51 private final static String SECOND_UPPER_LIMIT = "59";
52 private final static String SECOND_LOWER_LIMIT = "00";
53
54
55
56 private final static int SSE_YEAR_LOWER_LIMIT;
57
58 private final static String[] months = new String[12];
59
60 static {
61
62
63 YEAR_LOWER_LIMIT = System.getProperty("wayback.timestamp.startyear", YEAR_DEFAULT_LOWER_LIMIT);
64
65 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
66 cal.set(Integer.parseInt(YEAR_LOWER_LIMIT), 0, 1, 0, 0, 0);
67 SSE_YEAR_LOWER_LIMIT = (int)(cal.getTimeInMillis() / 1000);
68
69
70 Map <String, Integer> month = cal.getDisplayNames(Calendar.MONTH, Calendar.SHORT, Locale.getDefault());
71 for (String s:month.keySet()) {
72 months[month.get(s)] = s;
73 }
74 }
75
76 private String dateStr = null;
77 private Date date = null;
78
79
80
81
82 public Timestamp() {
83 }
84
85
86
87
88
89
90
91 public Timestamp(final String dateStr) {
92 setDate(dateStrToDate(dateStr));
93 }
94
95
96
97
98
99
100 public Timestamp(final int sse) {
101 setSse(sse);
102 }
103
104
105
106
107
108 public Timestamp(final Date date) {
109 setDate(date);
110 }
111
112
113
114
115
116 public final void setDate(final Date date) {
117 this.date = (Date) date.clone();
118 dateStr = ArchiveUtils.get14DigitDate(date);
119 }
120
121
122
123
124
125 public Date getDate() {
126 return date;
127 }
128
129
130
131
132
133 public final void setSse(final int sse) {
134 setDate(new Date(((long)sse) * 1000));
135 }
136
137
138
139
140
141
142
143
144 public void setDateStr(String dateStr) {
145 setDate(dateStrToDate(dateStr));
146 }
147
148
149
150
151
152 public String getDateStr() {
153 return dateStr;
154 }
155
156
157
158
159
160 public int sse() {
161 return Math.round(date.getTime() / 1000);
162 }
163
164
165
166
167
168
169
170
171
172
173 public int absDistanceFromTimestamp(final Timestamp otherTimeStamp) {
174 return Math.abs(distanceFromTimestamp(otherTimeStamp));
175 }
176
177
178
179
180
181
182
183
184
185
186 public int distanceFromTimestamp(final Timestamp otherTimeStamp) {
187 return otherTimeStamp.sse() - sse();
188 }
189
190
191
192
193 public String getYear() {
194 return this.dateStr.substring(0, 4);
195 }
196
197
198
199
200 public String getMonth() {
201 return this.dateStr.substring(4, 6);
202 }
203
204
205
206
207 public String getDay() {
208 return this.dateStr.substring(6, 8);
209 }
210
211
212
213
214
215 public String prettyDate() {
216 String year = dateStr.substring(0, 4);
217 String month = dateStr.substring(4, 6);
218 String day = dateStr.substring(6, 8);
219 int monthInt = Integer.parseInt(month) - 1;
220 String prettyMonth = "UNK";
221 if ((monthInt >= 0) && (monthInt < months.length)) {
222 prettyMonth = months[monthInt];
223 }
224 return prettyMonth + " " + day + ", " + year;
225 }
226
227
228
229
230
231 public String prettyTime() {
232 return dateStr.substring(8, 10) + ":" + dateStr.substring(10, 12) + ":"
233 + dateStr.substring(12, 14);
234 }
235
236
237
238
239
240 public String prettyDateTime() {
241 return prettyDate() + " " + prettyTime();
242 }
243
244
245
246
247
248
249
250 private static String getDaysInMonthBound(int year, int month) {
251 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
252 cal.set(Calendar.YEAR, year);
253 cal.set(Calendar.MONTH, month);
254 return new Integer(cal.getActualMaximum(Calendar.DAY_OF_MONTH)).toString();
255 }
256
257
258
259
260
261 public static Calendar dateStrToCalendar(final String dateStr) {
262 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
263 String paddedDateStr = padStartDateStr(dateStr);
264
265 int iYear = Integer.parseInt(paddedDateStr.substring(0,4));
266 int iMonth = Integer.parseInt(paddedDateStr.substring(4,6));
267 int iDay = Integer.parseInt(paddedDateStr.substring(6,8));
268 int iHour = Integer.parseInt(paddedDateStr.substring(8,10));
269 int iMinute = Integer.parseInt(paddedDateStr.substring(10,12));
270 int iSecond = Integer.parseInt(paddedDateStr.substring(12,14));
271
272 cal.set(Calendar.YEAR,iYear);
273 cal.set(Calendar.MONTH,iMonth - 1);
274 cal.set(Calendar.DAY_OF_MONTH,iDay);
275 cal.set(Calendar.HOUR_OF_DAY,iHour);
276 cal.set(Calendar.MINUTE,iMinute);
277 cal.set(Calendar.SECOND,iSecond);
278 cal.set(Calendar.MILLISECOND,0);
279
280 return cal;
281 }
282
283
284
285
286
287
288
289
290 public static Date dateStrToDate(final String dateStr) {
291
292 String paddedDateStr = padStartDateStr(dateStr);
293 try {
294 return ArchiveUtils.parse14DigitDate(paddedDateStr);
295 } catch (ParseException e) {
296 e.printStackTrace();
297
298
299 return new Date((long)SSE_YEAR_LOWER_LIMIT * 1000);
300 }
301 }
302
303 private static String padDigits(String input, String min, String max,
304 String missing) {
305 if(input == null) {
306 input = "";
307 }
308 StringBuilder finalDigits = new StringBuilder();
309
310 for(int i = 0; i < missing.length(); i++) {
311 if(input.length() <= i) {
312 finalDigits.append(missing.charAt(i));
313 } else {
314 char inc = input.charAt(i);
315 char maxc = max.charAt(i);
316 char minc = min.charAt(i);
317 if(inc > maxc) {
318 inc = maxc;
319 } else if (inc < minc) {
320 inc = minc;
321 }
322 finalDigits.append(inc);
323 }
324 }
325
326 return finalDigits.toString();
327 }
328
329 private static String boundDigits(final String test, final String min,
330 final String max) {
331 if(test.compareTo(min) < 0) {
332 return min;
333 } else if(test.compareTo(max) > 0) {
334 return max;
335 }
336 return test;
337 }
338
339
340
341
342 private static String boundTimestamp(String input) {
343 StringBuilder boundTimestamp = new StringBuilder();
344
345 if (input == null) {
346 input = "";
347 }
348
349 boundTimestamp.append(boundDigits(input.substring(0,4),
350 YEAR_LOWER_LIMIT,
351 String.valueOf(Calendar.getInstance(TimeZone.getTimeZone("GMT")).get(Calendar.YEAR) )));
352
353
354 boundTimestamp.append(boundDigits(input.substring(4,6),
355 MONTH_LOWER_LIMIT,MONTH_UPPER_LIMIT));
356
357
358
359 int iYear = Integer.parseInt(boundTimestamp.substring(0,4));
360 int iMonth = Integer.parseInt(boundTimestamp.substring(4,6));
361 String maxDayOfMonth = getDaysInMonthBound(iYear, iMonth-1);
362
363 boundTimestamp.append(boundDigits(input.substring(6,8),
364 DAY_LOWER_LIMIT,maxDayOfMonth));
365
366
367 boundTimestamp.append(boundDigits(input.substring(8,10),
368 HOUR_LOWER_LIMIT,HOUR_UPPER_LIMIT));
369
370
371 boundTimestamp.append(boundDigits(input.substring(10,12),
372 MINUTE_LOWER_LIMIT,MINUTE_UPPER_LIMIT));
373
374
375 boundTimestamp.append(boundDigits(input.substring(12,14),
376 SECOND_LOWER_LIMIT,SECOND_UPPER_LIMIT));
377
378 return boundTimestamp.toString();
379 }
380
381
382
383
384
385
386
387 public static String padEndDateStr(String timestamp) {
388 return boundTimestamp(padDigits(timestamp,LOWER_TIMESTAMP_LIMIT,
389 UPPER_TIMESTAMP_LIMIT,UPPER_TIMESTAMP_LIMIT));
390 }
391
392
393
394
395
396
397
398 public static String padStartDateStr(String timestamp) {
399 return boundTimestamp(padDigits(timestamp,LOWER_TIMESTAMP_LIMIT,
400 UPPER_TIMESTAMP_LIMIT,LOWER_TIMESTAMP_LIMIT));
401 }
402
403
404
405
406
407
408 public static Timestamp parseBefore(final String dateStr) {
409 return new Timestamp(padStartDateStr(dateStr));
410 }
411
412
413
414
415
416
417 public static Timestamp parseAfter(final String dateStr) {
418 return new Timestamp(padEndDateStr(dateStr));
419 }
420
421
422
423
424
425 public static Timestamp fromSse(final int sse) {
426
427 return new Timestamp(sse);
428 }
429
430
431
432
433 public static Timestamp currentTimestamp() {
434 return new Timestamp(new Date());
435 }
436
437
438
439
440 public static Timestamp latestTimestamp() {
441 return currentTimestamp();
442 }
443
444
445
446
447 public static Timestamp earliestTimestamp() {
448 return new Timestamp(SSE_YEAR_LOWER_LIMIT);
449 }
450
451
452
453
454
455 public void setStartYear(int year) {
456 YEAR_LOWER_LIMIT = Integer.toString(year);
457 }
458
459
460
461
462 public static int getStartYear() {
463 return Integer.parseInt(YEAR_LOWER_LIMIT);
464 }
465
466
467
468
469 public static int getEndYear() {
470 return Calendar.getInstance(TimeZone.getTimeZone("GMT")).get(Calendar.YEAR);
471 }
472 }