1 |
12936
|
thanos.pap
|
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 |
14031
|
thanos.pap
|
* This class implements a date format conforming to RFC-3339.
|
16 |
12936
|
thanos.pap
|
* @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 |
14031
|
thanos.pap
|
* Construct a new RFC-3339 date format.
|
29 |
12936
|
thanos.pap
|
*/
|
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 |
14031
|
thanos.pap
|
toAppendTo.append(twoDigits.format(offset / 3600000)); // convert milliseconds to hours
|
73 |
12936
|
thanos.pap
|
toAppendTo.append(":");
|
74 |
14031
|
thanos.pap
|
toAppendTo.append(twoDigits.format((offset % 3600000) / 60000)); // convert remaining milliseconds to minutes
|
75 |
12936
|
thanos.pap
|
}
|
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 |
|
|
}
|