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
028package ca.uhn.hl7v2.model.primitive;
029import java.util.Calendar;
030import java.util.Date;
031import java.util.GregorianCalendar;
032import java.io.Serializable;
033
034import ca.uhn.hl7v2.model.DataTypeException;
035import 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")
055public 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 theDate The date 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