001 /**
002 * The contents of this file are subject to the Mozilla Public License Version 1.1
003 * (the "License"); you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
005 * Software distributed under the License is distributed on an "AS IS" basis,
006 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
007 * specific language governing rights and limitations under the License.
008 *
009 * The Original Code is "CommmonTM.java". Description:
010 * "Note: The class description below has been excerpted from the Hl7 2.4 documentation"
011 *
012 * The Initial Developer of the Original Code is University Health Network. Copyright (C)
013 * 2001. All Rights Reserved.
014 *
015 * Contributor(s): ______________________________________.
016 *
017 * Alternatively, the contents of this file may be used under the terms of the
018 * GNU General Public License (the "GPL"), in which case the provisions of the GPL are
019 * applicable instead of those above. If you wish to allow use of your version of this
020 * file only under the terms of the GPL and not to allow others to use your version
021 * of this file under the MPL, indicate your decision by deleting the provisions above
022 * and replace them with the notice and other provisions required by the GPL License.
023 * If you do not delete the provisions above, a recipient may use your version of
024 * this file under either the MPL or the GPL.
025 *
026 */
027
028 package ca.uhn.hl7v2.model.primitive;
029
030 import java.util.Calendar;
031 import java.util.Date;
032 import java.util.GregorianCalendar;
033 import java.util.TimeZone;
034 import java.io.Serializable;
035
036 import ca.uhn.hl7v2.model.DataTypeException;
037 import ca.uhn.hl7v2.model.DataTypeUtil;
038
039 /**
040 * This class contains functionality used by the TM class
041 * in the version 2.3.0, 2.3.1, and 2.4 packages
042 *
043 * Note: The class description below has been excerpted from the Hl7 2.4 documentation. Sectional
044 * references made below also refer to the same documentation.
045 *
046 * Format: HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ]
047 * In prior versions of HL7, this data type was always specified to be in the
048 * format HHMM[SS[.SSSS]][+/-ZZZZ] using a 24 hour clock notation. In the
049 * current and future versions, the precision of a time may be expressed by
050 * limiting the number of digits used with the format specification as shown
051 * above. By site-specific agreement, HHMM[SS[.SSSS]][+/-ZZZZ] may be used where
052 * backward compatibility must be maintained.
053 * Thus, HH is used to specify a precision of "hour," HHMM is used to specify a
054 * precision of "minute," HHMMSS is used to specify a precision of seconds, and
055 * HHMMSS.SSSS is used to specify a precision of ten-thousandths of a second.
056 * In each of these cases, the time zone is an optional component. The fractional
057 * seconds could be sent by a transmitter who requires greater precision than whole
058 * seconds. Fractional representations of minutes, hours or other higher-order units
059 * of time are not permitted.
060 * Note: The time zone [+/-ZZZZ], when used, is restricted to legally-defined time zones
061 * and is represented in HHMM format.
062 * The time zone of the sender may be sent optionally as an offset from the coordinated
063 * universal time (previously known as Greenwich Mean Time). Where the time zone
064 * is not present in a particular TM field but is included as part of the date/time
065 * field in the MSH segment, the MSH value will be used as the default time zone.
066 * Otherwise, the time is understood to refer to the local time of the sender.
067 * Midnight is represented as 0000.
068 * Examples:|235959+1100| 1 second before midnight in a time zone eleven hours
069 * ahead of Universal Coordinated Time (i.e., east of Greenwich).
070 * |0800| Eight AM, local time of the sender.
071 * |093544.2312| 44.2312 seconds after Nine thirty-five AM, local time of sender.
072 * |13| 1pm (with a precision of hours), local time of sender.
073 * @author Neal Acharya
074 */
075
076 @SuppressWarnings("serial")
077 public class CommonTM implements Serializable {
078
079 /**
080 * Value returned by {@link #getGMTOffset()} if no offset is set
081 */
082 public static final int GMT_OFFSET_NOT_SET_VALUE = -99;
083
084 private String value;
085 private int hour;
086 private int minute;
087 private int second;
088 private float fractionOfSec;
089 private int offSet;
090 private boolean omitOffsetFg = false;
091
092 /**
093 * Constructs a TM datatype with fields initialzed to zero and the value set to
094 * null.
095 */
096 public CommonTM() {
097 //initialize all DT fields
098 value = null;
099 hour = 0;
100 minute = 0;
101 second = 0;
102 fractionOfSec = 0;
103 offSet = GMT_OFFSET_NOT_SET_VALUE;
104 } //end constructor
105
106 /**
107 * Constructs a TM object with the given value.
108 * The stored value will be in the following
109 * format HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ].
110 */
111 public CommonTM(String val) throws DataTypeException {
112 this.setValue(val);
113 } //end constructor
114
115 /**
116 * This method takes in a string HL7 Time value and performs validations
117 * then sets the value field. The stored value will be in the following
118 * format HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ].
119 * Note: Trailing zeros supplied in the time value (HH[MM[SS[.S[S[S[S]]]]]])
120 * and GMT offset ([+/-ZZZZ]) will be preserved.
121 * Note: If the GMT offset is not supplied then the local
122 * time zone (using standard time zone format which is not modified for daylight savings)
123 * will be stored as a default. Passing in <code>null</code> clears any existing value.
124 */
125 public void setValue(String val) throws DataTypeException {
126
127 if (val != null && !val.equals("") && !val.equals("\"\"")) {
128 //check to see if any of the following characters exist: "." or "+/-"
129 //this will help us determine the acceptable lengths
130
131 int d = val.indexOf(".");
132 int sp = val.indexOf("+");
133 int sm = val.indexOf("-");
134 int indexOfSign = -1;
135 boolean offsetExists = false;
136 if ((sp != -1) || (sm != -1))
137 offsetExists = true;
138 if (sp != -1)
139 indexOfSign = sp;
140 if (sm != -1)
141 indexOfSign = sm;
142
143 try {
144 //If the GMT offset exists then extract it from the input string and store it
145 //in another variable called tempOffset. Also, store the time value
146 //(without the offset)in a separate variable called timeVal.
147 //If there is no GMT offset then simply set timeVal to val.
148 String timeVal = val;
149 String tempOffset = null;
150 if (offsetExists) {
151 timeVal = val.substring(0, indexOfSign);
152 tempOffset = val.substring(indexOfSign);
153 } //end if
154
155 if (offsetExists && (tempOffset.length() != 5)) {
156 //The length of the GMT offset must be 5 characters (including the sign)
157 String msg =
158 "The length of the TM datatype value does not conform to an allowable"
159 + " format. Format should conform to HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ]";
160 DataTypeException e = new DataTypeException(msg);
161 throw e;
162 } //end if
163
164 if (d != -1) {
165 //here we know that decimal exists
166 //thus length of the time value can be between 8 and 11 characters
167 if ((timeVal.length() < 8) || (timeVal.length() > 11)) {
168 String msg =
169 "The length of the TM datatype value does not conform to an allowable"
170 + " format. Format should conform to HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ]";
171 DataTypeException e = new DataTypeException(msg);
172 throw e;
173 } //end if
174 } //end if
175
176 if (d == -1) {
177 //here we know that the decimal does not exist
178 //thus length of the time value can be 2 or 4 or 6 characters
179 if ((timeVal.length() != 2) && (timeVal.length() != 4) && (timeVal.length() != 6)) {
180 String msg =
181 "The length of the TM datatype value does not conform to an allowable"
182 + " format. Format should conform to HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ]";
183 DataTypeException e = new DataTypeException(msg);
184 throw e;
185 } //end if
186 } //end if
187
188 //We will now try to validate the timeVal portion of the TM datatype value
189 if (timeVal.length() >= 2) {
190 //extract the hour data from the input value. If the first 2 characters
191 //are not numeric then a number format exception will be generated
192 int hrInt = Integer.parseInt(timeVal.substring(0, 2));
193 //check to see if the hour value is valid
194 if ((hrInt < 0) || (hrInt > 23)) {
195 String msg = "The hour value of the TM datatype must be >=0 and <=23";
196 DataTypeException e = new DataTypeException(msg);
197 throw e;
198 } //end if
199 hour = hrInt;
200 } //end if
201
202 if (timeVal.length() >= 4) {
203 //extract the minute data from the input value
204 //If these characters are not numeric then a number
205 //format exception will be generated
206 int minInt = Integer.parseInt(timeVal.substring(2, 4));
207 //check to see if the minute value is valid
208 if ((minInt < 0) || (minInt > 59)) {
209 String msg = "The minute value of the TM datatype must be >=0 and <=59";
210 DataTypeException e = new DataTypeException(msg);
211 throw e;
212 } //end if
213 minute = minInt;
214 } //end if
215
216 if (timeVal.length() >= 6) {
217 //extract the seconds data from the input value
218 //If these characters are not numeric then a number
219 //format exception will be generated
220 int secInt = Integer.parseInt(timeVal.substring(4, 6));
221 //check to see if the seconds value is valid
222 if ((secInt < 0) || (secInt > 59)) {
223 String msg = "The seconds value of the TM datatype must be >=0 and <=59";
224 DataTypeException e = new DataTypeException(msg);
225 throw e;
226 } //end if
227 second = secInt;
228 } //end if
229
230 if (timeVal.length() >= 8) {
231 //extract the fractional second value from the input value
232 //If these characters are not numeric then a number
233 //format exception will be generated
234 float fract = Float.parseFloat(timeVal.substring(6));
235 //check to see if the fractional second value is valid
236 if ((fract < 0) || (fract >= 1)) {
237 String msg = "The fractional second value of the TM datatype must be >= 0 and < 1";
238 DataTypeException e = new DataTypeException(msg);
239 throw e;
240 } //end if
241 fractionOfSec = fract;
242 } //end if
243
244 //We will now try to validate the tempOffset portion of the TM datatype value
245 if (offsetExists) {
246 //in case the offset are a series of zeros we should not omit displaying
247 //it in the return value from the getValue() method
248 omitOffsetFg = false;
249 //remove the sign from the temp offset
250 String tempOffsetNoS = tempOffset.substring(1);
251 //extract the hour data from the offset value. If the first 2 characters
252 //are not numeric then a number format exception will be generated
253 int offsetInt = Integer.parseInt(tempOffsetNoS.substring(0, 2));
254 //check to see if the hour value is valid
255 if ((offsetInt < 0) || (offsetInt > 23)) {
256 String msg = "The GMT offset hour value of the TM datatype must be >=0 and <=23";
257 DataTypeException e = new DataTypeException(msg);
258 throw e;
259 } //end if
260 //extract the minute data from the offset value. If these characters
261 //are not numeric then a number format exception will be generated
262 offsetInt = Integer.parseInt(tempOffsetNoS.substring(2, 4));
263 //check to see if the minute value is valid
264 if ((offsetInt < 0) || (offsetInt > 59)) {
265 String msg = "The GMT offset minute value of the TM datatype must be >=0 and <=59";
266 DataTypeException e = new DataTypeException(msg);
267 throw e;
268 } //end if
269 //validation done, update the offSet field
270 offSet = Integer.parseInt(tempOffsetNoS);
271 //add the sign back to the offset if it is negative
272 if (sm != -1) {
273 offSet = -1 * offSet;
274 } //end if
275 } //end if
276
277 //If the GMT offset has not been supplied then set the offset to the
278 //local timezone
279 //[Bryan: changing this to omit time zone because erroneous if parser in different zone than sender]
280 if (!offsetExists) {
281 omitOffsetFg = true;
282 // set the offSet field to the current time and local time zone
283 //offSet = DataTypeUtil.getLocalGMTOffset();
284 } //end if
285
286 //validations are now done store the time value into the private value field
287 value = timeVal;
288 } //end try
289
290 catch (DataTypeException e) {
291 throw e;
292 } //end catch
293
294 catch (Exception e) {
295 throw new DataTypeException(e);
296 } //end catch
297 } //end if
298 else {
299 //set the private value field to null or empty space.
300 value = val;
301 } //end else
302 } //end method
303
304 /**
305 * This method takes in an integer value for the hour and performs validations,
306 * it then sets the value field formatted as an HL7 time
307 * value with hour precision (HH).
308 */
309 public void setHourPrecision(int hr) throws DataTypeException {
310 try {
311 //validate input value
312 if ((hr < 0) || (hr > 23)) {
313 String msg = "The hour value of the TM datatype must be >=0 and <=23";
314 DataTypeException e = new DataTypeException(msg);
315 throw e;
316 } //end if
317 hour = hr;
318 minute = 0;
319 second = 0;
320 fractionOfSec = 0;
321 offSet = 0;
322 //Here the offset is not defined, we should omit showing it in the
323 //return value from the getValue() method
324 omitOffsetFg = true;
325 value = DataTypeUtil.preAppendZeroes(hr, 2);
326 } //end try
327
328 catch (DataTypeException e) {
329 throw e;
330 } //end catch
331
332 catch (Exception e) {
333 throw new DataTypeException(e.getMessage());
334 } //end catch
335
336 } //end method
337
338 /**
339 * This method takes in integer values for the hour and minute and performs validations,
340 * it then sets the value field formatted as an HL7 time value
341 * with hour&minute precision (HHMM).
342 */
343 public void setHourMinutePrecision(int hr, int min) throws DataTypeException {
344 try {
345 this.setHourPrecision(hr);
346 //validate input minute value
347 if ((min < 0) || (min > 59)) {
348 String msg = "The minute value of the TM datatype must be >=0 and <=59";
349 DataTypeException e = new DataTypeException(msg);
350 throw e;
351 } //end if
352 minute = min;
353 second = 0;
354 fractionOfSec = 0;
355 offSet = 0;
356 //Here the offset is not defined, we should omit showing it in the
357 //return value from the getValue() method
358 omitOffsetFg = true;
359 value = value + DataTypeUtil.preAppendZeroes(min, 2);
360 } //end try
361
362 catch (DataTypeException e) {
363 throw e;
364 } //end catch
365
366 catch (Exception e) {
367 throw new DataTypeException(e.getMessage());
368 } //end catch
369 } //end method
370
371 /**
372 * This method takes in integer values for the hour, minute, seconds, and fractional seconds
373 * (going to the tenthousandths precision).
374 * The method performs validations and then sets the value field formatted as an
375 * HL7 time value with a precision that starts from the hour and goes down to the tenthousandths
376 * of a second (HHMMSS.SSSS).
377 * Note: all of the precisions from tenths down to tenthousandths of a
378 * second are optional. If the precision goes below tenthousandths of a second then the second
379 * value will be rounded to the nearest tenthousandths of a second.
380 */
381 public void setHourMinSecondPrecision(int hr, int min, float sec) throws DataTypeException {
382 try {
383 this.setHourMinutePrecision(hr, min);
384 //multiply the seconds input value by 10000 and round the result
385 //then divide the number by tenthousand and store it back.
386 //This will round the fractional seconds to the nearest tenthousandths
387 int secMultRound = Math.round(10000F * sec);
388 sec = secMultRound / 10000F;
389 //Now store the second and fractional component
390 second = (int) Math.floor(sec);
391 //validate input seconds value
392 if ((second < 0) || (second >= 60)) {
393 String msg = "The (rounded) second value of the TM datatype must be >=0 and <60";
394 DataTypeException e = new DataTypeException(msg);
395 throw e;
396 } //end if
397 int fractionOfSecInt = (int) (secMultRound - (second * 10000));
398 fractionOfSec = fractionOfSecInt / 10000F;
399 String fractString = "";
400 //Now convert the fractionOfSec field to a string without the leading zero
401 if (fractionOfSec != 0.0F) {
402 fractString = (Float.toString(fractionOfSec)).substring(1);
403 } //end if
404 //Now update the value field
405 offSet = 0;
406 //Here the offset is not defined, we should omit showing it in the
407 //return value from the getValue() method
408 omitOffsetFg = true;
409 value = value + DataTypeUtil.preAppendZeroes(second, 2) + fractString;
410 } //end try
411
412 catch (DataTypeException e) {
413 throw e;
414 } //end catch
415
416 catch (Exception e) {
417 throw new DataTypeException(e);
418 } //end catch
419 } //end method
420
421 /**
422 * This method takes in the four digit (signed) GMT offset and sets the offset
423 * field
424 */
425 public void setOffset(int signedOffset) throws DataTypeException {
426 try {
427 //When this function is called an offset is being created/updated
428 //we should not omit displaying it in the return value from
429 //the getValue() method
430 omitOffsetFg = false;
431 String offsetStr = Integer.toString(signedOffset);
432 if ((signedOffset >= 0 && offsetStr.length() > 4) || (signedOffset < 0 && offsetStr.length() > 5)) {
433 //The length of the GMT offset must be no greater than 5 characters (including the sign)
434 String msg =
435 "The length of the GMT offset for the TM datatype value does"
436 + " not conform to the allowable format [+/-ZZZZ]. Value: " + signedOffset;
437 DataTypeException e = new DataTypeException(msg);
438 throw e;
439 } //end if
440 //obtain the absolute value of the input
441 int absOffset = Math.abs(signedOffset);
442 //extract the hour data from the offset value.
443 //first preappend zeros so we have a 4 char offset value (without sign)
444 offsetStr = DataTypeUtil.preAppendZeroes(absOffset, 4);
445 int hrOffsetInt = Integer.parseInt(offsetStr.substring(0, 2));
446 //check to see if the hour value is valid
447 if ((hrOffsetInt < 0) || (hrOffsetInt > 23)) {
448 String msg = "The GMT offset hour value of the TM datatype must be >=0 and <=23";
449 DataTypeException e = new DataTypeException(msg);
450 throw e;
451 } //end if
452 //extract the minute data from the offset value.
453 int minOffsetInt = Integer.parseInt(offsetStr.substring(2, 4));
454 //check to see if the minute value is valid
455 if ((minOffsetInt < 0) || (minOffsetInt > 59)) {
456 String msg = "The GMT offset minute value of the TM datatype must be >=0 and <=59";
457 DataTypeException e = new DataTypeException(msg);
458 throw e;
459 } //end if
460 //The input value is valid, now store it in the offset field
461 offSet = signedOffset;
462 } //end try
463
464 catch (DataTypeException e) {
465 throw e;
466 } //end catch
467
468 catch (Exception e) {
469 throw new DataTypeException(e);
470 } //end catch
471 } //end method
472
473 /**
474 * Returns the HL7 TM string value.
475 */
476 public String getValue() {
477 //combine the value field with the offSet field and return it
478 String returnVal = null;
479 if (value != null && !value.equals("")) {
480 if (omitOffsetFg == false && !value.equals("\"\"")) {
481 int absOffset = Math.abs(offSet);
482 String sign = "";
483 if (offSet >= 0) {
484 sign = "+";
485 } //end if
486 else {
487 sign = "-";
488 } //end else
489 returnVal = value + sign + DataTypeUtil.preAppendZeroes(absOffset, 4);
490 }
491 else {
492 returnVal = value;
493 } //end else
494 } //end if
495 return returnVal;
496 } //end method
497
498 /**
499 * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
500 *
501 * Note: Sets fields using precision up to the minute
502 *
503 * @param theCalendar The calendar object from which to retrieve values
504 * @since 1.1
505 */
506 public void setValueToMinute(Calendar theCalendar) throws DataTypeException {
507 if (theCalendar == null) {
508 setValue((String)null);
509 return;
510 }
511
512 int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
513 int min = theCalendar.get(Calendar.MINUTE);
514 setHourMinutePrecision(hr, min);
515 }
516
517 /**
518 * Convenience setter which sets the value using a {@link Date} object. Passing in <code>null</code> clears any existing value.
519 *
520 * Note: Sets fields using precision up to the minute
521 * Note: Date is timezone-agnostic, representing always GMT time
522 *
523 * @param theCalendar The calendar object from which to retrieve values
524 * @since 1.1
525 */
526 public void setValueToMinute(Date theDate) throws DataTypeException {
527 if (theDate == null) {
528 setValue((String)null);
529 return;
530 }
531
532 Calendar calendar = Calendar.getInstance();
533 calendar.setTime(theDate);
534 setValueToMinute(calendar);
535 }
536
537 /**
538 * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
539 *
540 * Note: Sets fields using precision up to the second
541 *
542 * @param theCalendar The calendar object from which to retrieve values
543 * @since 1.1
544 */
545 public void setValueToSecond(Calendar theCalendar) throws DataTypeException {
546 if (theCalendar == null) {
547 setValue((String)null);
548 return;
549 }
550
551 int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
552 int min = theCalendar.get(Calendar.MINUTE);
553 int sec = theCalendar.get(Calendar.SECOND);
554
555 setHourMinSecondPrecision(hr, min, sec);
556 }
557
558 /**
559 * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
560 *
561 * Note: Sets fields using precision up to the millisecond, including timezone offset
562 *
563 * @param theCalendar The calendar object from which to retrieve values
564 * @since 1.1
565 */
566 public void setValue(Calendar theCalendar) throws DataTypeException {
567 if (theCalendar == null) {
568 setValue((String)null);
569 return;
570 }
571
572 int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
573 int min = theCalendar.get(Calendar.MINUTE);
574 float sec = theCalendar.get(Calendar.SECOND) + (theCalendar.get(Calendar.MILLISECOND) / 1000.0F);
575 setHourMinSecondPrecision(hr, min, sec);
576
577 // 3410095: care for integer overflow and timezones not at the full hour, e.g. India
578 int hourOffset= theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
579 int minuteOffset = (theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
580 int zoneOffset = hourOffset * 100 + minuteOffset;
581 setOffset(zoneOffset);
582 }
583
584 /**
585 * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
586 *
587 * Note: Sets fields using precision up to the millisecond, and sets the timezone offset to
588 * the current system offset
589 * Note: Date is timezone-agnostic, representing always GMT time
590 *
591 * @param theDate The calendar object from which to retrieve values
592 * @since 1.1
593 */
594 public void setValue(Date theDate) throws DataTypeException {
595 if (theDate == null) {
596 setValue((String)null);
597 return;
598 }
599
600 GregorianCalendar cal = new GregorianCalendar();
601 cal.setTime(theDate);
602 setValue(cal);
603 }
604
605 /**
606 * Convenience setter which sets the value using a {@link Date} object. Passing in <code>null</code> clears any existing value.
607 *
608 * Note: Sets fields using precision up to the second
609 * Note: Date is timezone-agnostic, representing always GMT time
610 *
611 * @param theCalendar The calendar object from which to retrieve values
612 * @since 1.1
613 */
614 public void setValueToSecond(Date theDate) throws DataTypeException {
615 if (theDate == null) {
616 setValue((String)null);
617 return;
618 }
619
620 Calendar calendar = Calendar.getInstance();
621 calendar.setTime(theDate);
622 setValueToSecond(calendar);
623 }
624
625 /**
626 * <p>Return the value as a calendar object.</p>
627 *
628 * <b>Note that only the time component of the return value is set to
629 * the value from this object. Returned value will have today's date</b>
630 * @since 1.1
631 */
632 public Calendar getValueAsCalendar() {
633 Calendar retVal = Calendar.getInstance();
634 retVal.set(Calendar.HOUR_OF_DAY, getHour());
635 retVal.set(Calendar.MINUTE, getMinute());
636 retVal.set(Calendar.SECOND, getSecond());
637
638 float fractSecond = getFractSecond();
639 retVal.set(Calendar.MILLISECOND, (int) (fractSecond * 1000.0));
640
641 int gmtOff = getGMTOffset();
642 if (gmtOff != GMT_OFFSET_NOT_SET_VALUE && !omitOffsetFg) {
643 retVal.set(Calendar.ZONE_OFFSET, (gmtOff/100) * (1000 * 60 * 60));
644
645 /*
646 * The following sets the TimeZone associated with the returned calendar
647 * to use the offset specified in the value if this conflicts with the
648 * value it already contains.
649 *
650 * This is needed in situations where daylight savings is in effect
651 * during part of the year, and a date is parsed which contains the
652 * other part of the year (i.e. parsing a DST DateTime when it is not actually
653 * DST according to the system clock).
654 *
655 * See CommonTSTest#testGetCalendarRespectsDaylightSavings() for an example
656 * which fails if this is removed.
657 */
658 if (retVal.getTimeZone().getRawOffset() != retVal.get(Calendar.ZONE_OFFSET)) {
659 int hrOffset = gmtOff / 100;
660 int minOffset = gmtOff % 100;
661 StringBuilder tzBuilder = new StringBuilder("GMT");
662
663 if (hrOffset < 0) {
664 tzBuilder.append('-');
665 }
666 tzBuilder.append(Math.abs(hrOffset));
667 tzBuilder.append(':');
668 if (minOffset < 10) {
669 tzBuilder.append('0');
670 }
671 tzBuilder.append(minOffset);
672
673 retVal.setTimeZone(TimeZone.getTimeZone(tzBuilder.toString()));
674 }
675
676 }
677
678 return retVal;
679 }
680
681
682 /**
683 * <p>Return the value as a date object</p>
684 *
685 * <b>Note that only the time component of the return value is set to
686 * the value from this object. Returned value will have today's date</b>
687 * Note: Date is timezone-agnostic, representing always GMT time
688 * @since 1.1
689 */
690 public Date getValueAsDate() {
691 return getValueAsCalendar().getTime();
692 }
693
694 /**
695 * Returns the hour as an integer.
696 */
697 public int getHour() {
698 return hour;
699 } //end method
700
701 /**
702 * Returns the minute as an integer.
703 */
704 public int getMinute() {
705 return minute;
706 } //end method
707
708 /**
709 * Returns the second as an integer.
710 */
711 public int getSecond() {
712 return second;
713 } //end method
714
715 /**
716 * Returns the fractional second value as a float.
717 */
718 public float getFractSecond() {
719 return fractionOfSec;
720 } //end method
721
722 /**
723 * Returns the GMT offset value as an integer, {@link #GMT_OFFSET_NOT_SET_VALUE} if not set.
724 */
725 public int getGMTOffset() {
726 return offSet;
727 } //end method
728
729 /**
730 * Returns a string value representing the input Gregorian Calendar object in
731 * an Hl7 Time Format.
732 */
733 public static String toHl7TMFormat(GregorianCalendar cal) throws DataTypeException {
734 String val = "";
735 try {
736 //set the input cal object so that it can report errors
737 //on it's value
738 cal.setLenient(false);
739 int calHour = cal.get(GregorianCalendar.HOUR_OF_DAY);
740 int calMin = cal.get(GregorianCalendar.MINUTE);
741 int calSec = cal.get(GregorianCalendar.SECOND);
742 int calMilli = cal.get(GregorianCalendar.MILLISECOND);
743 //the inputs seconds and milli seconds should be combined into a float type
744 float fractSec = calMilli / 1000F;
745 float calSecFloat = calSec + fractSec;
746 int calOffset = cal.get(GregorianCalendar.ZONE_OFFSET) + cal.get(GregorianCalendar.DST_OFFSET);
747 //Note the input's Offset value is in milliseconds, we must convert it to
748 //a 4 digit integer in the HL7 Offset format.
749 int offSetSignInt;
750 if (calOffset < 0) {
751 offSetSignInt = -1;
752 }
753 else {
754 offSetSignInt = 1;
755 }
756 //get the absolute value of the gmtOffSet
757 int absGmtOffSet = Math.abs(calOffset);
758 int gmtOffSetHours = absGmtOffSet / (3600 * 1000);
759 int gmtOffSetMin = (absGmtOffSet / 60000) % (60);
760 //reset calOffset
761 calOffset = ((gmtOffSetHours * 100) + gmtOffSetMin) * offSetSignInt;
762 //Create an object of the TS class and populate it with the above values
763 //then return the HL7 string value from the object
764 CommonTM tm = new CommonTM();
765 tm.setHourMinSecondPrecision(calHour, calMin, calSecFloat);
766 tm.setOffset(calOffset);
767 val = tm.getValue();
768 } // end try
769
770 catch (DataTypeException e) {
771 throw e;
772 } //end catch
773
774 catch (Exception e) {
775 throw new DataTypeException(e);
776 } //end catch
777 return val;
778 } //end method
779
780 } //end class