Source code: desmoj/TimeConverter.java
1 package desmoj;
2
3 import java.util.Date;
4 import java.util.Locale;
5 import java.text.SimpleDateFormat;
6 import java.text.ParseException;
7
8 /** TimeConverter is a class used by Experiment to convert sim time values
9 * to true time values and vice versa. A true time value is a point in "real"
10 * time specified as a String consisting of a date and a time,
11 * for example "26.3.2001 13:25". In order to map the sim time values to
12 * true time values a reference time and a time unit are needed.
13 * The class <code>TimeConverter</code> implements the interface
14 * {@link desmoj.Units Units} to easily use the time units and conversion factors
15 * defined there.
16 * <p>
17 * Every experiment has its own time converter and provides methods for
18 * time conversion. The <code>TimeConverter</code> class is not intended for
19 * direct use in model components because handling of (simulation) time should
20 * be done in experiments only.
21 * Instead, if a model component needs to convert true time values to sim time
22 * or vice versa it has to call the appropriate methods of the class
23 * <code>Experiment</code>.
24 *
25 * @author Ruth Meyer
26 *
27 * @version DESMO-J, Ver. 1.5 copyright (c) 2001 licensed under GNU GPL
28 *
29 * @see desmoj.Experiment#toSimTime
30 * @see desmoj.Experiment#toTrueTime
31 */
32 class TimeConverter implements Units {
33
34 /** The default output format pattern for true time values as a constant.
35 * Specified according to the time format syntax used in the
36 * <code>java.text.SimpleDateFormat</code> class.
37 */
38 static final String DEFAULT_PATTERN = "dd.MM.yyyy HH:mm:ss:SSS";
39
40 /** The default date used for true time values is <tt>1.1.1970</tt>.
41 */
42 static final String DEFAULT_DATE = "1.1.1970";
43
44 /** The default time used for true time values is <tt>0:00:00</tt>.
45 */
46 static final String DEFAULT_TIME = "00:00:00";
47
48 /** The default time unit is <code>Units.MIN</tt>.
49 */
50 static final int DEFAULT_UNIT = Units.MIN;
51
52 /** The interval between reference time (= start time of simulation)
53 * and default time of class <code>java.util.Date</code> (= 1.1.1970 0:00:00)
54 * in milliseconds.
55 */
56 private long offset;
57
58 /** The reference time unit as a constant defined in interface
59 * <code>Units</code>.
60 */
61 private int unit;
62
63 /** The output formatter for true time values. Uses the default pattern
64 * if no other pattern is specified via call of the
65 * {@link #setTimeFormat(String) setTimeFormat} method.
66 */
67 private SimpleDateFormat outFormat;
68
69 /** The start time of the simulation as double (sim time).
70 * Default is 0.0.
71 */
72 private double startSimTime;
73
74
75 /** Default constructor for a time converter using the defined constants
76 * as default values for reference time (1.1.1970 0:00:00) and reference
77 * time unit (minutes).
78 * @throws java.text.ParseException Is never thrown because the default
79 * values for reference time have a valid format.
80 */
81 public TimeConverter()
82 throws ParseException
83 {
84 this(DEFAULT_DATE + " " + DEFAULT_TIME, DEFAULT_UNIT);
85 }
86 /** Constructs a time converter with given reference time and reference
87 * unit. The reference time String should follow the format:
88 * <tt><date><blank><time><tt> with <tt><date> = [d]d.[M]M.[yy]yy</tt> and
89 * <tt><time> = [H]H[:[m]m[:[s]s[:[S][S]S]]]</tt>
90 * @param referenceTime String : the reference time as a String
91 * @param referenceUnit int : the reference time unit as a constant defined
92 * in the {@link desmoj.Units Units} interface
93 * @throws java.text.ParseException if an error occurred while parsing
94 * the reference time
95 */
96 public TimeConverter(String referenceTime, int referenceUnit)
97 throws ParseException
98 {
99 // initialize instance variables
100 this.unit = referenceUnit;
101 this.outFormat = new SimpleDateFormat(DEFAULT_PATTERN, Locale.GERMANY);
102 this.startSimTime = 0.0;
103 // parse parameter referenceTime
104 String completeRefTime = checkRefTime(referenceTime);
105 String pattern = constructPattern(completeRefTime);
106 SimpleDateFormat inFormat = new SimpleDateFormat(pattern, Locale.GERMANY);
107 Date ref = inFormat.parse(completeRefTime);
108 // calculate offset = millisecs since 1.1.1970 0:00:00
109 this.offset = ref.getTime();
110 }
111 /** Checks if the given reference time is complete. A complete true time
112 * value consists of <date><blank><time> with
113 * <date> = [d]d.[M]M.[yy]yy and
114 * <time> = [H]H[:[m]m[:[s]s[:[S][S]S]]].
115 * If date or time is missing, the default values are used instead.
116 */
117 private String checkRefTime(String refTime) {
118 StringBuffer completeTime = new StringBuffer(17);
119 if (refTime == null) {
120 // neither date nor time --> use default values for both
121 completeTime.append(DEFAULT_DATE);
122 completeTime.append(" ");
123 completeTime.append(DEFAULT_TIME);
124 }
125 else {
126 int spacePos = refTime.indexOf(" ");
127 if (spacePos < 0) {
128 int pointPos = refTime.indexOf(".");
129 if (pointPos < 0) {
130 // apparently time only --> use default date
131 completeTime.append(DEFAULT_DATE);
132 completeTime.append(" ");
133 completeTime.append(refTime);
134 }
135 else {
136 // apparently date only --> use default time
137 completeTime.append(refTime);
138 completeTime.append(" ");
139 completeTime.append(DEFAULT_TIME);
140 }
141 }
142 else {
143 // both date and time exist --> use given refTime
144 completeTime.append(refTime);
145 }
146 }
147 return completeTime.toString();
148 }
149 ///////////////////// helper methods /////////////////////////////////////
150
151 /** Constructs a pattern to be used for parsing the given timeString.
152 * This private helper method is called in any of the above methods
153 * when a true time parameter has to be parsed.
154 * The following assumptions are made:
155 * <ol>
156 * <li>timeString consists of a date and a time separated by a blank
157 * (<tt><date> <time></tt>)</li>
158 * <li><date> has the format <tt>[d]d.[M]M.[yy]yy</tt></li>
159 * <li><time> has the format <tt>[H]H[:[m]m[:[s]s[:[S][S]S]]]</tt>
160 * </ol>
161 * Because the <code>SimpleDateFormat</code> class can use "minimal"
162 * patterns (for example: the pattern "d.M.yy" is okay for all dates
163 * consisting of 1 or 2 day digits, 1 or 2 month digits, and 2 or 4
164 * year digits, separated by dots) the date format is no problem.
165 * But the time has to be checked on the number of elements (hours,
166 * minutes, seconds, milliseconds) used in order to construct the
167 * appropriate pattern.
168 */
169 private String constructPattern(String timeString) {
170 StringBuffer pattern = new StringBuffer(14);
171 pattern.append("d.M.yy ");
172 int spacePos = timeString.indexOf(" ");
173 if (spacePos < 0) {
174 // no time specified --> return pattern "as is"
175 return pattern.toString();
176 }
177 // determine number of colons (:) in order to get number of time elements
178 int numberOfDelimiters = 0;
179 int pos = timeString.indexOf (":", spacePos);
180 while (pos >= 0) {
181 pos = timeString.indexOf (":", pos+1);
182 numberOfDelimiters++;
183 }
184 // the time format depends on the number of elements
185 // for each element use the minimal form
186 switch (numberOfDelimiters) {
187 case 3: pattern.insert(7, ":S");
188 case 2: pattern.insert(7, ":s");
189 case 1: pattern.insert(7, ":m");
190 case 0: pattern.insert(7, "H");
191 }
192 return pattern.toString();
193 }
194 /** Returns the reference time as as String formatted as defined in the
195 * default output format pattern. A different format may be specified
196 * via call of the <code>setTimeFormat(String)</code> method.
197 * @return String : the reference time which is the true time of the
198 * simulation start. It is mapped to simulation time 0.0 if no other
199 * simulation start time is specified.
200 */
201 public String getReferenceTime() {
202 return this.outFormat.format(new Date(this.offset));
203 }
204 /** Returns the reference time unit as a constant defined in the <code>
205 * Units</code> interface.
206 * @return the reference unit specifying what is meant by the simulation
207 * time step 1.0
208 */
209 public int getReferenceUnit() {
210 return this.unit;
211 }
212 /** Resets the time format used to format true time values to the default
213 * pattern.
214 * @see #DEFAULT_PATTERN
215 */
216 public void resetTimeFormat() {
217 this.outFormat.applyPattern(DEFAULT_PATTERN);
218 }
219 /** Sets the start time of the simulation to <code>initTime</code>.
220 * This method must be called if a start time other than 0.0 is used.
221 * @param initTime double the simulation start time as double (value of
222 * <code>SimTime</code>)
223 */
224 public void setStartSimTime(double initTime) {
225 this.startSimTime = initTime;
226 }
227 /** Sets the time format used to format true time values. Initially, the
228 * default pattern is used for formatting.
229 * @param pattern String : the time format to be used for formatting true
230 * time values. It must follow the time format syntax given in class
231 * {@link java.text.SimpleDateFormat SimpleDateFormat}.
232 */
233 public void setTimeFormat(String pattern) {
234 this.outFormat.applyPattern(pattern);
235 }
236 /** Converts the given duration with the given time unit into a sim time
237 * value. The duration is interpreted as the interval between sim time
238 * 0.0 and the calculated sim time value.
239 * @param duration double : the duration value to be converted
240 * @param unit int : the time unit for the duration as a constant defined
241 * in the {@link desmoj.Units Units} interface
242 * @return SimTime the sim time representing the given duration
243 */
244 public SimTime toSimTime(double duration, int unit) {
245 // transform duration in sim time
246 // - because SimTime doesn't distinguish between points in time and
247 // durations of time, a duration is interpreted as the interval between
248 // sim time 0.0 and the corresponding duration sim time.
249 // - the given duration is in the given unit -> just has to be converted
250 // to reference unit
251 double simDuration = duration * unitFactors[unit] / unitFactors[this.unit];
252 return new SimTime(simDuration);
253 }
254 /** Converts the given true time value to the corresponding sim time value.
255 * @param trueTime String : the true time value to be converted as a String
256 * following the time format syntax of class <code>SimpleDateFormat</code>.
257 * @return SimTime : the sim time representing the given true time
258 * @throws java.text.ParseException If an error occurred while parsing
259 * the given true time String
260 * @see java.text.SimpleDateFormat
261 */
262 public SimTime toSimTime(String trueTime)
263 throws ParseException
264 {
265 // transform true time to sim time
266 String pattern = constructPattern(trueTime);
267 SimpleDateFormat inFormat = new SimpleDateFormat(pattern, Locale.GERMANY);
268 Date trueDate = inFormat.parse(trueTime);
269 // for this, subtract offset from trueDate (both are in milliseconds),
270 // convert into reference unit and then add startSimTime (is in ref unit)
271 return new SimTime(((double)(trueDate.getTime()-this.offset))
272 * unitFactors[MS] / unitFactors[this.unit]
273 + this.startSimTime);
274 }
275 /** Converts the given sim time value to the corresponding true time value.
276 * @param simTime SimTime : the sim time value to be converted
277 * @return String : the true time representing the given sim time as a
278 * String formatted according to the currently used time format. Initially,
279 * this will be the default pattern.
280 */
281 public String toTrueTime(SimTime simTime) {
282 // transform sim time to true time
283 // for this, subtract startSimTime from simTime (both are in reference unit),
284 // convert into milliseconds and then add offset (is in milliseconds)
285 Date trueTime = new Date((long)((simTime.getTimeValue() - this.startSimTime)
286 * unitFactors[this.unit] / unitFactors[MS]
287 + this.offset));
288 return this.outFormat.format(trueTime);
289 }
290 /** Converts the given sim time value to the corresponding true time value
291 * using the given pattern as time format.
292 * @param simTime SimTime : the sim time value to be converted
293 * @param pattern String : the time format to be used for formatting the
294 * true time value
295 * @return String : the true time representing the given sim time as a
296 * String formatted according to the given pattern
297 */
298 public String toTrueTime(SimTime simTime, String pattern) {
299 setTimeFormat(pattern);
300 String trueTime = toTrueTime(simTime);
301 resetTimeFormat();
302 return trueTime;
303 }
304 }