001    /**
002     * The contents of this file are subject to the Mozilla Public License Version 1.1
003     * (the "License"); you may not use this file except in compliance with the License.
004     * You may obtain a copy of the License at http://www.mozilla.org/MPL/
005     * Software distributed under the License is distributed on an "AS IS" basis,
006     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
007     * specific language governing rights and limitations under the License.
008     *
009     *
010     *
011     * The Initial Developer of the Original Code is University Health Network. Copyright (C)
012     * 2001.  All Rights Reserved.
013     *
014     * Contributor(s): ______________________________________.
015     *
016     * Alternatively, the contents of this file may be used under the terms of the
017     * GNU General Public License (the "GPL"), in which case the provisions of the GPL are
018     * applicable instead of those above.  If you wish to allow use of your version of this
019     * file only under the terms of the GPL and not to allow others to use your version
020     * of this file under the MPL, indicate your decision by deleting  the provisions above
021     * and replace  them with the notice and other provisions required by the GPL License.
022     * If you do not delete the provisions above, a recipient may use your version of
023     * this file under either the MPL or the GPL.
024     *
025     */
026    
027    package ca.uhn.hl7v2.model.primitive;
028    
029    import java.util.Calendar;
030    import java.util.Date;
031    import java.util.GregorianCalendar;
032    import java.io.Serializable;
033    
034    import ca.uhn.hl7v2.model.DataTypeException;
035    import ca.uhn.hl7v2.model.DataTypeUtil;
036    
037    /**
038     * <p>
039     * This class contains functionality used by the TS class
040     * in the version 2.3.0, 2.3.1, and 2.4 packages
041     * </p>
042     * 
043     * <p>
044     * Note: The class description below has been excerpted from the Hl7 2.4 documentation. Sectional
045     * references made below also refer to the same documentation.
046     * </p>
047     *
048     * <p>
049     * Format: YYYY[MM[DD[HHMM[SS[.S[S[S[S]]]]]]]][+/-ZZZZ]^<degree of precision>
050     * </p>
051     * 
052     * <p>
053     * Contains the exact time of an event, including the date and time. The date portion of a time stamp follows the rules of a
054     * date field and the time portion follows the rules of a time field. The time zone (+/-ZZZZ) is represented as +/-HHMM
055     * offset from UTC (formerly Greenwich Mean Time (GMT)), where +0000 or -0000 both represent UTC (without offset).
056     * The specific data representations used in the HL7 encoding rules are compatible with ISO 8824-1987(E).
057     * In prior versions of HL7, an optional second component indicates the degree of precision of the time stamp (Y = year, L
058     * = month, D = day, H = hour, M = minute, S = second). This optional second component is retained only for purposes of
059     * backward compatibility.
060     * </p>
061     * 
062     * <p>
063     * By site-specific agreement, YYYYMMDD[HHMM[SS[.S[S[S[S]]]]]][+/-ZZZZ]^<degree of precision> may be used
064     * where backward compatibility must be maintained.
065     * In the current and future versions of HL7, the precision is indicated by limiting the number of digits used, unless the
066     * optional second component is present. Thus, YYYY is used to specify a precision of "year," YYYYMM specifies a
067     * precision of "month," YYYYMMDD specifies a precision of "day," YYYYMMDDHH is used to specify a precision of
068     * "hour," YYYYMMDDHHMM is used to specify a precision of "minute," YYYYMMDDHHMMSS is used to specify a
069     * precision of seconds, and YYYYMMDDHHMMSS.SSSS is used to specify a precision of ten thousandths of a second.
070     * In each of these cases, the time zone is an optional component. Note that if the time zone is not included, the timezone
071     * defaults to that of the local time zone of the sender. Also note that a TS valued field with the HHMM part set to "0000"
072     * represents midnight of the night extending from the previous day to the day given by the YYYYMMDD part (see example
073     * below). Maximum length of the time stamp is 26. 
074     * </p>
075     * <p>
076     * Examples: <br/>
077     * |19760704010159-0500|<br/>
078     * 1:01:59 on July 4, 1976 in the Eastern Standard Time zone (USA).<br/>
079     * |19760704010159-0400|<br/>
080     * 1:01:59 on July 4, 1976 in the Eastern Daylight Saving Time zone (USA).<br/>
081     * |198807050000|<br/>
082     * Midnight of the night extending from July 4 to July 5, 1988 in the local time zone of the sender.<br/>
083     * |19880705|<br/>
084     * Same as prior example, but precision extends only to the day. Could be used for a birthdate, if the time of birth is
085     * unknown.<br/>
086     * |19981004010159+0100|<br/>
087     * 1:01:59 on October 4, 1998 in Amsterdam, NL. (Time zone=+0100).<br/>
088     * </p>
089     * <p>
090     * The HL7 Standard strongly recommends that all systems routinely send the time zone offset but does not require it. All
091     * HL7 systems are required to accept the time zone offset, but its implementation is application specific. For many
092     * applications the time of interest is the local time of the sender. For example, an application in the Eastern Standard Time
093     * zone receiving notification of an admission that takes place at 11:00 PM in San Francisco on December 11 would prefer
094     * to treat the admission as having occurred on December 11 rather than advancing the date to December 12.
095     * </p>
096     * <p>
097     * Note: The time zone [+/-ZZZZ], when used, is restricted to legally-defined time zones and is represented in HHMM
098     * format.
099     * </p>
100     * <p>
101     * One exception to this rule would be a clinical system that processed patient data collected in a clinic and a nearby hospital
102     * that happens to be in a different time zone. Such applications may choose to convert the data to a common
103     * representation. Similar concerns apply to the transitions to and from daylight saving time. HL7 supports such requirements
104     * by requiring that the time zone information be present when the information is sent. It does not, however, specify which of
105     * the treatments discussed here will be applied by the receiving system.
106     * </p>
107     * @author Neal Acharya
108     */
109    
110    @SuppressWarnings("serial")
111    public class CommonTS implements Serializable {
112    
113        private CommonDT dt;
114        private CommonTM tm;
115    
116        /** Creates new ValidTS
117         * zero argument constructor.
118         * Creates an uninitailized TS datatype
119         */
120        public CommonTS() {
121        } //zero arg constructor
122    
123        /**
124         * Constructs a TS object with the given value.
125         * The stored value will be in the following
126         * format YYYY[MM[DD[HHMM[SS[.S[S[S[S]]]]]]]][+/-ZZZZ]
127         */
128        public CommonTS(String val) throws DataTypeException {
129            this.setValue(val);
130        } //end constructor
131    
132        /**
133         * Returns the day as an integer.
134         */
135        public int getDay() {
136            int day = 0;
137            if (dt != null) {
138                day = dt.getDay();
139            } //end if
140            return day;
141        } //end method
142    
143        /**
144         * Returns the fractional second value as a float.
145         */
146        public float getFractSecond() {
147            float fractionOfSec = 0;
148            if (tm != null) {
149                fractionOfSec = tm.getFractSecond();
150            } //end if
151            return fractionOfSec;
152        } //end method
153    
154        /**
155         * Returns the GMT offset value as an integer.
156         */
157        public int getGMTOffset() {
158            int offSet = 0;
159            if (tm != null) {
160                    offSet = tm.getGMTOffset();
161            } //end if
162            return offSet;
163        } //end method
164    
165        /**
166         * Returns the hour as an integer.
167         */
168        public int getHour() {
169            int hour = 0;
170            if (tm != null) {
171                hour = tm.getHour();
172            } //end if
173            return hour;
174        } //end method
175    
176        /**
177         * Returns the minute as an integer.
178         */
179        public int getMinute() {
180            int minute = 0;
181            if (tm != null) {
182                minute = tm.getMinute();
183            } //end if
184            return minute;
185        } //end method
186    
187        /**
188         * Returns the month as an integer.
189         */
190        public int getMonth() {
191            int month = 0;
192            if (dt != null) {
193                month = dt.getMonth();
194            } //end if
195            return month;
196        } //end method
197    
198        /**
199         * Returns the second as an integer.
200         */
201        public int getSecond() {
202            int seconds = 0;
203            if (tm != null) {
204                seconds = tm.getSecond();
205            } //end if
206            return seconds;
207        } //end method
208    
209        /**
210         * Returns the HL7 TS string value.
211         */
212        public String getValue() {
213            String value = null;
214            if (dt != null) {
215                value = dt.getValue();
216            } //end if
217            if (tm != null && value != null && !value.equals("")) {
218                if (tm.getValue() != null && !tm.getValue().equals("")) {
219                    //here we know we have a delete value or separate date and the time values supplied
220                    if (tm.getValue().equals("\"\"") && dt.getValue().equals("\"\"")) {
221                        //set value to the delete value ("")
222                        value = "\"\"";
223                    }
224                    else{
225                        //set value to date concatonated with time value
226                        value = value + tm.getValue();
227                    }                
228                } //end if
229                if (tm.getValue() == null || tm.getValue().equals("")) {
230                    //here we know we both have the date and just the time offset value
231                    //change the offset value from an integer to a signed string
232                    int offset = tm.getGMTOffset();
233                    String offsetStr = "";
234                    if (offset != CommonTM.GMT_OFFSET_NOT_SET_VALUE) {
235                        offsetStr = DataTypeUtil.preAppendZeroes(Math.abs(offset), 4);
236                        if (tm.getGMTOffset() >= 0) {
237                            offsetStr = "+" + offsetStr;
238                        } //end if
239                        else {
240                            offsetStr = "-" + offsetStr;
241                        } //end else
242                    }
243                    value = value + offsetStr;
244                } //end if
245            } //end if
246            return value;
247        } //end method
248        
249        /**
250         * Return the value as a calendar object. If the value is null (e.g. no value has
251         * been set), returns null
252         * 
253         * @since 1.1 
254         */
255        public Calendar getValueAsCalendar() {
256            if (getValue() == null) {
257                    return null;
258            }
259            
260            Calendar retVal = tm.getValueAsCalendar();
261    
262            retVal.set(Calendar.YEAR, getYear());
263            retVal.set(Calendar.MONTH, getMonth() - 1);
264            retVal.set(Calendar.DATE, getDay());
265            
266            return retVal;
267        }
268    
269        /**
270         * Return the value as a date objectIf the value is null (e.g. no value has
271         * been set), returns null
272         * 
273         * @since 1.1 
274         */
275        public Date getValueAsDate() {
276            if (getValue() == null) {
277                    return null;
278            }
279    
280            return getValueAsCalendar().getTime();
281        }
282        
283        /**
284         * Returns the year as an integer.
285         */
286        public int getYear() {
287            int year = 0;
288            if (dt != null) {
289                year = dt.getYear();
290            } //end if
291            return year;
292        } //end method
293    
294        
295        /**
296         * This method takes in integer values for the year, month, day, hour
297         * and minute and performs validations, it then sets the value in the object
298         * formatted as an HL7 Time Stamp value with year&month&day&hour&minute precision (YYYYMMDDHHMM).
299         */
300        public void setDateMinutePrecision(int yr, int mnth, int dy, int hr, int min) throws DataTypeException {
301            try {
302                //set the value of the date object to the input date value
303                this.setDatePrecision(yr, mnth, dy);
304                //create new time object is there isn't one
305                if (tm == null) {
306                    tm = new CommonTM();
307                }
308                //set the value of the time object to the minute precision with the input values
309                tm.setHourMinutePrecision(hr, min);
310            } //end try
311    
312            catch (DataTypeException e) {
313                throw e;
314            } //end catch
315    
316            catch (Exception e) {
317                throw new DataTypeException(e);
318            } //end catch
319        } //end method
320        
321        
322        /**
323         * This method takes in integer values for the year and month and day
324         * and performs validations, it then sets the value in the object
325         * formatted as an HL7 Time Stamp value with year&month&day precision (YYYYMMDD).
326         *
327         */
328        public void setDatePrecision(int yr, int mnth, int dy) throws DataTypeException {
329            try {
330                //create date object if there isn't one
331                if (dt == null) {
332                    dt = new CommonDT();
333                }
334                //set the value of the date object to the input date value
335                dt.setYearMonthDayPrecision(yr, mnth, dy);
336                //clear the time value object
337                tm = null;
338            } //end try
339    
340            catch (DataTypeException e) {
341                throw e;
342            } //end catch
343    
344            catch (Exception e) {
345                throw new DataTypeException(e);
346            } //end catch
347        } //end method
348    
349        /**
350         * This method takes in integer values for the year, month, day, hour, minute, seconds,
351         * and fractional seconds (going to the tenthousandths precision).
352         * The method performs validations and then sets the value in the object formatted as an
353         * HL7 time value with a precision that starts from the year and goes down to the tenthousandths
354         * of a second (YYYYMMDDHHMMSS.SSSS).
355         * The Gmt Offset will not be effected.
356         * Note: all of the precisions from tenths down to
357         * tenthousandths of a second are optional. If the precision goes below tenthousandths
358         * of a second then the second value will be rounded to the nearest tenthousandths of a second.
359         */
360        public void setDateSecondPrecision(int yr, int mnth, int dy, int hr, int min, float sec) throws DataTypeException {
361            try {
362                //set the value of the date object to the input date value
363                this.setDatePrecision(yr, mnth, dy);
364                //create new time object is there isn't one
365                if (tm == null) {
366                    tm = new CommonTM();
367                }
368                //set the value of the time object to the second precision with the input values
369                tm.setHourMinSecondPrecision(hr, min, sec);
370            } //end try
371    
372            catch (DataTypeException e) {
373                throw e;
374            } //end catch
375    
376            catch (Exception e) {
377                throw new DataTypeException(e);
378            } //end catch
379        } //end method
380    
381        /**
382         * This method takes in the four digit (signed) GMT offset and sets the offset
383         * field
384         */
385        public void setOffset(int signedOffset) throws DataTypeException {
386            try {
387                //create new time object is there isn't one
388                if (tm == null) {
389                    tm = new CommonTM();
390                }
391                //set the offset value of the time object to the input value
392                tm.setOffset(signedOffset);
393            }
394    
395            catch (DataTypeException e) {
396                throw e;
397            } //end catch
398    
399            catch (Exception e) {
400                throw new DataTypeException(e);
401            } //end catch
402        } //end method
403    
404        /**
405         * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
406         * 
407         * Note: Sets fields using precision up to the millisecond, including timezone offset
408         * 
409         * @param theCalendar The calendar object from which to retrieve values 
410         * @since 1.1 
411         */
412        public void setValue(Calendar theCalendar) throws DataTypeException {
413                    if (theCalendar == null) {
414                            setValue((String)null);
415                            return;
416                    }
417    
418                    int yr = theCalendar.get(Calendar.YEAR);
419            int mnth = theCalendar.get(Calendar.MONTH) + 1;
420            int dy = theCalendar.get(Calendar.DATE);
421            int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
422            int min = theCalendar.get(Calendar.MINUTE);
423            float sec = theCalendar.get(Calendar.SECOND) + (theCalendar.get(Calendar.MILLISECOND) / 1000.0F);
424            setDateSecondPrecision(yr, mnth, dy, hr, min, sec);
425            
426            // 3410095: care for integer overflow and timezones not at the full hour, e.g. India
427            int hourOffset= theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);   
428            int minuteOffset = (theCalendar.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
429            int zoneOffset = hourOffset * 100 + minuteOffset;
430            setOffset(zoneOffset);
431        }
432    
433        /**
434         * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
435         * 
436         * Note: Sets fields using precision up to the millisecond, and sets the timezone offset to
437         * the current system offset
438         * 
439         * @param theDate The calendar object from which to retrieve values 
440         * @since 1.1 
441         */
442            public void setValue(Date theDate) throws DataTypeException {
443                    if (theDate == null) {
444                            setValue((String)null);
445                            return;
446                    }
447    
448                    GregorianCalendar cal = new GregorianCalendar();
449                    cal.setTime(theDate);
450                    setValue(cal);
451            }
452    
453        /**
454         * This method takes in a string HL7 Time Stamp value and performs validations.
455         * The stored value will be in the following
456         * format YYYY[MM[DD[HHMM[SS[.S[S[S[S]]]]]]]][+/-ZZZZ].
457         * Note: Trailing zeros supplied in the time value (HHMM[SS[.S[S[S[S]]]]]])
458         * and GMT offset ([+/-ZZZZ]) will be preserved.
459         * Note: If the GMT offset is not supplied then the local
460         * time zone (using standard time zone format which is not modified for daylight savings)
461         * will be stored as a default. Passing in <code>null</code> clears any existing value.
462         */
463        public void setValue(String val) throws DataTypeException {
464            if (val != null && !val.equals("") && !val.equals("\"\"")) {
465                try {
466                    //check the length of the input value, ensure that it is no less than
467                    //8 characters in length
468                    if (val.length() < 4) {
469                        String msg = "The length of the TS datatype value must be at least 4 characters in length.";
470                        DataTypeException e = new DataTypeException(msg);
471                        throw e;
472                    }
473    
474                    //check the length of the input value, ensure that it is not greater
475                    //than 24 characters in length
476                    if (val.length() > 24) {
477                        String msg = "The length of the TS datatype value must not be more than 24 characters in length.";
478                        DataTypeException e = new DataTypeException(msg);
479                        throw e;
480                    }
481    
482                    //at this point we know that we have a value that should conform to the DT
483                    //datatype and possibly a value that should conform to the TM datatype
484                    String dateVal = null;
485                    String timeVal = null;
486                    String timeValLessOffset = null;
487                    int sp = val.indexOf("+");
488                    int sm = val.indexOf("-");
489                    int indexOfSign = -1;
490                    boolean offsetExists = false;
491                    boolean timeValIsOffsetOnly = false;
492                    if ((sp != -1) || (sm != -1)) {
493                        offsetExists = true;
494                    }
495                    if (sp != -1)
496                        indexOfSign = sp;
497                    if (sm != -1)
498                        indexOfSign = sm;
499    
500                    if (offsetExists == false) {
501                        if (val.length() <= 8) {
502                            dateVal = val;
503                        }
504                        else {
505                            //here we know that a time value is present
506                            dateVal = val.substring(0, 8);
507                            timeVal = val.substring(8);
508                            timeValLessOffset = timeVal;
509                        }
510                    } //offset not exist
511    
512                    if (offsetExists == true) {
513                        if (indexOfSign > 8) {
514                            dateVal = val.substring(0, 8);
515                            timeVal = val.substring(8);
516                            timeValLessOffset = val.substring(8, indexOfSign);
517                        }
518                        else {
519                            //we know that the time val is simply the offset
520                            dateVal = val.substring(0, indexOfSign);
521                            timeVal = val.substring(indexOfSign);
522                            timeValIsOffsetOnly = true;
523                        }
524                    } //offset exists
525    
526                    //create date object
527                    dt = new CommonDT();
528                    //set the value of the date object to the input date value
529                    dt.setValue(dateVal);
530                    //if the offset does not exist and a timvalue does not exist then
531                    //we must provide a default offset = to the local time zone
532                    if (timeVal == null && offsetExists == false) {
533    //                    int defaultOffset = DataTypeUtil.getLocalGMTOffset();
534                        tm = new CommonTM();
535                        //tm.setOffset(defaultOffset);
536                        tm.setValue("");
537                    } //end if
538    
539                    //if we have a time value then make a new time object and set it to the
540                    //input time value (as long as the time val has time + offset or just time only)
541                    if (timeVal != null && timeValIsOffsetOnly == false) {
542                        // must make sure that the time component contains both hours 
543                        // at the very least -- must be at least 2 chars in length.
544                            // Note: this changed as of v2.5, before hours AND minutes were required.
545                        if (timeValLessOffset.length() < 2) {
546                            String msg =
547                                "The length of the time component for the TM datatype"
548                                    + " value does not conform to the allowable format"
549                                    + " YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ].";
550                            DataTypeException e = new DataTypeException(msg);
551                            throw e;
552                        } //end if
553                        tm = new CommonTM();
554                        tm.setValue(timeVal);
555                    } //end if
556    
557                    //if we have a time value and it only has the offset then make a new
558                    //time object and set the offset value to the input value
559                    if (timeVal != null && timeValIsOffsetOnly == true) {
560                        //we know that the time value is just the offset so we
561                        //must check to see if it is the right length before setting the
562                        //offset field in the tm object
563                        if (timeVal.length() != 5) {
564                            String msg =
565                                "The length of the GMT offset for the TM datatype value does"
566                                    + " not conform to the allowable format [+/-ZZZZ]";
567                            DataTypeException e = new DataTypeException(msg);
568                            throw e;
569                        } //end if 
570                        tm = new CommonTM();
571                        //first extract the + sign from the offset value string if it exists
572                        if (timeVal.indexOf("+") == 0) {
573                            timeVal = timeVal.substring(1);
574                        } //end if
575                        int signedOffset = Integer.parseInt(timeVal);
576                        tm.setOffset(signedOffset);
577                    } //end if
578                } //end try
579    
580                catch (DataTypeException e) {
581                    throw e;
582                } //end catch
583    
584                catch (Exception e) {
585                    throw new DataTypeException(e);
586                } //end catch
587            } //end if
588            else {
589                //set the private value field to null or empty space.
590                if (val == null) {
591                    dt = null;
592                    tm = null;
593                } //end if
594                if (val != null && val.equals("")) {
595                    dt = new CommonDT();
596                    dt.setValue("");
597                    tm = new CommonTM();
598                    tm.setValue("");
599                } //end if
600                if (val != null && val.equals("\"\"")) {
601                    dt = new CommonDT();
602                    dt.setValue("\"\"");
603                    tm = new CommonTM();
604                    tm.setValue("\"\"");
605                } //end if
606            } //end else    
607    
608        } // end method
609    
610        /**
611         * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
612         * 
613         * Note: Sets fields using precision up to the minute
614         * 
615         * @param theCalendar The calendar object from which to retrieve values 
616         * @since 1.1 
617         */
618        public void setValueToMinute(Calendar theCalendar) throws DataTypeException {
619                    if (theCalendar == null) {
620                            setValue((String)null);
621                            return;
622                    }
623    
624            int yr = theCalendar.get(Calendar.YEAR);
625            int mnth = theCalendar.get(Calendar.MONTH) + 1;
626            int dy = theCalendar.get(Calendar.DATE);
627            int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
628            int min = theCalendar.get(Calendar.MINUTE);
629            setDateMinutePrecision(yr, mnth, dy, hr, min);
630            
631        }
632    
633        /**
634         * Convenience setter which sets the value using a {@link Date} object. Passing in <code>null</code> clears any existing value.
635         * 
636         * Note: Sets fields using precision up to the minute
637         * 
638         * @param theCalendar The calendar object from which to retrieve values 
639         * @since 1.1 
640         */
641        public void setValueToMinute(Date theDate) throws DataTypeException {
642                    if (theDate == null) {
643                            setValue((String)null);
644                            return;
645                    }
646    
647                    Calendar calendar = Calendar.getInstance();
648            calendar.setTime(theDate);
649            setValueToMinute(calendar);
650        }
651    
652        /**
653         * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
654         * 
655         * Note: Sets fields using precision up to the second
656         * 
657         * @param theCalendar The calendar object from which to retrieve values 
658         * @since 1.1 
659         */
660        public void setValueToSecond(Calendar theCalendar) throws DataTypeException {
661                    if (theCalendar == null) {
662                            setValue((String)null);
663                            return;
664                    }
665    
666            int yr = theCalendar.get(Calendar.YEAR);
667            int mnth = theCalendar.get(Calendar.MONTH) + 1;
668            int dy = theCalendar.get(Calendar.DATE);
669            int hr = theCalendar.get(Calendar.HOUR_OF_DAY);
670            int min = theCalendar.get(Calendar.MINUTE);
671            int sec = theCalendar.get(Calendar.SECOND);
672            setDateSecondPrecision(yr, mnth, dy, hr, min, sec);
673        }
674    
675        /**
676         * Convenience setter which sets the value using a {@link Date} object. Passing in <code>null</code> clears any existing value.
677         * 
678         * Note: Sets fields using precision up to the second
679         * 
680         * @param theCalendar The calendar object from which to retrieve values 
681         * @since 1.1 
682         */
683        public void setValueToSecond(Date theDate) throws DataTypeException {
684                    if (theDate == null) {
685                            setValue((String)null);
686                            return;
687                    }
688    
689                    Calendar calendar = Calendar.getInstance();
690            calendar.setTime(theDate);
691            setValueToSecond(calendar);
692        }
693    
694        /**
695         * Returns a string value representing the input Gregorian Calendar object in
696         * an Hl7 TimeStamp Format.
697         */
698        public static String toHl7TSFormat(GregorianCalendar cal) throws DataTypeException {
699            String val = "";
700            try {
701                //set the input cal object so that it can report errors
702                //on it's value
703                cal.setLenient(false);
704                int calYear = cal.get(GregorianCalendar.YEAR);
705                int calMonth = cal.get(GregorianCalendar.MONTH) + 1;
706                int calDay = cal.get(GregorianCalendar.DAY_OF_MONTH);
707                int calHour = cal.get(GregorianCalendar.HOUR_OF_DAY);
708                int calMin = cal.get(GregorianCalendar.MINUTE);
709                int calSec = cal.get(GregorianCalendar.SECOND);
710                int calMilli = cal.get(GregorianCalendar.MILLISECOND);
711                //the inputs seconds and milli seconds should be combined into a float type
712                float fractSec = calMilli / 1000F;
713                float calSecFloat = calSec + fractSec;
714                int calOffset = cal.get(GregorianCalendar.ZONE_OFFSET);
715                //Note the input's Offset value is in milliseconds, we must convert it to
716                //a 4 digit integer in the HL7 Offset format.
717                int offSetSignInt;
718                if (calOffset < 0) {
719                    offSetSignInt = -1;
720                }
721                else {
722                    offSetSignInt = 1;
723                }
724                //get the absolute value of the gmtOffSet
725                int absGmtOffSet = Math.abs(calOffset);
726                int gmtOffSetHours = absGmtOffSet / (3600 * 1000);
727                int gmtOffSetMin = (absGmtOffSet / 60000) % (60);
728                //reset calOffset
729                calOffset = ((gmtOffSetHours * 100) + gmtOffSetMin) * offSetSignInt;
730                //Create an object of the TS class and populate it with the above values
731                //then return the HL7 string value from the object
732                CommonTS ts = new CommonTS();
733                ts.setDateSecondPrecision(calYear, calMonth, calDay, calHour, calMin, calSecFloat);
734                ts.setOffset(calOffset);
735                val = ts.getValue();
736            } // end try
737    
738            catch (DataTypeException e) {
739                throw e;
740            } //end catch
741    
742            catch (Exception e) {
743                throw new DataTypeException(e);
744            } //end catch
745            return val;
746        } //end method
747    
748        
749        public static void main(String[] args) throws DataTypeException {
750            
751            CommonTS ts = new CommonTS();
752            ts.setValue("1984");
753            
754            System.out.println(ts.getValue());
755            
756        }
757        
758        
759    } //end class