ISODateIO.java

1
/*
2
 * Copyright 2006 - 2013
3
 *     Stefan Balev     <stefan.balev@graphstream-project.org>
4
 *     Julien Baudry    <julien.baudry@graphstream-project.org>
5
 *     Antoine Dutot    <antoine.dutot@graphstream-project.org>
6
 *     Yoann Pign��      <yoann.pigne@graphstream-project.org>
7
 *     Guilhelm Savin   <guilhelm.savin@graphstream-project.org>
8
 * 
9
 * This file is part of GraphStream <http://graphstream-project.org>.
10
 * 
11
 * GraphStream is a library whose purpose is to handle static or dynamic
12
 * graph, create them from scratch, file or any source and display them.
13
 * 
14
 * This program is free software distributed under the terms of two licenses, the
15
 * CeCILL-C license that fits European law, and the GNU Lesser General Public
16
 * License. You can  use, modify and/ or redistribute the software under the terms
17
 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
18
 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
19
 * the Free Software Foundation, either version 3 of the License, or (at your
20
 * option) any later version.
21
 * 
22
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
23
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
24
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
25
 * 
26
 * You should have received a copy of the GNU Lesser General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 * 
29
 * The fact that you are presently reading this means that you have had
30
 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
31
 */
32
package org.graphstream.util.time;
33
34
import java.text.ParseException;
35
import java.util.Calendar;
36
import java.util.LinkedList;
37
import java.util.regex.Matcher;
38
import java.util.regex.Pattern;
39
40
import org.graphstream.util.time.ISODateComponent.TextComponent;
41
42
/**
43
 * Scanner for date in ISO/IEC 9899:1999 format. The scanner takes a format and
44
 * then is able to parse timestamp in the given format.
45
 * 
46
 * The <i>parse()</i> return a {@link java.util.Calendar} for convenience.
47
 * 
48
 * Format of the scanner can be composed of %? directive which define components
49
 * of the time. These directives are listed below. For example, the format
50
 * "%F %T", which is equivalent to "%Y-%m-%d %H:%M:%S" can parse the following
51
 * timestamp: "2010-12-09 03:45:39";
52
 * 
53
 * <dl>
54
 * <dt>%a</dt>
55
 * <dd>locale's abbreviated weekday name</dd>
56
 * <dt>%A</dt>
57
 * <dd>locale's weekday name</dd>
58
 * <dt>%b</dt>
59
 * <dd>locale's abbreviated month name</dd>
60
 * <dt>%B</dt>
61
 * <dd>locale's month name</dd>
62
 * <dt>%c</dt>
63
 * <dd>locale's date and time representation</dd>
64
 * <dt>%C</dt>
65
 * <dd>two first digits of full year as an integer (00-99)</dd>
66
 * <dt>%d</dt>
67
 * <dd>day of the month (01-31)</dd>
68
 * <dt>%D</dt>
69
 * <dd>%m/%d/%y</dd>
70
 * <dt>%e</dt>
71
 * <dd>day of the month (1-31)</dd>
72
 * <dt>%F</dt>
73
 * <dd>%Y-%m-%d</dd>
74
 * <dt>%g</dt>
75
 * <dd>last 2 digits of the week-based year (00-99)</dd>
76
 * <dt>%G</dt>
77
 * <dd>"week-based year as a decimal number</dd>
78
 * <dt>%h</dt>
79
 * <dd>%b</dd>
80
 * <dt>%H</dt>
81
 * <dd>hour (24-hour clock) as a decimal number (00-23)</dd>
82
 * <dt>%I</dt>
83
 * <dd>hour (12-hour clock) as a decimal number (01-12)</dd>
84
 * <dt>%j</dt>
85
 * <dd>day of the year as a decimal number (001-366)</dd>
86
 * <dt>%k</dt>
87
 * <dd>milliseconds as a decimal number (001-999)</dd>
88
 * <dt>%K</dt>
89
 * <dd>milliseconds since the epoch</dd>
90
 * <dt>%m</dt>
91
 * <dd>month as a decimal number (01-12)</dd>
92
 * <dt>%M</dt>
93
 * <dd>minute as a decimal number (00-59)</dd>
94
 * <dt>%n</dt>
95
 * <dd>\n</dd>
96
 * <dt>%p</dt>
97
 * <dd>locale-s equivalent of the AM/PM</dd>
98
 * <dt>%r</dt>
99
 * <dd>locale's 12-hour clock time</dd>
100
 * <dt>%R</dt>
101
 * <dd>%H:%M</dd>
102
 * <dt>%S</dt>
103
 * <dd>second as a decimal number (00-60)</dd>
104
 * <dt>%t</dt>
105
 * <dd>\t</dd>
106
 * <dt>%T</dt>
107
 * <dd>%H:%M:%S</dd>
108
 * <dt>%u</dt>
109
 * <dd>ISO 8601 weekday as a decimal number (1-7)</dd>
110
 * <dt>%U</dt>
111
 * <dd>week number of the year as a decimal number (00-53)</dd>
112
 * <dt>%V</dt>
113
 * <dd>ISO 8601 week number as a decimal number (01-53)</dd>
114
 * <dt>%w</dt>
115
 * <dd>weekday as a decimal number (0-6)</dd>
116
 * <dt>%W</dt>
117
 * <dd>week number of the year as a decimal number (00-53)</dd>
118
 * <dt>%x</dt>
119
 * <dd>locale's date representation</dd>
120
 * <dt>%X</dt>
121
 * <dd>locale's time representation</dd>
122
 * <dt>%y</dt>
123
 * <dd>last 2 digits of the year as a decimal number (00-99)</dd>
124
 * <dt>%Y</dt>
125
 * <dd>year as a decimal number</dd>
126
 * <dt>%z</dt>
127
 * <dd>offset from UTC in the ISO 8601 format</dd>
128
 * <dt>%Z</dt>
129
 * <dd>locale's time zone name of abbreviation or empty</dd>
130
 * </dl>
131
 * 
132
 * @author Guilhelm Savin
133
 */
