View Javadoc
1   /**
2    * The contents of this file are subject to the Mozilla Public License Version 1.1
3    * (the "License"); you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at http://www.mozilla.org/MPL/
5    * Software distributed under the License is distributed on an "AS IS" basis,
6    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
7    * specific language governing rights and limitations under the License.
8    *
9    * The Original Code is "CommmonTM.java".  Description:
10   * "Note: The class description below has been excerpted from the Hl7 2.4 documentation"
11   *
12   * The Initial Developer of the Original Code is University Health Network. Copyright (C)
13   * 2001.  All Rights Reserved.
14   *
15   * Contributor(s): ______________________________________.
16   *
17   * Alternatively, the contents of this file may be used under the terms of the
18   * GNU General Public License (the "GPL"), in which case the provisions of the GPL are
19   * applicable instead of those above.  If you wish to allow use of your version of this
20   * file only under the terms of the GPL and not to allow others to use your version
21   * of this file under the MPL, indicate your decision by deleting  the provisions above
22   * and replace  them with the notice and other provisions required by the GPL License.
23   * If you do not delete the provisions above, a recipient may use your version of
24   * this file under either the MPL or the GPL.
25   *
26   */
27  
28  package ca.uhn.hl7v2.model.primitive;
29  
30  import java.util.Calendar;
31  import java.util.Date;
32  import java.util.GregorianCalendar;
33  import java.util.TimeZone;
34  import java.io.Serializable;
35  
36  import ca.uhn.hl7v2.model.DataTypeException;
37  import ca.uhn.hl7v2.model.DataTypeUtil;
38  
39  /**
40   * This class contains functionality used by the TM class
41   * in the version 2.3.0, 2.3.1, and 2.4 packages
42   *
43   * Note: The class description below has been excerpted from the Hl7 2.4 documentation. Sectional
44   * references made below also refer to the same documentation.
45   *
46   * Format: HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ]
47   * In prior versions of HL7, this data type was always specified to be in the
48   * format HHMM[SS[.SSSS]][+/-ZZZZ] using a 24 hour clock notation. In the
49   * current and future versions, the precision of a time may be expressed by
50   * limiting the number of digits used with the format specification as shown
51   * above. By site-specific agreement, HHMM[SS[.SSSS]][+/-ZZZZ] may be used where
52   * backward compatibility must be maintained.
53   * Thus, HH is used to specify a precision of "hour," HHMM is used to specify a
54   * precision of "minute," HHMMSS is used to specify a precision of seconds, and
55   * HHMMSS.SSSS is used to specify a precision of ten-thousandths of a second.
56   * In each of these cases, the time zone is an optional component. The fractional
57   * seconds could be sent by a transmitter who requires greater precision than whole
58   * seconds. Fractional representations of minutes, hours or other higher-order units
59   * of time are not permitted.
60   * Note: The time zone [+/-ZZZZ], when used, is restricted to legally-defined time zones
61   * and is represented in HHMM format.
62   * The time zone of the sender may be sent optionally as an offset from the coordinated
63   * universal time (previously known as Greenwich Mean Time). Where the time zone
64   * is not present in a particular TM field but is included as part of the date/time
65   * field in the MSH segment, the MSH value will be used as the default time zone.
66   * Otherwise, the time is understood to refer to the local time of the sender.
67   * Midnight is represented as 0000.
68   * Examples:|235959+1100| 1 second before midnight in a time zone eleven hours
69   * ahead of Universal Coordinated Time (i.e., east of Greenwich).
70   * |0800| Eight AM, local time of the sender.
71   * |093544.2312| 44.2312 seconds after Nine thirty-five AM, local time of sender.
72   * |13| 1pm (with a precision of hours), local time of sender.
73   * @author Neal Acharya
74   */
75  
76  @SuppressWarnings("serial")
77  public class CommonTM implements Serializable {
78      
79  	/**
80       * Value returned by {@link #getGMTOffset()} if no offset is set
81       */
82      public static final int GMT_OFFSET_NOT_SET_VALUE = -99;
83  
84      private String value;
85      private int hour;
86      private int minute;
87      private int second;
88      private float fractionOfSec;
89      private int offSet;
90      private boolean omitOffsetFg = false;
91  
92      /**
93       * Constructs a TM datatype with fields initialzed to zero and the value set to
94       * null.
95       */
96      public CommonTM() {
97          //initialize all DT fields
98          value = null;
99          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                     throw new DataTypeException(msg);
161                 } //end if
162 
163                 if (d != -1) {
164                     //here we know that decimal exists
165                     //thus length of the time value can be between 8 and 11 characters
166                     if ((timeVal.length() < 8) || (timeVal.length() > 11)) {
167                         String msg =
168                             "The length of the TM datatype value does not conform to an allowable"
169                                 + " format. Format should conform to HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ]";
170                         throw new DataTypeException(msg);
171                     } //end if
172                 } //end if
173 
174                 if (d == -1) {
175                     //here we know that the decimal does not exist
176                     //thus length of the time value can be 2 or 4 or 6 characters
177                     if ((timeVal.length() != 2) && (timeVal.length() != 4) && (timeVal.length() != 6)) {
178                         String msg =
179                             "The length of the TM datatype value does not conform to an allowable"
180                                 + " format. Format should conform to HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ]";
181                         throw new DataTypeException(msg);
182                     } //end if
183                 } //end if
184 
185                 //We will now try to validate the timeVal portion of the TM datatype value
186                 if (timeVal.length() >= 2) {
187                     //extract the hour data from the input value.  If the first 2 characters
188                     //are not numeric then a number format exception will be generated
189                     int hrInt = Integer.parseInt(timeVal.substring(0, 2));
190                     //check to see if the hour value is valid
191                     if ((hrInt < 0) || (hrInt > 23)) {
192                         String msg = "The hour value of the TM datatype must be >=0 and <=23";
193                         throw new DataTypeException(msg);
194                     } //end if
195                     hour = hrInt;
196                 } //end if
197 
198                 if (timeVal.length() >= 4) {
199                     //extract the minute data from the input value
200                     //If these characters are not numeric then a number
201                     //format exception will be generated
202                     int minInt = Integer.parseInt(timeVal.substring(2, 4));
203                     //check to see if the minute value is valid
204                     if ((minInt < 0) || (minInt > 59)) {
205                         String msg = "The minute value of the TM datatype must be >=0 and <=59";
206                         throw new DataTypeException(msg);
207                     } //end if
208                     minute = minInt;
209                 } //end if
210 
211                 if (timeVal.length() >= 6) {
212                     //extract the seconds data from the input value
213                     //If these characters are not numeric then a number
214                     //format exception will be generated
215                     int secInt = Integer.parseInt(timeVal.substring(4, 6));
216                     //check to see if the seconds value is valid
217                     if ((secInt < 0) || (secInt > 59)) {
218                         String msg = "The seconds value of the TM datatype must be >=0 and <=59";
219                         throw new DataTypeException(msg);
220                     } //end if
221                     second = secInt;
222                 } //end if
223 
224                 if (timeVal.length() >= 8) {
225                     //extract the fractional second value from the input value
226                     //If these characters are not numeric then a number
227                     //format exception will be generated
228                     float fract = Float.parseFloat(timeVal.substring(6));
229                     //check to see if the fractional second value is valid
230                     if ((fract < 0) || (fract >= 1)) {
231                         String msg = "The fractional second value of the TM datatype must be >= 0 and < 1";
232                         throw new DataTypeException(msg);
233                     } //end if
234                     fractionOfSec = fract;
235                 } //end if
236 
237                 //We will now try to validate the tempOffset portion of the TM datatype value
238                 if (offsetExists) {
239                     //in case the offset are a series of zeros we should not omit displaying
240                     //it in the return value from the getValue() method
241                     omitOffsetFg = false;
242                     //remove the sign from the temp offset
243                     String tempOffsetNoS = tempOffset.substring(1);
244                     //extract the hour data from the offset value.  If the first 2 characters
245                     //are not numeric then a number format exception will be generated
246                     int offsetInt = Integer.parseInt(tempOffsetNoS.substring(0, 2));
247                     //check to see if the hour value is valid
248                     if ((offsetInt < 0) || (offsetInt > 23)) {
249                         String msg = "The GMT offset hour value of the TM datatype must be >=0 and <=23";
250                         throw new DataTypeException(msg);
251                     } //end if
252                     //extract the minute data from the offset value.  If these characters
253                     //are not numeric then a number format exception will be generated
254                     offsetInt = Integer.parseInt(tempOffsetNoS.substring(2, 4));
255                     //check to see if the minute value is valid
256                     if ((offsetInt < 0) || (offsetInt > 59)) {
257                         String msg = "The GMT offset minute value of the TM datatype must be >=0 and <=59";
258                         throw new DataTypeException(msg);
259                     } //end if
260                     //validation done, update the offSet field
261                     offSet = Integer.parseInt(tempOffsetNoS);
262                     //add the sign back to the offset if it is negative
263                     if (sm != -1) {
264                         offSet = -1 * offSet;
265                     } //end if
266                 } //end if
267 
268                 //If the GMT offset has not been supplied then set the offset to the
269                 //local timezone
270                 //[Bryan: changing this to omit time zone because erroneous if parser in different zone than sender]
271                 if (!offsetExists) {
272                     omitOffsetFg = true;
273                     // set the offSet field to the current time and local time zone
274                     //offSet = DataTypeUtil.getLocalGMTOffset();
275                 } //end if
276 
277                 //validations are now done store the time value into the private value field
278                 value = timeVal;
279             } //end try
280 
281             catch (DataTypeException e) {
282                 throw e;
283             } //end catch
284 
285             catch (Exception e) {
286                 throw new DataTypeException(e);
287             } //end catch
288         } //end if
289         else {
290             //set the private value field to null or empty space.
291             value = val;
292         } //end else
293     } //end method
294 
295     /**
296      * This method takes in an integer value for the hour and performs validations,
297      * it then sets the value field formatted as an HL7 time
298      * value with hour precision (HH).
299      */
300     public void setHourPrecision(int hr) throws DataTypeException {
301         try {
302             //validate input value
303             if ((hr < 0) || (hr > 23)) {
304                 String msg = "The hour value of the TM datatype must be >=0 and <=23";
305                 throw new DataTypeException(msg);
306             } //end if
307             hour = hr;
308             minute = 0;
309             second = 0;
310             fractionOfSec = 0;
311             offSet = 0;
312             //Here the offset is not defined, we should omit showing it in the
313             //return value from the getValue() method
314             omitOffsetFg = true;
315             value = DataTypeUtil.preAppendZeroes(hr, 2);
316         } //end try
317 
318         catch (DataTypeException e) {
319             throw e;
320         } //end catch
321 
322         catch (Exception e) {
323             throw new DataTypeException(e.getMessage());
324         } //end catch
325 
326     } //end method
327 
328     /**
329      * This method takes in integer values for the hour and minute and performs validations,
330      * it then sets the value field formatted as an HL7 time value
331      * with hour&minute precision (HHMM).
332      */
333     public void setHourMinutePrecision(int hr, int min) throws DataTypeException {
334         try {
335             this.setHourPrecision(hr);
336             //validate input minute value
337             if ((min < 0) || (min > 59)) {
338                 String msg = "The minute value of the TM datatype must be >=0 and <=59";
339                 throw new DataTypeException(msg);
340             } //end if
341             minute = min;
342             second = 0;
343             fractionOfSec = 0;
344             offSet = 0;
345             //Here the offset is not defined, we should omit showing it in the
346             //return value from the getValue() method
347             omitOffsetFg = true;
348             value = value + DataTypeUtil.preAppendZeroes(min, 2);
349         } //end try
350 
351         catch (DataTypeException e) {
352             throw e;
353         } //end catch
354 
355         catch (Exception e) {
356             throw new DataTypeException(e.getMessage());
357         } //end catch
358     } //end method
359 
360     /**
361      * This method takes in integer values for the hour, minute, seconds, and fractional seconds
362      * (going to the tenthousandths precision).
363      * The method performs validations and then sets the value field formatted as an
364      * HL7 time value with a precision that starts from the hour and goes down to the tenthousandths
365      * of a second (HHMMSS.SSSS).
366      * Note: all of the precisions from tenths down to tenthousandths of a
367      * second are optional. If the precision goes below tenthousandths of a second then the second
368      * value will be rounded to the nearest tenthousandths of a second.
369      */
370     public void setHourMinSecondPrecision(int hr, int min, float sec) throws DataTypeException {
371         try {
372             this.setHourMinutePrecision(hr, min);
373             //multiply the seconds input value by 10000 and round the result
374             //then divide the number by tenthousand and store it back.
375             //This will round the fractional seconds to the nearest tenthousandths
376             int secMultRound = Math.round(10000F * sec);
377             sec = secMultRound / 10000F;
378             //Now store the second and fractional component
379             second = (int) Math.floor(sec);
380 			//validate input seconds value
381 			if ((second < 0) || (second >= 60)) {
382 				String msg = "The (rounded) second value of the TM datatype must be >=0 and <60";
383                 throw new DataTypeException(msg);
384 			} //end if
385             int fractionOfSecInt = secMultRound - (second * 10000);
386             fractionOfSec = fractionOfSecInt / 10000F;
387             String fractString = "";
388             //Now convert the fractionOfSec field to a string without the leading zero
389             if (fractionOfSec != 0.0F) {
390                 fractString = (Float.toString(fractionOfSec)).substring(1);
391             } //end if
392             //Now update the value field
393             offSet = 0;
394             //Here the offset is not defined, we should omit showing it in the
395             //return value from the getValue() method
396             omitOffsetFg = true;
397             value = value + DataTypeUtil.preAppendZeroes(second, 2) + fractString;
398         } //end try
399 
400         catch (DataTypeException e) {
401             throw e;
402         } //end catch
403 
404         catch (Exception e) {
405             throw new DataTypeException(e);
406         } //end catch
407     } //end method
408 
409     /**
410      * This method takes in the four digit (signed) GMT offset and sets the offset
411      * field
412      */
413     public void setOffset(int signedOffset) throws DataTypeException {
414         try {
415             //When this function is called an offset is being created/updated
416             //we should not omit displaying it in the return value from
417             //the getValue() method
418             omitOffsetFg = false;
419             String offsetStr = Integer.toString(signedOffset);
420             if ((signedOffset >= 0 && offsetStr.length() > 4) || (signedOffset < 0 && offsetStr.length() > 5)) {
421                 //The length of the GMT offset must be no greater than 5 characters (including the sign)
422                 String msg =
423                     "The length of the GMT offset for the TM datatype value does"
424                         + " not conform to the allowable format [+/-ZZZZ]. Value: " + signedOffset;
425                 throw new DataTypeException(msg);
426             } //end if
427             //obtain the absolute value of the input
428             int absOffset = Math.abs(signedOffset);
429             //extract the hour data from the offset value.
430             //first preappend zeros so we have a 4 char offset value (without sign)
431             offsetStr = DataTypeUtil.preAppendZeroes(absOffset, 4);
432             int hrOffsetInt = Integer.parseInt(offsetStr.substring(0, 2));
433             //check to see if the hour value is valid
434             if ((hrOffsetInt < 0) || (hrOffsetInt > 23)) {
435                 String msg = "The GMT offset hour value of the TM datatype must be >=0 and <=23";
436                 throw new DataTypeException(msg);
437             } //end if
438             //extract the minute data from the offset value.
439             int minOffsetInt = Integer.parseInt(offsetStr.substring(2, 4));
440             //check to see if the minute value is valid
441             if ((minOffsetInt < 0) || (minOffsetInt > 59)) {
442                 String msg = "The GMT offset minute value of the TM datatype must be >=0 and <=59";
443                 throw new DataTypeException(msg);
444             } //end if
445             //The input value is valid, now store it in the offset field
446             offSet = signedOffset;
447         } //end try
448 
449         catch (DataTypeException e) {
450             throw e;
451         } //end catch
452 
453         catch (Exception e) {
454             throw new DataTypeException(e);
455         } //end catch
456     } //end method
457 
458     /**
459      * Returns the HL7 TM string value.
460      */
461     public String getValue() {
462         //combine the value field with the offSet field and return it
463         String returnVal = null;
464         if (value != null && !value.equals("")) {
465             if (!omitOffsetFg && !value.equals("\"\"")) {
466                 int absOffset = Math.abs(offSet);
467                 String sign;
468                 if (offSet >= 0) {
469                     sign = "+";
470                 } //end if
471                 else {
472                     sign = "-";
473                 } //end else
474                 returnVal = value + sign + DataTypeUtil.preAppendZeroes(absOffset, 4);
475             }
476             else {
477                 returnVal = value;
478             } //end else
479         } //end if
480         return returnVal;
481     } //end method
482 
483     /**
484      * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
485      * 
486      * Note: Sets fields using precision up to the minute
487      * 
488      * @param theCalendar The calendar object from which to retrieve values 
489      * @since 1.1 
490      */
491     public void setValueToMinute(Calendar theCalendar) throws DataTypeException {
492 		if (theCalendar == null) {
493 			setValue((String)null);
494 			return;
495 		}
496 
497         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
498         int min = theCalendar.get(Calendar.MINUTE);
499         setHourMinutePrecision(hr, min);
500     }
501 
502     /**
503      * Convenience setter which sets the value using a {@link Date} object. Passing in <code>null</code> clears any existing value.
504      * 
505      * Note: Sets fields using precision up to the minute
506      * Note: Date is timezone-agnostic, representing always GMT time
507      * 
508      * @param theDate The date object from which to retrieve values
509      * @since 1.1 
510      */
511     public void setValueToMinute(Date theDate) throws DataTypeException {
512 		if (theDate == null) {
513 			setValue((String)null);
514 			return;
515 		}
516 
517 		Calendar calendar = Calendar.getInstance();
518         calendar.setTime(theDate);
519         setValueToMinute(calendar);
520     }
521     
522     /**
523      * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
524      * 
525      * Note: Sets fields using precision up to the second
526      * 
527      * @param theCalendar The calendar object from which to retrieve values 
528      * @since 1.1 
529      */
530     public void setValueToSecond(Calendar theCalendar) throws DataTypeException {
531 		if (theCalendar == null) {
532 			setValue((String)null);
533 			return;
534 		}
535 
536         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
537         int min = theCalendar.get(Calendar.MINUTE);
538         int sec = theCalendar.get(Calendar.SECOND);
539         
540         setHourMinSecondPrecision(hr, min, sec);
541     }
542 
543     /**
544      * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
545      * 
546      * Note: Sets fields using precision up to the millisecond, including timezone offset
547      * 
548      * @param theCalendar The calendar object from which to retrieve values 
549      * @since 1.1 
550      */
551     public void setValue(Calendar theCalendar) throws DataTypeException {
552 		if (theCalendar == null) {
553 			setValue((String)null);
554 			return;
555 		}
556 
557         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
558         int min = theCalendar.get(Calendar.MINUTE);
559         float sec = theCalendar.get(Calendar.SECOND) + (theCalendar.get(Calendar.MILLISECOND) / 1000.0F);
560         setHourMinSecondPrecision(hr, min, sec);
561         
562         // 3410095: care for integer overflow and timezones not at the full hour, e.g. India
563         int hourOffset= theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);   
564         int minuteOffset = (theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
565         int zoneOffset = hourOffset * 100 + minuteOffset;
566         setOffset(zoneOffset);
567     }
568    
569     /**
570      * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
571      * 
572      * Note: Sets fields using precision up to the millisecond, and sets the timezone offset to
573      * the current system offset
574      * Note: Date is timezone-agnostic, representing always GMT time
575      * 
576      * @param theDate The calendar object from which to retrieve values 
577      * @since 1.1 
578      */
579 	public void setValue(Date theDate) throws DataTypeException {
580 		if (theDate == null) {
581 			setValue((String)null);
582 			return;
583 		}
584 
585 		GregorianCalendar cal = new GregorianCalendar();
586 		cal.setTime(theDate);
587 		setValue(cal);
588 	}
589     
590     /**
591      * Convenience setter which sets the value using a {@link Date} object. Passing in <code>null</code> clears any existing value.
592      * 
593      * Note: Sets fields using precision up to the second
594      * Note: Date is timezone-agnostic, representing always GMT time
595      * 
596      * @param theDate The date object from which to retrieve values
597      * @since 1.1 
598      */
599     public void setValueToSecond(Date theDate) throws DataTypeException {
600 		if (theDate == null) {
601 			setValue((String)null);
602 			return;
603 		}
604 
605         Calendar calendar = Calendar.getInstance();
606         calendar.setTime(theDate);
607         setValueToSecond(calendar);
608     }
609     
610     /**
611      * <p>Return the value as a calendar object.</p> 
612      * 
613      * <b>Note that only the time component of the return value is set to
614      * the value from this object. Returned value will have today's date</b> 
615      * @since 1.1 
616      */
617     public Calendar getValueAsCalendar() {
618         int gmtOff = getGMTOffset();
619         Calendar retVal;
620         if (gmtOff != GMT_OFFSET_NOT_SET_VALUE && !omitOffsetFg) {
621             int hrOffset = gmtOff / 100;
622             int minOffset = Math.abs(gmtOff % 100);
623             String timeZone = String.format("GMT%+d:%02d", hrOffset, minOffset);
624             retVal = new GregorianCalendar(TimeZone.getTimeZone(timeZone));
625         } else {
626             retVal = Calendar.getInstance();
627         }
628 
629         retVal.set(Calendar.HOUR_OF_DAY, getHour());
630         retVal.set(Calendar.MINUTE, getMinute());
631         retVal.set(Calendar.SECOND, getSecond());
632         float fractSecond = getFractSecond();
633         retVal.set(Calendar.MILLISECOND, (int) Math.round(fractSecond * 1000.0));
634 
635         return retVal;
636     }
637 
638     
639     /**
640      * <p>Return the value as a date object</p>
641      * 
642      * <b>Note that only the time component of the return value is set to
643      * the value from this object. Returned value will have today's date</b> 
644      * Note: Date is timezone-agnostic, representing always GMT time
645      * @since 1.1 
646      */
647     public Date getValueAsDate() {
648         return getValueAsCalendar().getTime();
649     }    
650     
651     /**
652      * Returns the hour as an integer.
653      */
654     public int getHour() {
655         return hour;
656     } //end method
657 
658     /**
659      * Returns the minute as an integer.
660      */
661     public int getMinute() {
662         return minute;
663     } //end method
664 
665     /**
666      * Returns the second as an integer.
667      */
668     public int getSecond() {
669         return second;
670     } //end method
671 
672     /**
673      * Returns the fractional second value as a float.
674      */
675     public float getFractSecond() {
676         return fractionOfSec;
677     } //end method
678 
679     /**
680      * Returns the GMT offset value as an integer, {@link #GMT_OFFSET_NOT_SET_VALUE} if not set.  
681      */
682     public int getGMTOffset() {
683         return offSet;
684     } //end method
685     
686     /**
687      * Returns a string value representing the input Gregorian Calendar object in
688      * an Hl7 Time Format.
689      */
690     public static String toHl7TMFormat(GregorianCalendar cal) throws DataTypeException {
691         String val;
692         try {
693             //set the input cal object so that it can report errors
694             //on it's value
695             cal.setLenient(false);
696             int calHour = cal.get(GregorianCalendar.HOUR_OF_DAY);
697             int calMin = cal.get(GregorianCalendar.MINUTE);
698             int calSec = cal.get(GregorianCalendar.SECOND);
699             int calMilli = cal.get(GregorianCalendar.MILLISECOND);
700             //the inputs seconds and milli seconds should be combined into a float type
701             float fractSec = calMilli / 1000F;
702             float calSecFloat = calSec + fractSec;
703             int calOffset = cal.get(GregorianCalendar.ZONE_OFFSET) + cal.get(GregorianCalendar.DST_OFFSET); 
704             //Note the input's Offset value is in milliseconds, we must convert it to
705             //a 4 digit integer in the HL7 Offset format.
706             int offSetSignInt;
707             if (calOffset < 0) {
708                 offSetSignInt = -1;
709             }
710             else {
711                 offSetSignInt = 1;
712             }
713             //get the absolute value of the gmtOffSet
714             int absGmtOffSet = Math.abs(calOffset);
715             int gmtOffSetHours = absGmtOffSet / (3600 * 1000);
716             int gmtOffSetMin = (absGmtOffSet / 60000) % (60);
717             //reset calOffset
718             calOffset = ((gmtOffSetHours * 100) + gmtOffSetMin) * offSetSignInt;
719             //Create an object of the TS class and populate it with the above values
720             //then return the HL7 string value from the object
721             CommonTMitive/CommonTM.html#CommonTM">CommonTM tm = new CommonTM();
722             tm.setHourMinSecondPrecision(calHour, calMin, calSecFloat);
723             tm.setOffset(calOffset);
724             val = tm.getValue();
725         } // end try
726 
727         catch (DataTypeException e) {
728             throw e;
729         } //end catch
730 
731         catch (Exception e) {
732             throw new DataTypeException(e);
733         } //end catch
734         return val;
735     } //end method
736 
737 } //end class