Coverage Report - ca.uhn.hl7v2.model.primitive.CommonTM
 
Classes in this File Line Coverage Branch Coverage Complexity
CommonTM
87%
256/293
84%
115/136
6.136
 
 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  486
     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  469
     public CommonTM() {
 97  
         //initialize all DT fields
 98  469
         value = null;
 99  469
         hour = 0;
 100  469
         minute = 0;
 101  469
         second = 0;
 102  469
         fractionOfSec = 0;
 103  469
         offSet = GMT_OFFSET_NOT_SET_VALUE;
 104  469
     } //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  17
     public CommonTM(String val) throws DataTypeException {
 112  17
         this.setValue(val);
 113  17
     } //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  145
         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  133
             int d = val.indexOf(".");
 132  133
             int sp = val.indexOf("+");
 133  133
             int sm = val.indexOf("-");
 134  133
             int indexOfSign = -1;
 135  133
             boolean offsetExists = false;
 136  133
             if ((sp != -1) || (sm != -1))
 137  73
                 offsetExists = true;
 138  133
             if (sp != -1)
 139  24
                 indexOfSign = sp;
 140  133
             if (sm != -1)
 141  49
                 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  133
                 String timeVal = val;
 149  133
                 String tempOffset = null;
 150  133
                 if (offsetExists) {
 151  73
                     timeVal = val.substring(0, indexOfSign);
 152  73
                     tempOffset = val.substring(indexOfSign);
 153  
                 } //end if
 154  
 
 155  133
                 if (offsetExists && (tempOffset.length() != 5)) {
 156  
                     //The length of the GMT offset must be 5 characters (including the sign)
 157  12
                     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  12
                     DataTypeException e = new DataTypeException(msg);
 161  12
                     throw e;
 162  
                 } //end if
 163  
 
 164  121
                 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  52
                     if ((timeVal.length() < 8) || (timeVal.length() > 11)) {
 168  3
                         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  3
                         DataTypeException e = new DataTypeException(msg);
 172  3
                         throw e;
 173  
                     } //end if
 174  
                 } //end if
 175  
 
 176  118
                 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  69
                     if ((timeVal.length() != 2) && (timeVal.length() != 4) && (timeVal.length() != 6)) {
 180  11
                         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  11
                         DataTypeException e = new DataTypeException(msg);
 184  11
                         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  107
                 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  107
                     int hrInt = Integer.parseInt(timeVal.substring(0, 2));
 193  
                     //check to see if the hour value is valid
 194  107
                     if ((hrInt < 0) || (hrInt > 23)) {
 195  1
                         String msg = "The hour value of the TM datatype must be >=0 and <=23";
 196  1
                         DataTypeException e = new DataTypeException(msg);
 197  1
                         throw e;
 198  
                     } //end if
 199  106
                     hour = hrInt;
 200  
                 } //end if
 201  
 
 202  106
                 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  103
                     int minInt = Integer.parseInt(timeVal.substring(2, 4));
 207  
                     //check to see if the minute value is valid
 208  103
                     if ((minInt < 0) || (minInt > 59)) {
 209  1
                         String msg = "The minute value of the TM datatype must be >=0 and <=59";
 210  1
                         DataTypeException e = new DataTypeException(msg);
 211  1
                         throw e;
 212  
                     } //end if
 213  102
                     minute = minInt;
 214  
                 } //end if
 215  
 
 216  105
                 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  82
                     int secInt = Integer.parseInt(timeVal.substring(4, 6));
 221  
                     //check to see if the seconds value is valid
 222  82
                     if ((secInt < 0) || (secInt > 59)) {
 223  1
                         String msg = "The seconds value of the TM datatype must be >=0 and <=59";
 224  1
                         DataTypeException e = new DataTypeException(msg);
 225  1
                         throw e;
 226  
                     } //end if
 227  81
                     second = secInt;
 228  
                 } //end if
 229  
 
 230  104
                 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  49
                     float fract = Float.parseFloat(timeVal.substring(6));
 235  
                     //check to see if the fractional second value is valid
 236  49
                     if ((fract < 0) || (fract >= 1)) {
 237  0
                         String msg = "The fractional second value of the TM datatype must be >= 0 and < 1";
 238  0
                         DataTypeException e = new DataTypeException(msg);
 239  0
                         throw e;
 240  
                     } //end if
 241  49
                     fractionOfSec = fract;
 242  
                 } //end if
 243  
 
 244  
                 //We will now try to validate the tempOffset portion of the TM datatype value
 245  104
                 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  59
                     omitOffsetFg = false;
 249  
                     //remove the sign from the temp offset
 250  59
                     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  59
                     int offsetInt = Integer.parseInt(tempOffsetNoS.substring(0, 2));
 254  
                     //check to see if the hour value is valid
 255  59
                     if ((offsetInt < 0) || (offsetInt > 23)) {
 256  0
                         String msg = "The GMT offset hour value of the TM datatype must be >=0 and <=23";
 257  0
                         DataTypeException e = new DataTypeException(msg);
 258  0
                         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  59
                     offsetInt = Integer.parseInt(tempOffsetNoS.substring(2, 4));
 263  
                     //check to see if the minute value is valid
 264  59
                     if ((offsetInt < 0) || (offsetInt > 59)) {
 265  6
                         String msg = "The GMT offset minute value of the TM datatype must be >=0 and <=59";
 266  6
                         DataTypeException e = new DataTypeException(msg);
 267  6
                         throw e;
 268  
                     } //end if
 269  
                     //validation done, update the offSet field
 270  53
                     offSet = Integer.parseInt(tempOffsetNoS);
 271  
                     //add the sign back to the offset if it is negative
 272  53
                     if (sm != -1) {
 273  36
                         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  98
                 if (!offsetExists) {
 281  45
                     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  98
                 value = timeVal;
 288  
             } //end try
 289  
 
 290  35
             catch (DataTypeException e) {
 291  35
                 throw e;
 292  
             } //end catch
 293  
 
 294  0
             catch (Exception e) {
 295  0
                 throw new DataTypeException(e);
 296  98
             } //end catch
 297  98
         } //end if
 298  
         else {
 299  
             //set the private value field to null or empty space.
 300  12
             value = val;
 301  
         } //end else
 302  110
     } //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  315
             if ((hr < 0) || (hr > 23)) {
 313  13
                 String msg = "The hour value of the TM datatype must be >=0 and <=23";
 314  13
                 DataTypeException e = new DataTypeException(msg);
 315  13
                 throw e;
 316  
             } //end if
 317  302
             hour = hr;
 318  302
             minute = 0;
 319  302
             second = 0;
 320  302
             fractionOfSec = 0;
 321  302
             offSet = 0;
 322  
             //Here the offset is not defined, we should omit showing it in the
 323  
             //return value from the getValue() method
 324  302
             omitOffsetFg = true;
 325  302
             value = DataTypeUtil.preAppendZeroes(hr, 2);
 326  
         } //end try
 327  
 
 328  13
         catch (DataTypeException e) {
 329  13
             throw e;
 330  
         } //end catch
 331  
 
 332  0
         catch (Exception e) {
 333  0
             throw new DataTypeException(e.getMessage());
 334  302
         } //end catch
 335  
 
 336  302
     } //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  309
             this.setHourPrecision(hr);
 346  
             //validate input minute value
 347  298
             if ((min < 0) || (min > 59)) {
 348  8
                 String msg = "The minute value of the TM datatype must be >=0 and <=59";
 349  8
                 DataTypeException e = new DataTypeException(msg);
 350  8
                 throw e;
 351  
             } //end if
 352  290
             minute = min;
 353  290
             second = 0;
 354  290
             fractionOfSec = 0;
 355  290
             offSet = 0;
 356  
             //Here the offset is not defined, we should omit showing it in the
 357  
             //return value from the getValue() method
 358  290
             omitOffsetFg = true;
 359  290
             value = value + DataTypeUtil.preAppendZeroes(min, 2);
 360  
         } //end try
 361  
 
 362  19
         catch (DataTypeException e) {
 363  19
             throw e;
 364  
         } //end catch
 365  
 
 366  0
         catch (Exception e) {
 367  0
             throw new DataTypeException(e.getMessage());
 368  290
         } //end catch
 369  290
     } //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  277
             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  267
             int secMultRound = Math.round(10000F * sec);
 388  267
             sec = secMultRound / 10000F;
 389  
             //Now store the second and fractional component
 390  267
             second = (int) Math.floor(sec);
 391  
                         //validate input seconds value
 392  267
                         if ((second < 0) || (second >= 60)) {
 393  7
                                 String msg = "The (rounded) second value of the TM datatype must be >=0 and <60";
 394  7
                                 DataTypeException e = new DataTypeException(msg);
 395  7
                                 throw e;
 396  
                         } //end if
 397  260
             int fractionOfSecInt = (int) (secMultRound - (second * 10000));
 398  260
             fractionOfSec = fractionOfSecInt / 10000F;
 399  260
             String fractString = "";
 400  
             //Now convert the fractionOfSec field to a string without the leading zero
 401  260
             if (fractionOfSec != 0.0F) {
 402  228
                 fractString = (Float.toString(fractionOfSec)).substring(1);
 403  
             } //end if
 404  
             //Now update the value field
 405  260
             offSet = 0;
 406  
             //Here the offset is not defined, we should omit showing it in the
 407  
             //return value from the getValue() method
 408  260
             omitOffsetFg = true;
 409  260
             value = value + DataTypeUtil.preAppendZeroes(second, 2) + fractString;
 410  
         } //end try
 411  
 
 412  17
         catch (DataTypeException e) {
 413  17
             throw e;
 414  
         } //end catch
 415  
 
 416  0
         catch (Exception e) {
 417  0
             throw new DataTypeException(e);
 418  260
         } //end catch
 419  260
     } //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  272
             omitOffsetFg = false;
 431  272
             String offsetStr = Integer.toString(signedOffset);
 432  272
             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  2
                 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  2
                 DataTypeException e = new DataTypeException(msg);
 438  2
                 throw e;
 439  
             } //end if
 440  
             //obtain the absolute value of the input
 441  270
             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  270
             offsetStr = DataTypeUtil.preAppendZeroes(absOffset, 4);
 445  270
             int hrOffsetInt = Integer.parseInt(offsetStr.substring(0, 2));
 446  
             //check to see if the hour value is valid
 447  270
             if ((hrOffsetInt < 0) || (hrOffsetInt > 23)) {
 448  1
                 String msg = "The GMT offset hour value of the TM datatype must be >=0 and <=23";
 449  1
                 DataTypeException e = new DataTypeException(msg);
 450  1
                 throw e;
 451  
             } //end if
 452  
             //extract the minute data from the offset value.
 453  269
             int minOffsetInt = Integer.parseInt(offsetStr.substring(2, 4));
 454  
             //check to see if the minute value is valid
 455  269
             if ((minOffsetInt < 0) || (minOffsetInt > 59)) {
 456  8
                 String msg = "The GMT offset minute value of the TM datatype must be >=0 and <=59";
 457  8
                 DataTypeException e = new DataTypeException(msg);
 458  8
                 throw e;
 459  
             } //end if
 460  
             //The input value is valid, now store it in the offset field
 461  261
             offSet = signedOffset;
 462  
         } //end try
 463  
 
 464  11
         catch (DataTypeException e) {
 465  11
             throw e;
 466  
         } //end catch
 467  
 
 468  0
         catch (Exception e) {
 469  0
             throw new DataTypeException(e);
 470  261
         } //end catch
 471  261
     } //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  2084
         String returnVal = null;
 479  2084
         if (value != null && !value.equals("")) {
 480  2033
             if (omitOffsetFg == false && !value.equals("\"\"")) {
 481  1592
                 int absOffset = Math.abs(offSet);
 482  1592
                 String sign = "";
 483  1592
                 if (offSet >= 0) {
 484  166
                     sign = "+";
 485  
                 } //end if
 486  
                 else {
 487  1426
                     sign = "-";
 488  
                 } //end else
 489  1592
                 returnVal = value + sign + DataTypeUtil.preAppendZeroes(absOffset, 4);
 490  1592
             }
 491  
             else {
 492  441
                 returnVal = value;
 493  
             } //end else
 494  
         } //end if
 495  2084
         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  2
                 if (theCalendar == null) {
 508  0
                         setValue((String)null);
 509  0
                         return;
 510  
                 }
 511  
 
 512  2
         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
 513  2
         int min = theCalendar.get(Calendar.MINUTE);
 514  2
         setHourMinutePrecision(hr, min);
 515  2
     }
 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 theDate The date object from which to retrieve values
 524  
      * @since 1.1 
 525  
      */
 526  
     public void setValueToMinute(Date theDate) throws DataTypeException {
 527  1
                 if (theDate == null) {
 528  0
                         setValue((String)null);
 529  0
                         return;
 530  
                 }
 531  
 
 532  1
                 Calendar calendar = Calendar.getInstance();
 533  1
         calendar.setTime(theDate);
 534  1
         setValueToMinute(calendar);
 535  1
     }
 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  2
                 if (theCalendar == null) {
 547  0
                         setValue((String)null);
 548  0
                         return;
 549  
                 }
 550  
 
 551  2
         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
 552  2
         int min = theCalendar.get(Calendar.MINUTE);
 553  2
         int sec = theCalendar.get(Calendar.SECOND);
 554  
         
 555  2
         setHourMinSecondPrecision(hr, min, sec);
 556  2
     }
 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  5
                 if (theCalendar == null) {
 568  0
                         setValue((String)null);
 569  0
                         return;
 570  
                 }
 571  
 
 572  5
         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
 573  5
         int min = theCalendar.get(Calendar.MINUTE);
 574  5
         float sec = theCalendar.get(Calendar.SECOND) + (theCalendar.get(Calendar.MILLISECOND) / 1000.0F);
 575  5
         setHourMinSecondPrecision(hr, min, sec);
 576  
         
 577  
         // 3410095: care for integer overflow and timezones not at the full hour, e.g. India
 578  5
         int hourOffset= theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);   
 579  5
         int minuteOffset = (theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
 580  5
         int zoneOffset = hourOffset * 100 + minuteOffset;
 581  5
         setOffset(zoneOffset);
 582  5
     }
 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  0
                 if (theDate == null) {
 596  0
                         setValue((String)null);
 597  0
                         return;
 598  
                 }
 599  
 
 600  0
                 GregorianCalendar cal = new GregorianCalendar();
 601  0
                 cal.setTime(theDate);
 602  0
                 setValue(cal);
 603  0
         }
 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 theDate The date object from which to retrieve values
 612  
      * @since 1.1 
 613  
      */
 614  
     public void setValueToSecond(Date theDate) throws DataTypeException {
 615  1
                 if (theDate == null) {
 616  0
                         setValue((String)null);
 617  0
                         return;
 618  
                 }
 619  
 
 620  1
         Calendar calendar = Calendar.getInstance();
 621  1
         calendar.setTime(theDate);
 622  1
         setValueToSecond(calendar);
 623  1
     }
 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  22
         Calendar retVal = Calendar.getInstance();
 634  22
         retVal.set(Calendar.HOUR_OF_DAY, getHour());
 635  22
         retVal.set(Calendar.MINUTE, getMinute());
 636  22
         retVal.set(Calendar.SECOND, getSecond());
 637  
         
 638  22
         float fractSecond = getFractSecond();
 639  22
         retVal.set(Calendar.MILLISECOND, (int) (fractSecond * 1000.0));
 640  
         
 641  22
         int gmtOff = getGMTOffset();
 642  22
         if (gmtOff != GMT_OFFSET_NOT_SET_VALUE && !omitOffsetFg) {
 643  10
             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  10
             if (retVal.getTimeZone().getRawOffset() != retVal.get(Calendar.ZONE_OFFSET)) {
 659  5
                     int hrOffset = gmtOff / 100;
 660  5
                     int minOffset = gmtOff % 100;
 661  5
                     StringBuilder tzBuilder = new StringBuilder("GMT");
 662  
                     
 663  5
                     if (hrOffset < 0) {
 664  5
                             tzBuilder.append('-');
 665  
                     }
 666  5
                     tzBuilder.append(Math.abs(hrOffset));
 667  5
                     tzBuilder.append(':');
 668  5
                     if (minOffset < 10) {
 669  5
                             tzBuilder.append('0');
 670  
                     }
 671  5
                     tzBuilder.append(minOffset);
 672  
                     
 673  5
                     retVal.setTimeZone(TimeZone.getTimeZone(tzBuilder.toString()));
 674  
             }
 675  
             
 676  
         }
 677  
         
 678  22
         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  2
         return getValueAsCalendar().getTime();
 692  
     }    
 693  
     
 694  
     /**
 695  
      * Returns the hour as an integer.
 696  
      */
 697  
     public int getHour() {
 698  24
         return hour;
 699  
     } //end method
 700  
 
 701  
     /**
 702  
      * Returns the minute as an integer.
 703  
      */
 704  
     public int getMinute() {
 705  24
         return minute;
 706  
     } //end method
 707  
 
 708  
     /**
 709  
      * Returns the second as an integer.
 710  
      */
 711  
     public int getSecond() {
 712  24
         return second;
 713  
     } //end method
 714  
 
 715  
     /**
 716  
      * Returns the fractional second value as a float.
 717  
      */
 718  
     public float getFractSecond() {
 719  24
         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  68
         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  5
         String val = "";
 735  
         try {
 736  
             //set the input cal object so that it can report errors
 737  
             //on it's value
 738  5
             cal.setLenient(false);
 739  5
             int calHour = cal.get(GregorianCalendar.HOUR_OF_DAY);
 740  5
             int calMin = cal.get(GregorianCalendar.MINUTE);
 741  5
             int calSec = cal.get(GregorianCalendar.SECOND);
 742  5
             int calMilli = cal.get(GregorianCalendar.MILLISECOND);
 743  
             //the inputs seconds and milli seconds should be combined into a float type
 744  5
             float fractSec = calMilli / 1000F;
 745  5
             float calSecFloat = calSec + fractSec;
 746  5
             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  5
             if (calOffset < 0) {
 751  3
                 offSetSignInt = -1;
 752  
             }
 753  
             else {
 754  2
                 offSetSignInt = 1;
 755  
             }
 756  
             //get the absolute value of the gmtOffSet
 757  5
             int absGmtOffSet = Math.abs(calOffset);
 758  5
             int gmtOffSetHours = absGmtOffSet / (3600 * 1000);
 759  5
             int gmtOffSetMin = (absGmtOffSet / 60000) % (60);
 760  
             //reset calOffset
 761  5
             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  5
             CommonTM tm = new CommonTM();
 765  5
             tm.setHourMinSecondPrecision(calHour, calMin, calSecFloat);
 766  5
             tm.setOffset(calOffset);
 767  5
             val = tm.getValue();
 768  
         } // end try
 769  
 
 770  0
         catch (DataTypeException e) {
 771  0
             throw e;
 772  
         } //end catch
 773  
 
 774  0
         catch (Exception e) {
 775  0
             throw new DataTypeException(e);
 776  5
         } //end catch
 777  5
         return val;
 778  
     } //end method
 779  
 
 780  
 } //end class