134
public class ISODateIO {
135
136
	private static final ISODateComponent[] KNOWN_COMPONENTS = {
137
			ISODateComponent.ABBREVIATED_WEEKDAY_NAME,
138
			ISODateComponent.FULL_WEEKDAY_NAME,
139
			ISODateComponent.ABBREVIATED_MONTH_NAME,
140
			ISODateComponent.FULL_MONTH_NAME,
141
			ISODateComponent.LOCALE_DATE_AND_TIME, ISODateComponent.CENTURY,
142
			ISODateComponent.DAY_OF_MONTH_2_DIGITS, ISODateComponent.DATE,
143
			ISODateComponent.DAY_OF_MONTH, ISODateComponent.DATE_ISO8601,
144
			ISODateComponent.WEEK_BASED_YEAR_2_DIGITS,
145
			ISODateComponent.WEEK_BASED_YEAR_4_DIGITS,
146
			ISODateComponent.ABBREVIATED_MONTH_NAME_ALIAS,
147
			ISODateComponent.HOUR_OF_DAY, ISODateComponent.HOUR,
148
			ISODateComponent.DAY_OF_YEAR, ISODateComponent.MILLISECOND,
149
			ISODateComponent.EPOCH, ISODateComponent.MONTH,
150
			ISODateComponent.MINUTE, ISODateComponent.NEW_LINE,
151
			ISODateComponent.AM_PM, ISODateComponent.LOCALE_CLOCK_TIME_12_HOUR,
152
			ISODateComponent.HOUR_AND_MINUTE, ISODateComponent.SECOND,
153
			ISODateComponent.TABULATION, ISODateComponent.TIME_ISO8601,
154
			ISODateComponent.DAY_OF_WEEK_1_7,
155
			ISODateComponent.WEEK_OF_YEAR_FROM_SUNDAY,
156
			ISODateComponent.WEEK_NUMBER_ISO8601,
157
			ISODateComponent.DAY_OF_WEEK_0_6,
158
			ISODateComponent.WEEK_OF_YEAR_FROM_MONDAY,
159
			ISODateComponent.LOCALE_DATE_REPRESENTATION,
160
			ISODateComponent.LOCALE_TIME_REPRESENTATION,
161
			ISODateComponent.YEAR_2_DIGITS, ISODateComponent.YEAR_4_DIGITS,
162
			ISODateComponent.UTC_OFFSET,
163
			ISODateComponent.LOCALE_TIME_ZONE_NAME, ISODateComponent.PERCENT };
164
165
	/**
166
	 * List of components, build from a string format. Some of these components
167
	 * can just be text.
168
	 */
169
	protected LinkedList<ISODateComponent> components;
170
	/**
171
	 * The regular expression builds from the components.
172
	 */
173
	protected Pattern pattern;
174
175
	/**
176
	 * Create a scanner with default format "%K".
177
	 * 
178
	 * @throws ParseException
179
	 */
180
	public ISODateIO() throws ParseException {
181
		this("%K");
182
	}
183
184
	/**
185
	 * Create a new scanner with a given format.
186
	 * 
187
	 * @param format
188
	 *            format of the scanner.
189
	 * @throws ParseException
190
	 *             if bad directives found
191
	 */
192
	public ISODateIO(String format) throws ParseException {
193 1 1. : removed call to org/graphstream/util/time/ISODateIO::setFormat → NO_COVERAGE
		setFormat(format);
194
	}
195
196
	/**
197
	 * Get the current pattern used to parse timestamp.
198
	 * 
199
	 * @return a regular expression as a string
200
	 */
201
	public Pattern getPattern() {
202 1 1. getPattern : mutated return of Object value for org/graphstream/util/time/ISODateIO::getPattern to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
		return pattern;
203
	}
204
205
	/**
206
	 * Build a list of component from a string.
207
	 * 
208
	 * @param format
209
	 *            format of the scanner
210
	 * @return a list of components found in the string format
211
	 * @throws ParseException
212
	 *             if invalid component found
213
	 */
214
	protected LinkedList<ISODateComponent> findComponents(String format)
215
			throws ParseException {
216
		LinkedList<ISODateComponent> components = new LinkedList<ISODateComponent>();
217
		int offset = 0;
218
219 2 1. findComponents : changed conditional boundary → NO_COVERAGE
2. findComponents : negated conditional → NO_COVERAGE
		while (offset < format.length()) {
220 1 1. findComponents : negated conditional → NO_COVERAGE
			if (format.charAt(offset) == '%') {
221
				boolean found = false;
222 4 1. findComponents : changed conditional boundary → NO_COVERAGE
2. findComponents : Changed increment from 1 to -1 → NO_COVERAGE
3. findComponents : negated conditional → NO_COVERAGE
4. findComponents : negated conditional → NO_COVERAGE
				for (int i = 0; !found && i < KNOWN_COMPONENTS.length; i++) {
223
					if (format.startsWith(KNOWN_COMPONENTS[i].getDirective(),
224 1 1. findComponents : negated conditional → NO_COVERAGE
							offset)) {
225
						found = true;
226 1 1. findComponents : negated conditional → NO_COVERAGE
						if (KNOWN_COMPONENTS[i].isAlias()) {
227
							LinkedList<ISODateComponent> sub = findComponents(KNOWN_COMPONENTS[i]
228
									.getReplacement());
229
							components.addAll(sub);
230
						} else
231 1 1. findComponents : removed call to java/util/LinkedList::addLast → NO_COVERAGE
							components.addLast(KNOWN_COMPONENTS[i]);
232
233 1 1. findComponents : Replaced integer addition with subtraction → NO_COVERAGE
						offset += KNOWN_COMPONENTS[i].getDirective().length();
234
					}
235
				}
236 1 1. findComponents : negated conditional → NO_COVERAGE
				if (!found)
237
					throw new ParseException("unknown identifier", offset);
238
			} else {
239
				int from = offset;
240 3 1. findComponents : changed conditional boundary → NO_COVERAGE
2. findComponents : negated conditional → NO_COVERAGE
3. findComponents : negated conditional → NO_COVERAGE
				while (offset < format.length() && format.charAt(offset) != '%')
241 1 1. findComponents : Changed increment from 1 to -1 → NO_COVERAGE
					offset++;
242 1 1. findComponents : removed call to java/util/LinkedList::addLast → NO_COVERAGE
				components.addLast(new TextComponent(Pattern.quote(format
243
						.substring(from, offset))));
244
			}
245
		}
246
247 1 1. findComponents : mutated return of Object value for org/graphstream/util/time/ISODateIO::findComponents to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
		return components;
248
	}
249
250
	/**
251
	 * Build a regular expression from the components of the scanner.
252
	 */
253
	protected void buildRegularExpression() {
254
		String pattern = "";
255
256 3 1. buildRegularExpression : changed conditional boundary → NO_COVERAGE
2. buildRegularExpression : Changed increment from 1 to -1 → NO_COVERAGE
3. buildRegularExpression : negated conditional → NO_COVERAGE
		for (int i = 0; i < components.size(); i++) {
257
			Object c = components.get(i);
258
			String regexValue;
259 1 1. buildRegularExpression : negated conditional → NO_COVERAGE
			if (c instanceof ISODateComponent)
260
				regexValue = ((ISODateComponent) c).getReplacement();
261
			else
262
				regexValue = c.toString();
263
264
			pattern += "(" + regexValue + ")";
265
		}
266
267
		this.pattern = Pattern.compile(pattern);
268
	}
269
270
	/**
271
	 * Set the format of this scanner.
272
	 * 
273
	 * @param format
274
	 *            new format of the scanner
275
	 * @throws ParseException
276
	 *             if an error is found in the new format
277
	 */
278
	public void setFormat(String format) throws ParseException {
279
		components = findComponents(format);
280 1 1. setFormat : removed call to org/graphstream/util/time/ISODateIO::buildRegularExpression → NO_COVERAGE
		buildRegularExpression();
281
	}
282
283
	/**
284
	 * Parse a string which should be in the scanner format. If not, null is
285
	 * returned.
286
	 * 
287
	 * @param time
288
	 *            timestamp in the scanner format
289
	 * @return a calendar modeling the time value or null if invalid format
290
	 */
291
	public Calendar parse(String time) {
292
		Calendar cal = Calendar.getInstance();
293
		Matcher match = pattern.matcher(time);
294
295 1 1. parse : negated conditional → NO_COVERAGE
		if (match.matches()) {
296 3 1. parse : changed conditional boundary → NO_COVERAGE
2. parse : Changed increment from 1 to -1 → NO_COVERAGE
3. parse : negated conditional → NO_COVERAGE
			for (int i = 0; i < components.size(); i++)
297 2 1. parse : Replaced integer addition with subtraction → NO_COVERAGE
2. parse : removed call to org/graphstream/util/time/ISODateComponent::set → NO_COVERAGE
				components.get(i).set(match.group(i + 1), cal);
298
		} else
299 1 1. parse : mutated return of Object value for org/graphstream/util/time/ISODateIO::parse to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
			return null;
300
301 1 1. parse : mutated return of Object value for org/graphstream/util/time/ISODateIO::parse to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
		return cal;
302
	}
303
304
	/**
305
	 * Convert a calendar into a string according to the format of this object.
306
	 * 
307
	 * @param calendar
308
	 *            the calendar to convert
309
	 * @return a string modeling the calendar.
310
	 */
311
	public String toString(Calendar calendar) {
312
		StringBuffer buffer = new StringBuffer();
313
314 3 1. toString : changed conditional boundary → NO_COVERAGE
2. toString : Changed increment from 1 to -1 → NO_COVERAGE
3. toString : negated conditional → NO_COVERAGE
		for (int i = 0; i < components.size(); i++)
315
			buffer.append(components.get(i).get(calendar));
316
317 1 1. toString : mutated return of Object value for org/graphstream/util/time/ISODateIO::toString to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
		return buffer.toString();
318
	}
319
}

