001    /**
002     * The contents of this file are subject to the Mozilla Public License Version 1.1
003     * (the "License"); you may not use this file except in compliance with the License.
004     * You may obtain a copy of the License at http://www.mozilla.org/MPL/
005     * Software distributed under the License is distributed on an "AS IS" basis,
006     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
007     * specific language governing rights and limitations under the License.
008     *
009     * The Original Code is "CommonDT.java".  Description:
010     * "Note: The class description below has been excerpted from the Hl7 2.4 documentation"
011     *
012     * The Initial Developer of the Original Code is University Health Network. Copyright (C)
013     * 2001.  All Rights Reserved.
014     *
015     * Contributor(s): ______________________________________.
016     *
017     * Alternatively, the contents of this file may be used under the terms of the
018     * GNU General Public License (the  �GPL�), in which case the provisions of the GPL are
019     * applicable instead of those above.  If you wish to allow use of your version of this
020     * file only under the terms of the GPL and not to allow others to use your version
021     * of this file under the MPL, indicate your decision by deleting  the provisions above
022     * and replace  them with the notice and other provisions required by the GPL License.
023     * If you do not delete the provisions above, a recipient may use your version of
024     * this file under either the MPL or the GPL.
025     *
026     */
027    
028    package ca.uhn.hl7v2.model.primitive;
029    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     * This class contains functionality used by the DT class
039     * in the version 2.3.0, 2.3.1, and 2.4 packages
040     *
041     * Note: The class description below has been excerpted from the Hl7 2.4 documentation. Sectional
042     * references made below also refer to the same documentation.
043     *
044     * Format: YYYY[MM[DD]]
045     * In prior versions of HL7, this data type was always specified to be in the format YYYYMMDD. In the current and future
046     * versions, the precision of a date may be expressed by limiting the number of digits used with the format specification
047     * YYYY[MM[DD]]. Thus, YYYY is used to specify a precision of "year," YYYYMM specifies a precision of "month,"
048     * and YYYYMMDD specifies a precision of "day."
049     * By site-specific agreement, YYYYMMDD may be used where backward compatibility must be maintained.
050     * Examples:   |19880704|  |199503|
051     * @author Neal Acharya
052     */
053    
054    @SuppressWarnings("serial")
055    public class CommonDT implements Serializable {
056    
057        private String value;
058        private int year;
059        private int month;
060        private int day;
061    
062        /**
063         * Constructs a DT datatype with fields initialzed to zero and value initialized
064         * to null.
065         */
066        public CommonDT() {
067            //initialize all DT fields
068            value = null;
069            year = 0;
070            month = 0;
071            day = 0;
072        } //end constructor
073    
074        /**
075         * Constructs a DT object with the given value.
076         * The stored value will be in the following
077         * format YYYY[MM[DD]].
078         */
079        public CommonDT(String val) throws DataTypeException {
080            this.setValue(val);
081        } //end constructor
082    
083        /**
084         * Convenience setter which sets the value using a {@link Calendar} object. Passing in <code>null</code> clears any existing value.
085         * 
086         * Note: Sets fields using maximum possible precision
087         * 
088         * @param theCalendar The calendar object from which to retrieve values
089         * @since 1.1 
090         */
091        public void setValue(Calendar theCalendar) throws DataTypeException {
092                    if (theCalendar == null) {
093                            setValue((String)null);
094                            return;
095                    }
096    
097            int yr = theCalendar.get(Calendar.YEAR);
098            int mnth = theCalendar.get(Calendar.MONTH) + 1;
099            int dy = theCalendar.get(Calendar.DATE);
100            setYearMonthDayPrecision(yr, mnth, dy);
101        }
102    
103        /**
104         * Convenience setter which sets the value using a {@link Date} object. Passing in <code>null</code> clears any existing value.
105         * 
106         * Note: Sets fields using maximum possible precision
107         * 
108         * @param theCalendar The calendar object from which to retrieve values 
109         * @since 1.1 
110         */
111        public void setValue(Date theDate) throws DataTypeException {
112                    if (theDate == null) {
113                            setValue((String)null);
114                            return;
115                    }
116    
117            Calendar calendar = Calendar.getInstance();
118            calendar.setTime(theDate);
119            setValue(calendar);
120        }
121        
122        
123        /**
124         * Return the value as a calendar object
125         * @since 1.1 
126         */
127        public Calendar getValueAsCalendar() {
128            Calendar retVal = Calendar.getInstance();
129            retVal.set(Calendar.DATE, getDay());
130            retVal.set(Calendar.MONTH, getMonth() - 1);
131            retVal.set(Calendar.YEAR, getYear());
132    
133            // Truncate
134            retVal.set(Calendar.HOUR_OF_DAY, 0);
135            retVal.set(Calendar.MINUTE, 0);
136            retVal.set(Calendar.SECOND, 0);
137            retVal.set(Calendar.MILLISECOND, 0);
138            
139            return retVal;
140        }
141    
142        
143        /**
144         * Return the value as a date object
145         * @since 1.1 
146         */
147        public Date getValueAsDate() {
148            return getValueAsCalendar().getTime();
149        }
150        
151        
152        /**
153         * This method takes in a string HL7 date value and performs validations
154         * then sets the value field. The stored value will be in the following
155         * format YYYY[MM[DD]]. Passing in <code>null</code> clears any existing value.
156         *
157         */
158        public void setValue(String val) throws DataTypeException {
159    
160            if (val != null && !val.equals("") && !val.equals("\"\"")){
161                try {
162                    GregorianCalendar cal = new GregorianCalendar();
163                    cal.clear();
164                    cal.setLenient(false);
165    
166                    //check the length, must be either four, six, or eight digits
167                    if ((val.length() != 4) && (val.length() != 6) && (val.length() != 8)) {
168                        String msg =
169                            "The length of the DT datatype value does not conform to an allowable"
170                                + " format. Format should conform to YYYY[MM[DD]]";
171                        DataTypeException e = new DataTypeException(msg);
172                        throw e;
173                    }
174    
175                    if (val.length() >= 4) {
176                        //extract the year from the input value
177                        int yrInt = Integer.parseInt(val.substring(0, 4));
178                        //check to see if the year is valid by creating a Gregorian calendar object with
179                        //this value.  If an error occurs then processing will stop in this try block
180                        cal.set(yrInt, 0, 1);
181                        cal.getTime(); //for error detection
182                        year = yrInt;
183                    }
184    
185                    if (val.length() >= 6) {
186                        //extract the month from the input value
187                        int mnthInt = Integer.parseInt(val.substring(4, 6));
188                        //check to see if the month is valid by creating a Gregorian calendar object with
189                        //this value.  If an error occurs then processing will stop in this try block
190                        cal.set(year, mnthInt - 1, 1);
191                        cal.getTime(); //for error detection
192                        month = mnthInt;
193    
194                    }
195    
196                    if (val.length() == 8) {
197                        //extract the day from the input value
198                        int dayInt = Integer.parseInt(val.substring(6, 8));
199                        //check to see if the day is valid by creating a Gregorian calendar object with
200                        //the year/month/day combination.  If an error occurs then processing will stop
201                        // in this try block
202                        cal.set(year, month - 1, dayInt);
203                        cal.getTime(); //for error detection
204                        day = dayInt;
205                    }
206                    //validations are complete now store the input value into the private value field
207                    value = val;
208                } //end try
209    
210                catch (DataTypeException e) {
211                    throw e;
212                } //end catch
213    
214                catch (Exception e) {
215                    throw new DataTypeException( e );
216                } //end catch
217            } //end if
218            else {
219                //set the private value field to null or empty space.
220                value = val;
221            } //end else       
222    
223        } //end method
224    
225        /**
226         * This method takes in an integer value for the year and performs validations,
227         * it then sets the value field formatted as an HL7 date.
228         * value with year precision (YYYY)
229         */
230        public void setYearPrecision(int yr) throws DataTypeException {
231            try {
232                GregorianCalendar cal = new GregorianCalendar();
233                cal.clear();
234                cal.setLenient(false);
235    
236                //ensure that the year field is four digits long
237                if (Integer.toString(yr).length() != 4) {
238                    String msg = "The input year value must be four digits long";
239                    DataTypeException e = new DataTypeException(msg);
240                    throw e;
241                }
242                //check is input year is valid
243                //GregorianCalendar cal = new GregorianCalendar(yr,0,1);
244                cal.set(yr, 0, 1);
245                cal.getTime(); //for error detection
246                year = yr;
247                month = 0;
248                day = 0;
249                value = Integer.toString(yr);
250            } //end try
251    
252            catch (DataTypeException e) {
253                throw e;
254            } //end catch
255    
256            catch (Exception e) {
257                throw new DataTypeException( e );
258            } //end catch
259    
260        } //end method
261    
262        /**
263         * This method takes in integer values for the year and month and performs validations,
264         * it then sets the value field formatted as an HL7 date
265         * value with year&month precision (YYYYMM).
266         * Note: The first month = 1 = January.
267         */
268        public void setYearMonthPrecision(int yr, int mnth) throws DataTypeException {
269            try {
270                GregorianCalendar cal = new GregorianCalendar();
271                cal.clear();
272                cal.setLenient(false);
273                //ensure that the year field is four digits long
274                if (Integer.toString(yr).length() != 4) {
275                    String msg = "The input year value must be four digits long";
276                    DataTypeException e = new DataTypeException(msg);
277                    throw e;
278                }
279                //validate the input month
280                //GregorianCalendar cal = new GregorianCalendar(yr,(mnth-1),1);
281                cal.set(yr, (mnth - 1), 1);
282                cal.getTime(); //for error detection
283                year = yr;
284                month = mnth;
285                day = 0;
286                value = Integer.toString(yr) + DataTypeUtil.preAppendZeroes(mnth, 2);
287            }
288    
289            catch (DataTypeException e) {
290                throw e;
291            } //end catch
292    
293            catch (Exception e) {
294                throw new DataTypeException( e );
295            } //end catch
296        } //end method
297    
298        /**
299         * This method takes in integer values for the year and month and day
300         * and performs validations, it then sets the value in the object
301         * formatted as an HL7 date value with year&month&day precision (YYYYMMDD).
302         */
303        public void setYearMonthDayPrecision(int yr, int mnth, int dy) throws DataTypeException {
304            try {
305                GregorianCalendar cal = new GregorianCalendar();
306                cal.clear();
307                cal.setLenient(false);
308    
309                //ensure that the year field is four digits long
310                if (Integer.toString(yr).length() != 4) {
311                    String msg = "The input year value must be four digits long";
312                    DataTypeException e = new DataTypeException(msg);
313                    throw e;
314                }
315                //validate the input month/day combination
316                cal.set(yr, (mnth - 1), dy);
317                cal.getTime(); //for error detection
318                year = yr;
319                month = mnth;
320                day = dy;
321                value = Integer.toString(yr) + DataTypeUtil.preAppendZeroes(mnth, 2) + DataTypeUtil.preAppendZeroes(dy, 2);
322            }
323    
324            catch (DataTypeException e) {
325                throw e;
326            } //end catch
327    
328            catch (Exception e) {
329                throw new DataTypeException( e );
330            } //end catch
331    
332        } //end method
333    
334        /**
335         * Returns the HL7 DT string value.
336         */
337        public String getValue() {
338            return value;
339        } //end method
340    
341        /**
342         * Returns the year as an integer.
343         */
344        public int getYear() {
345            return year;
346        } //end method
347    
348        /**
349         * Returns the month as an integer.
350         */
351        public int getMonth() {
352            return month;
353        } //end method
354    
355        /**
356         * Returns the day as an integer.
357         */
358        public int getDay() {
359            return day;
360        } //end method
361    
362        
363        /**
364         * Returns a string value representing the input Gregorian Calendar object in
365         * an Hl7 Date Format.
366         */
367        public static String toHl7DTFormat(GregorianCalendar cal) throws DataTypeException {
368            String val = "";
369            try {
370                //set the input cal object so that it can report errors
371                //on it's value
372                cal.setLenient(false);
373                int calYear = cal.get(GregorianCalendar.YEAR);
374                int calMonth = cal.get(GregorianCalendar.MONTH) + 1;
375                int calDay = cal.get(GregorianCalendar.DAY_OF_MONTH);
376                CommonDT dt = new CommonDT();
377                dt.setYearMonthDayPrecision(calYear, calMonth, calDay);
378                val = dt.getValue();
379            } //end try
380    
381            catch (DataTypeException e) {
382                throw e;
383            } //end catch
384    
385            catch (Exception e) {
386                throw new DataTypeException( e );
387            } //end catch
388            return val;
389        } //end method
390    
391    } //end class