1
|
package eu.dnetlib.utils;
|
2
|
|
3
|
import java.math.RoundingMode;
|
4
|
import java.text.DateFormat;
|
5
|
import java.text.FieldPosition;
|
6
|
import java.text.NumberFormat;
|
7
|
import java.text.ParseException;
|
8
|
import java.text.ParsePosition;
|
9
|
import java.util.Calendar;
|
10
|
import java.util.Date;
|
11
|
import java.util.regex.Matcher;
|
12
|
import java.util.regex.Pattern;
|
13
|
|
14
|
/**
|
15
|
* This class implements a date format conforming to RFC-3339.
|
16
|
* @author thanos@di.uoa.gr
|
17
|
*
|
18
|
*/
|
19
|
public class RFC3339DateFormat extends DateFormat {
|
20
|
private static final long serialVersionUID = 1L;
|
21
|
|
22
|
private final NumberFormat twoDigits;
|
23
|
private final NumberFormat threeDigits;
|
24
|
private final NumberFormat fourDigits;
|
25
|
private final Pattern pattern;
|
26
|
|
27
|
/**
|
28
|
* Construct a new RFC-3339 date format.
|
29
|
*/
|
30
|
public RFC3339DateFormat() {
|
31
|
calendar = Calendar.getInstance();
|
32
|
twoDigits = NumberFormat.getIntegerInstance();
|
33
|
twoDigits.setGroupingUsed(false);
|
34
|
twoDigits.setRoundingMode(RoundingMode.UNNECESSARY);
|
35
|
twoDigits.setMaximumIntegerDigits(2);
|
36
|
twoDigits.setMinimumIntegerDigits(2);
|
37
|
threeDigits = NumberFormat.getIntegerInstance();
|
38
|
threeDigits.setGroupingUsed(false);
|
39
|
threeDigits.setRoundingMode(RoundingMode.UNNECESSARY);
|
40
|
threeDigits.setMaximumIntegerDigits(3);
|
41
|
threeDigits.setMinimumIntegerDigits(3);
|
42
|
fourDigits = NumberFormat.getIntegerInstance();
|
43
|
fourDigits.setGroupingUsed(false);
|
44
|
fourDigits.setRoundingMode(RoundingMode.UNNECESSARY);
|
45
|
fourDigits.setMaximumIntegerDigits(4);
|
46
|
fourDigits.setMinimumIntegerDigits(4);
|
47
|
pattern = Pattern.compile("^(\\d{4})\\-(\\d{2})\\-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{3})(Z|\\+(\\d{2}):(\\d{2})|\\-(\\d{2}):(\\d{2}))$");
|
48
|
}
|
49
|
|
50
|
@Override
|
51
|
public StringBuffer format(final Date date, final StringBuffer toAppendTo, final FieldPosition fieldPosition) {
|
52
|
calendar.setTime(date);
|
53
|
final int beginIndex = toAppendTo.length();
|
54
|
toAppendTo.append(fourDigits.format(calendar.get(Calendar.YEAR)));
|
55
|
toAppendTo.append("-");
|
56
|
toAppendTo.append(twoDigits.format(calendar.get(Calendar.MONTH) + 1));
|
57
|
toAppendTo.append("-");
|
58
|
toAppendTo.append(twoDigits.format(calendar.get(Calendar.DAY_OF_MONTH)));
|
59
|
toAppendTo.append("T");
|
60
|
toAppendTo.append(twoDigits.format(calendar.get(Calendar.HOUR_OF_DAY)));
|
61
|
toAppendTo.append(":");
|
62
|
toAppendTo.append(twoDigits.format(calendar.get(Calendar.MINUTE)));
|
63
|
toAppendTo.append(":");
|
64
|
toAppendTo.append(twoDigits.format(calendar.get(Calendar.SECOND)));
|
65
|
toAppendTo.append(".");
|
66
|
toAppendTo.append(threeDigits.format(calendar.get(Calendar.MILLISECOND)));
|
67
|
final int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
|
68
|
if (offset == 0)
|
69
|
toAppendTo.append("Z");
|
70
|
else {
|
71
|
toAppendTo.append((offset > 0) ? "+" : "-");
|
72
|
toAppendTo.append(twoDigits.format(offset / 3600000)); // convert milliseconds to hours
|
73
|
toAppendTo.append(":");
|
74
|
toAppendTo.append(twoDigits.format((offset % 3600000) / 60000)); // convert remaining milliseconds to minutes
|
75
|
}
|
76
|
switch (fieldPosition.getField()) {
|
77
|
case DateFormat.YEAR_FIELD:
|
78
|
fieldPosition.setBeginIndex(beginIndex);
|
79
|
fieldPosition.setEndIndex(beginIndex + 4);
|
80
|
break;
|
81
|
case DateFormat.MONTH_FIELD:
|
82
|
fieldPosition.setBeginIndex(beginIndex + 5);
|
83
|
fieldPosition.setEndIndex(beginIndex + 7);
|
84
|
break;
|
85
|
case DateFormat.DATE_FIELD:
|
86
|
fieldPosition.setBeginIndex(beginIndex + 8);
|
87
|
fieldPosition.setEndIndex(beginIndex + 10);
|
88
|
break;
|
89
|
case DateFormat.HOUR_OF_DAY0_FIELD:
|
90
|
fieldPosition.setBeginIndex(beginIndex + 11);
|
91
|
fieldPosition.setEndIndex(beginIndex + 13);
|
92
|
break;
|
93
|
case DateFormat.MINUTE_FIELD:
|
94
|
fieldPosition.setBeginIndex(beginIndex + 14);
|
95
|
fieldPosition.setEndIndex(beginIndex + 16);
|
96
|
break;
|
97
|
case DateFormat.SECOND_FIELD:
|
98
|
fieldPosition.setBeginIndex(beginIndex + 17);
|
99
|
fieldPosition.setEndIndex(beginIndex + 19);
|
100
|
break;
|
101
|
case DateFormat.MILLISECOND_FIELD:
|
102
|
fieldPosition.setBeginIndex(beginIndex + 20);
|
103
|
fieldPosition.setEndIndex(beginIndex + 23);
|
104
|
case DateFormat.TIMEZONE_FIELD:
|
105
|
fieldPosition.setBeginIndex(beginIndex + 23);
|
106
|
fieldPosition.setEndIndex(toAppendTo.length());
|
107
|
}
|
108
|
return toAppendTo;
|
109
|
}
|
110
|
|
111
|
@Override
|
112
|
public Date parse(final String source, final ParsePosition parsePosition) {
|
113
|
Matcher matcher = pattern.matcher(source.substring(parsePosition.getIndex()));
|
114
|
if (!matcher.matches()) {
|
115
|
parsePosition.setErrorIndex(parsePosition.getIndex());
|
116
|
return null;
|
117
|
}
|
118
|
try {
|
119
|
calendar.set(Calendar.YEAR, fourDigits.parse(matcher.group(1)).intValue());
|
120
|
calendar.set(Calendar.MONTH, twoDigits.parse(matcher.group(2)).intValue() - 1);
|
121
|
calendar.set(Calendar.DAY_OF_MONTH, twoDigits.parse(matcher.group(3)).intValue());
|
122
|
calendar.set(Calendar.HOUR_OF_DAY, twoDigits.parse(matcher.group(4)).intValue());
|
123
|
calendar.set(Calendar.MINUTE, twoDigits.parse(matcher.group(5)).intValue());
|
124
|
calendar.set(Calendar.SECOND, twoDigits.parse(matcher.group(6)).intValue());
|
125
|
calendar.set(Calendar.MILLISECOND, threeDigits.parse(matcher.group(7)).intValue());
|
126
|
if (matcher.group(8).equals("Z"))
|
127
|
calendar.set(Calendar.ZONE_OFFSET, 0);
|
128
|
else if (matcher.group(8).startsWith("+"))
|
129
|
calendar.set(Calendar.ZONE_OFFSET, (twoDigits.parse(matcher.group(9)).intValue() * 60 + twoDigits.parse(matcher.group(10)).intValue()) * 60000);
|
130
|
else if (matcher.group(8).startsWith("-"))
|
131
|
calendar.set(Calendar.ZONE_OFFSET, -((twoDigits.parse(matcher.group(11)).intValue() * 60 + twoDigits.parse(matcher.group(12)).intValue()) * 60000));
|
132
|
calendar.set(Calendar.DST_OFFSET, 0);
|
133
|
parsePosition.setIndex(parsePosition.getIndex() + matcher.group(0).length());
|
134
|
return new Date(calendar.getTimeInMillis());
|
135
|
} catch (ParseException e) {
|
136
|
parsePosition.setErrorIndex(parsePosition.getIndex() + e.getErrorOffset());
|
137
|
return null;
|
138
|
}
|
139
|
}
|
140
|
}
|