Coverage Report - ca.uhn.hl7v2.model.primitive.CommonTM
 
Classes in this File Line Coverage Branch Coverage Complexity
CommonTM
87%
248/285
85%
111/130
6
 
 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  4378
     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  4293
     public CommonTM() {
 97  
         //initialize all DT fields
 98  4293
         value = null;
 99  4293
         hour = 0;
 100  4293
         minute = 0;
 101  4293
         second = 0;
 102  4293
         fractionOfSec = 0;
 103  4293
         offSet = GMT_OFFSET_NOT_SET_VALUE;
 104  4293
     } //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  85
     public CommonTM(String val) throws DataTypeException {
 112  85
         this.setValue(val);
 113  85
     } //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  725
         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  665
             int d = val.indexOf(".");
 132  665
             int sp = val.indexOf("+");
 133  665
             int sm = val.indexOf("-");
 134  665
             int indexOfSign = -1;
 135  665
             boolean offsetExists = false;
 136  665
             if ((sp != -1) || (sm != -1))
 137  365
                 offsetExists = true;
 138  665
             if (sp != -1)
 139  120
                 indexOfSign = sp;
 140  665
             if (sm != -1)
 141  245
                 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  665
                 String timeVal = val;
 149  665
                 String tempOffset = null;
 150  665
                 if (offsetExists) {
 151  365
                     timeVal = val.substring(0, indexOfSign);
 152  365
                     tempOffset = val.substring(indexOfSign);
 153  
                 } //end if
 154  
 
 155  665
                 if (offsetExists && (tempOffset.length() != 5)) {
 156  
                     //The length of the GMT offset must be 5 characters (including the sign)
 157  60
                     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  60
                     DataTypeException e = new DataTypeException(msg);
 161  60
                     throw e;
 162  
                 } //end if
 163  
 
 164  605
                 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  260
                     if ((timeVal.length() < 8) || (timeVal.length() > 11)) {
 168  15
                         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  15
                         DataTypeException e = new DataTypeException(msg);
 172  15
                         throw e;
 173  
                     } //end if
 174  
                 } //end if
 175  
 
 176  590
                 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  345
                     if ((timeVal.length() != 2) && (timeVal.length() != 4) && (timeVal.length() != 6)) {
 180  55
                         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  55
                         DataTypeException e = new DataTypeException(msg);
 184  55
                         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  535
                 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  535
                     int hrInt = Integer.parseInt(timeVal.substring(0, 2));
 193  
                     //check to see if the hour value is valid
 194  535
                     if ((hrInt < 0) || (hrInt > 23)) {
 195  5
                         String msg = "The hour value of the TM datatype must be >=0 and <=23";
 196  5
                         DataTypeException e = new DataTypeException(msg);
 197  5
                         throw e;
 198  
                     } //end if
 199  530
                     hour = hrInt;
 200  
                 } //end if
 201  
 
 202  530
                 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  515
                     int minInt = Integer.parseInt(timeVal.substring(2, 4));
 207  
                     //check to see if the minute value is valid
 208  515
                     if ((minInt < 0) || (minInt > 59)) {
 209  5
                         String msg = "The minute value of the TM datatype must be >=0 and <=59";
 210  5
                         DataTypeException e = new DataTypeException(msg);
 211  5
                         throw e;
 212  
                     } //end if
 213  510
                     minute = minInt;
 214  
                 } //end if
 215  
 
 216  525
                 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  410
                     int secInt = Integer.parseInt(timeVal.substring(4, 6));
 221  
                     //check to see if the seconds value is valid
 222  410
                     if ((secInt < 0) || (secInt > 59)) {
 223  5
                         String msg = "The seconds value of the TM datatype must be >=0 and <=59";
 224  5
                         DataTypeException e = new DataTypeException(msg);
 225  5
                         throw e;
 226  
                     } //end if
 227  405
                     second = secInt;
 228  
                 } //end if
 229  
 
 230  520
                 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  245
                     float fract = Float.parseFloat(timeVal.substring(6));
 235  
                     //check to see if the fractional second value is valid
 236  245
                     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  245
                     fractionOfSec = fract;
 242  
                 } //end if
 243  
 
 244  
                 //We will now try to validate the tempOffset portion of the TM datatype value
 245  520
                 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  295
                     omitOffsetFg = false;
 249  
                     //remove the sign from the temp offset
 250  295
                     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  295
                     int offsetInt = Integer.parseInt(tempOffsetNoS.substring(0, 2));
 254  
                     //check to see if the hour value is valid
 255  295
                     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  295
                     offsetInt = Integer.parseInt(tempOffsetNoS.substring(2, 4));
 263  
                     //check to see if the minute value is valid
 264  295
                     if ((offsetInt < 0) || (offsetInt > 59)) {
 265  30
                         String msg = "The GMT offset minute value of the TM datatype must be >=0 and <=59";
 266  30
                         DataTypeException e = new DataTypeException(msg);
 267  30
                         throw e;
 268  
                     } //end if
 269  
                     //validation done, update the offSet field
 270  265
                     offSet = Integer.parseInt(tempOffsetNoS);
 271  
                     //add the sign back to the offset if it is negative
 272  265
                     if (sm != -1) {
 273  180
                         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  490
                 if (!offsetExists) {
 281  225
                     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  490
                 value = timeVal;
 288  
             } //end try
 289  
 
 290  175
             catch (DataTypeException e) {
 291  175
                 throw e;
 292  
             } //end catch
 293  
 
 294  0
             catch (Exception e) {
 295  0
                 throw new DataTypeException(e);
 296  490
             } //end catch
 297  490
         } //end if
 298  
         else {
 299  
             //set the private value field to null or empty space.
 300  60
             value = val;
 301  
         } //end else
 302  550
     } //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  3523
             if ((hr < 0) || (hr > 23)) {
 313  65
                 String msg = "The hour value of the TM datatype must be >=0 and <=23";
 314  65
                 DataTypeException e = new DataTypeException(msg);
 315  65
                 throw e;
 316  
             } //end if
 317  3458
             hour = hr;
 318  3458
             minute = 0;
 319  3458
             second = 0;
 320  3458
             fractionOfSec = 0;
 321  3458
             offSet = 0;
 322  
             //Here the offset is not defined, we should omit showing it in the
 323  
             //return value from the getValue() method
 324  3458
             omitOffsetFg = true;
 325  3458
             value = DataTypeUtil.preAppendZeroes(hr, 2);
 326  
         } //end try
 327  
 
 328  65
         catch (DataTypeException e) {
 329  65
             throw e;
 330  
         } //end catch
 331  
 
 332  0
         catch (Exception e) {
 333  0
             throw new DataTypeException(e.getMessage());
 334  3458
         } //end catch
 335  
 
 336  3458
     } //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  3493
             this.setHourPrecision(hr);
 346  
             //validate input minute value
 347  3438
             if ((min < 0) || (min > 59)) {
 348  40
                 String msg = "The minute value of the TM datatype must be >=0 and <=59";
 349  40
                 DataTypeException e = new DataTypeException(msg);
 350  40
                 throw e;
 351  
             } //end if
 352  3398
             minute = min;
 353  3398
             second = 0;
 354  3398
             fractionOfSec = 0;
 355  3398
             offSet = 0;
 356  
             //Here the offset is not defined, we should omit showing it in the
 357  
             //return value from the getValue() method
 358  3398
             omitOffsetFg = true;
 359  3398
             value = value + DataTypeUtil.preAppendZeroes(min, 2);
 360  
         } //end try
 361  
 
 362  95
         catch (DataTypeException e) {
 363  95
             throw e;
 364  
         } //end catch
 365  
 
 366  0
         catch (Exception e) {
 367  0
             throw new DataTypeException(e.getMessage());
 368  3398
         } //end catch
 369  3398
     } //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  3328
             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  3278
             int secMultRound = Math.round(10000F * sec);
 388  3278
             sec = secMultRound / 10000F;
 389  
             //Now store the second and fractional component
 390  3278
             second = (int) Math.floor(sec);
 391  
                         //validate input seconds value
 392  3278
                         if ((second < 0) || (second >= 60)) {
 393  35
                                 String msg = "The (rounded) second value of the TM datatype must be >=0 and <60";
 394  35
                                 DataTypeException e = new DataTypeException(msg);
 395  35
                                 throw e;
 396  
                         } //end if
 397  3243
             int fractionOfSecInt = (int) (secMultRound - (second * 10000));
 398  3243
             fractionOfSec = fractionOfSecInt / 10000F;
 399  3243
             String fractString = "";
 400  
             //Now convert the fractionOfSec field to a string without the leading zero
 401  3243
             if (fractionOfSec != 0.0F) {
 402  1732
                 fractString = (Float.toString(fractionOfSec)).substring(1);
 403  
             } //end if
 404  
             //Now update the value field
 405  3243
             offSet = 0;
 406  
             //Here the offset is not defined, we should omit showing it in the
 407  
             //return value from the getValue() method
 408  3243
             omitOffsetFg = true;
 409  3243
             value = value + DataTypeUtil.preAppendZeroes(second, 2) + fractString;
 410  
         } //end try
 411  
 
 412  85
         catch (DataTypeException e) {
 413  85
             throw e;
 414  
         } //end catch
 415  
 
 416  0
         catch (Exception e) {
 417  0
             throw new DataTypeException(e);
 418  3243
         } //end catch
 419  3243
     } //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  3303
             omitOffsetFg = false;
 431  3303
             String offsetStr = Integer.toString(signedOffset);
 432  3303
             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  10
                 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  10
                 DataTypeException e = new DataTypeException(msg);
 438  10
                 throw e;
 439  
             } //end if
 440  
             //obtain the absolute value of the input
 441  3293
             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  3293
             offsetStr = DataTypeUtil.preAppendZeroes(absOffset, 4);
 445  3293
             int hrOffsetInt = Integer.parseInt(offsetStr.substring(0, 2));
 446  
             //check to see if the hour value is valid
 447  3293
             if ((hrOffsetInt < 0) || (hrOffsetInt > 23)) {
 448  5
                 String msg = "The GMT offset hour value of the TM datatype must be >=0 and <=23";
 449  5
                 DataTypeException e = new DataTypeException(msg);
 450  5
                 throw e;
 451  
             } //end if
 452  
             //extract the minute data from the offset value.
 453  3288
             int minOffsetInt = Integer.parseInt(offsetStr.substring(2, 4));
 454  
             //check to see if the minute value is valid
 455  3288
             if ((minOffsetInt < 0) || (minOffsetInt > 59)) {
 456  40
                 String msg = "The GMT offset minute value of the TM datatype must be >=0 and <=59";
 457  40
                 DataTypeException e = new DataTypeException(msg);
 458  40
                 throw e;
 459  
             } //end if
 460  
             //The input value is valid, now store it in the offset field
 461  3248
             offSet = signedOffset;
 462  
         } //end try
 463  
 
 464  55
         catch (DataTypeException e) {
 465  55
             throw e;
 466  
         } //end catch
 467  
 
 468  0
         catch (Exception e) {
 469  0
             throw new DataTypeException(e);
 470  3248
         } //end catch
 471  3248
     } //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  21658
         String returnVal = null;
 479  21658
         if (value != null && !value.equals("")) {
 480  21403
             if (omitOffsetFg == false && !value.equals("\"\"")) {
 481  19198
                 int absOffset = Math.abs(offSet);
 482  19198
                 String sign = "";
 483  19198
                 if (offSet >= 0) {
 484  5870
                     sign = "+";
 485  
                 } //end if
 486  
                 else {
 487  13328
                     sign = "-";
 488  
                 } //end else
 489  19198
                 returnVal = value + sign + DataTypeUtil.preAppendZeroes(absOffset, 4);
 490  19198
             }
 491  
             else {
 492  2205
                 returnVal = value;
 493  
             } //end else
 494  
         } //end if
 495  21658
         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  10
                 if (theCalendar == null) {
 508  0
                         setValue((String)null);
 509  0
                         return;
 510  
                 }
 511  
 
 512  10
         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
 513  10
         int min = theCalendar.get(Calendar.MINUTE);
 514  10
         setHourMinutePrecision(hr, min);
 515  10
     }
 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  5
                 if (theDate == null) {
 528  0
                         setValue((String)null);
 529  0
                         return;
 530  
                 }
 531  
 
 532  5
                 Calendar calendar = Calendar.getInstance();
 533  5
         calendar.setTime(theDate);
 534  5
         setValueToMinute(calendar);
 535  5
     }
 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  10
                 if (theCalendar == null) {
 547  0
                         setValue((String)null);
 548  0
                         return;
 549  
                 }
 550  
 
 551  10
         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
 552  10
         int min = theCalendar.get(Calendar.MINUTE);
 553  10
         int sec = theCalendar.get(Calendar.SECOND);
 554  
         
 555  10
         setHourMinSecondPrecision(hr, min, sec);
 556  10
     }
 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  25
                 if (theCalendar == null) {
 568  0
                         setValue((String)null);
 569  0
                         return;
 570  
                 }
 571  
 
 572  25
         int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
 573  25
         int min = theCalendar.get(Calendar.MINUTE);
 574  25
         float sec = theCalendar.get(Calendar.SECOND) + (theCalendar.get(Calendar.MILLISECOND) / 1000.0F);
 575  25
         setHourMinSecondPrecision(hr, min, sec);
 576  
         
 577  
         // 3410095: care for integer overflow and timezones not at the full hour, e.g. India
 578  25
         int hourOffset= theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);   
 579  25
         int minuteOffset = (theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
 580  25
         int zoneOffset = hourOffset * 100 + minuteOffset;
 581  25
         setOffset(zoneOffset);
 582  25
     }
 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  5
                 if (theDate == null) {
 616  0
                         setValue((String)null);
 617  0
                         return;
 618  
                 }
 619  
 
 620  5
         Calendar calendar = Calendar.getInstance();
 621  5
         calendar.setTime(theDate);
 622  5
         setValueToSecond(calendar);
 623  5
     }
 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  920
         int gmtOff = getGMTOffset();
 634  
         Calendar retVal;
 635  920
         if (gmtOff != GMT_OFFSET_NOT_SET_VALUE && !omitOffsetFg) {
 636  860
             int hrOffset = gmtOff / 100;
 637  860
             int minOffset = Math.abs(gmtOff % 100);
 638  860
             String timeZone = String.format("GMT%+d:%02d", hrOffset, minOffset);
 639  860
             retVal = new GregorianCalendar(TimeZone.getTimeZone(timeZone));
 640  860
         } else {
 641  60
             retVal = Calendar.getInstance();
 642  
         }
 643  
 
 644  920
         retVal.set(Calendar.HOUR_OF_DAY, getHour());
 645  920
         retVal.set(Calendar.MINUTE, getMinute());
 646  920
         retVal.set(Calendar.SECOND, getSecond());
 647  920
         float fractSecond = getFractSecond();
 648  920
         retVal.set(Calendar.MILLISECOND, (int) Math.round(fractSecond * 1000.0));
 649  
 
 650  920
         return retVal;
 651  
     }
 652  
 
 653  
     
 654  
     /**
 655  
      * <p>Return the value as a date object</p>
 656  
      * 
 657  
      * <b>Note that only the time component of the return value is set to
 658  
      * the value from this object. Returned value will have today's date</b> 
 659  
      * Note: Date is timezone-agnostic, representing always GMT time
 660  
      * @since 1.1 
 661  
      */
 662  
     public Date getValueAsDate() {
 663  10
         return getValueAsCalendar().getTime();
 664  
     }    
 665  
     
 666  
     /**
 667  
      * Returns the hour as an integer.
 668  
      */
 669  
     public int getHour() {
 670  1470
         return hour;
 671  
     } //end method
 672  
 
 673  
     /**
 674  
      * Returns the minute as an integer.
 675  
      */
 676  
     public int getMinute() {
 677  1470
         return minute;
 678  
     } //end method
 679  
 
 680  
     /**
 681  
      * Returns the second as an integer.
 682  
      */
 683  
     public int getSecond() {
 684  1470
         return second;
 685  
     } //end method
 686  
 
 687  
     /**
 688  
      * Returns the fractional second value as a float.
 689  
      */
 690  
     public float getFractSecond() {
 691  1470
         return fractionOfSec;
 692  
     } //end method
 693  
 
 694  
     /**
 695  
      * Returns the GMT offset value as an integer, {@link #GMT_OFFSET_NOT_SET_VALUE} if not set.  
 696  
      */
 697  
     public int getGMTOffset() {
 698  1690
         return offSet;
 699  
     } //end method
 700  
     
 701  
     /**
 702  
      * Returns a string value representing the input Gregorian Calendar object in
 703  
      * an Hl7 Time Format.
 704  
      */
 705  
     public static String toHl7TMFormat(GregorianCalendar cal) throws DataTypeException {
 706  25
         String val = "";
 707  
         try {
 708  
             //set the input cal object so that it can report errors
 709  
             //on it's value
 710  25
             cal.setLenient(false);
 711  25
             int calHour = cal.get(GregorianCalendar.HOUR_OF_DAY);
 712  25
             int calMin = cal.get(GregorianCalendar.MINUTE);
 713  25
             int calSec = cal.get(GregorianCalendar.SECOND);
 714  25
             int calMilli = cal.get(GregorianCalendar.MILLISECOND);
 715  
             //the inputs seconds and milli seconds should be combined into a float type
 716  25
             float fractSec = calMilli / 1000F;
 717  25
             float calSecFloat = calSec + fractSec;
 718  25
             int calOffset = cal.get(GregorianCalendar.ZONE_OFFSET) + cal.get(GregorianCalendar.DST_OFFSET); 
 719  
             //Note the input's Offset value is in milliseconds, we must convert it to
 720  
             //a 4 digit integer in the HL7 Offset format.
 721  
             int offSetSignInt;
 722  25
             if (calOffset < 0) {
 723  15
                 offSetSignInt = -1;
 724  
             }
 725  
             else {
 726  10
                 offSetSignInt = 1;
 727  
             }
 728  
             //get the absolute value of the gmtOffSet
 729  25
             int absGmtOffSet = Math.abs(calOffset);
 730  25
             int gmtOffSetHours = absGmtOffSet / (3600 * 1000);
 731  25
             int gmtOffSetMin = (absGmtOffSet / 60000) % (60);
 732  
             //reset calOffset
 733  25
             calOffset = ((gmtOffSetHours * 100) + gmtOffSetMin) * offSetSignInt;
 734  
             //Create an object of the TS class and populate it with the above values
 735  
             //then return the HL7 string value from the object
 736  25
             CommonTM tm = new CommonTM();
 737  25
             tm.setHourMinSecondPrecision(calHour, calMin, calSecFloat);
 738  25
             tm.setOffset(calOffset);
 739  25
             val = tm.getValue();
 740  
         } // end try
 741  
 
 742  0
         catch (DataTypeException e) {
 743  0
             throw e;
 744  
         } //end catch
 745  
 
 746  0
         catch (Exception e) {
 747  0
             throw new DataTypeException(e);
 748  25
         } //end catch
 749  25
         return val;
 750  
     } //end method
 751  
 
 752  
 } //end class