Mutations

193

1.1
Location :
Killed by : none
removed call to org/graphstream/util/time/ISODateIO::setFormat → NO_COVERAGE

202

1.1
Location : getPattern
Killed by : none
mutated return of Object value for org/graphstream/util/time/ISODateIO::getPattern to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE

219

1.1
Location : findComponents
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

220

1.1
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

222

1.1
Location : findComponents
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : findComponents
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

3.3
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

4.4
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

224

1.1
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

226

1.1
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

231

1.1
Location : findComponents
Killed by : none
removed call to java/util/LinkedList::addLast → NO_COVERAGE

233

1.1
Location : findComponents
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

236

1.1
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

240

1.1
Location : findComponents
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : findComponents
Killed by : none
negated conditional → NO_COVERAGE

241

1.1
Location : findComponents
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

242

1.1
Location : findComponents
Killed by : none
removed call to java/util/LinkedList::addLast → NO_COVERAGE

247

1.1
Location : findComponents
Killed by : none
mutated return of Object value for org/graphstream/util/time/ISODateIO::findComponents to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE

256

1.1
Location : buildRegularExpression
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : buildRegularExpression
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

3.3
Location : buildRegularExpression
Killed by : none
negated conditional → NO_COVERAGE

259

1.1
Location : buildRegularExpression
Killed by : none
negated conditional → NO_COVERAGE

280

1.1
Location : setFormat
Killed by : none
removed call to org/graphstream/util/time/ISODateIO::buildRegularExpression → NO_COVERAGE

295

1.1
Location : parse
Killed by : none
negated conditional → NO_COVERAGE

296

1.1
Location : parse
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : parse
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

3.3
Location : parse
Killed by : none
negated conditional → NO_COVERAGE

297

1.1
Location : parse
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

2.2
Location : parse
Killed by : none
removed call to org/graphstream/util/time/ISODateComponent::set → NO_COVERAGE

299

1.1
Location : parse
Killed by : none
mutated return of Object value for org/graphstream/util/time/ISODateIO::parse to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE

301

1.1
Location : parse
Killed by : none
mutated return of Object value for org/graphstream/util/time/ISODateIO::parse to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE

314

1.1
Location : toString
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : toString
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

3.3
Location : toString
Killed by : none
negated conditional → NO_COVERAGE

317

1.1
Location : toString
Killed by : none
mutated return of Object value for org/graphstream/util/time/ISODateIO::toString to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 0.33