Project

General

Profile

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
}
(6-6/7)