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                    throw new DataTypeException(msg);
172                }
173
174                if (val.length() >= 4) {
175                    //extract the year from the input value
176                    int yrInt = Integer.parseInt(val.substring(0, 4));
177                    //check to see if the year is valid by creating a Gregorian calendar object with
178                    //this value.  If an error occurs then processing will stop in this try block
179                    cal.set(yrInt, Calendar.JANUARY, 1);
180                    cal.getTime(); //for error detection
181                    year = yrInt;
182                }
183
184                if (val.length() >= 6) {
185                    //extract the month from the input value
186                    int mnthInt = Integer.parseInt(val.substring(4, 6));
187                    //check to see if the month is valid by creating a Gregorian calendar object with
188                    //this value.  If an error occurs then processing will stop in this try block
189                    cal.set(year, mnthInt - 1, 1);
190                    cal.getTime(); //for error detection
191                    month = mnthInt;
192
193                }
194
195                if (val.length() == 8) {
196                    //extract the day from the input value
197                    int dayInt = Integer.parseInt(val.substring(6, 8));
198                    //check to see if the day is valid by creating a Gregorian calendar object with
199                    //the year/month/day combination.  If an error occurs then processing will stop
200                    // in this try block
201                    cal.set(year, month - 1, dayInt);
202                    cal.getTime(); //for error detection
203                    day = dayInt;
204                }
205                //validations are complete now store the input value into the private value field
206                value = val;
207            } //end try
208
209            catch (DataTypeException e) {
210                throw e;
211            } //end catch
212
213            catch (Exception e) {
214                throw new DataTypeException( e );
215            } //end catch
216        } //end if
217        else {
218            //set the private value field to null or empty space.
219            value = val;
220        } //end else       
221
222    } //end method
223
224    /**
225     * This method takes in an integer value for the year and performs validations,
226     * it then sets the value field formatted as an HL7 date.
227     * value with year precision (YYYY)
228     */
229    public void setYearPrecision(int yr) throws DataTypeException {
230        try {
231            GregorianCalendar cal = new GregorianCalendar();
232            cal.clear();
233            cal.setLenient(false);
234
235            //ensure that the year field is four digits long
236            if (Integer.toString(yr).length() != 4) {
237                String msg = "The input year value must be four digits long";
238                throw new DataTypeException(msg);
239            }
240            //check is input year is valid
241            //GregorianCalendar cal = new GregorianCalendar(yr,0,1);
242            cal.set(yr, Calendar.JANUARY, 1);
243            cal.getTime(); //for error detection
244            year = yr;
245            month = 0;
246            day = 0;
247            value = Integer.toString(yr);
248        } //end try
249
250        catch (DataTypeException e) {
251            throw e;
252        } //end catch
253
254        catch (Exception e) {
255            throw new DataTypeException( e );
256        } //end catch
257
258    } //end method
259
260    /**
261     * This method takes in integer values for the year and month and performs validations,
262     * it then sets the value field formatted as an HL7 date
263     * value with year&month precision (YYYYMM).
264     * Note: The first month = 1 = January.
265     */
266    public void setYearMonthPrecision(int yr, int mnth) throws DataTypeException {
267        try {
268            GregorianCalendar cal = new GregorianCalendar();
269            cal.clear();
270            cal.setLenient(false);
271            //ensure that the year field is four digits long
272            if (Integer.toString(yr).length() != 4) {
273                String msg = "The input year value must be four digits long";
274                throw new DataTypeException(msg);
275            }
276            //validate the input month
277            //GregorianCalendar cal = new GregorianCalendar(yr,(mnth-1),1);
278            cal.set(yr, (mnth - 1), 1);
279            cal.getTime(); //for error detection
280            year = yr;
281            month = mnth;
282            day = 0;
283            value = yr + DataTypeUtil.preAppendZeroes(mnth, 2);
284        }
285
286        catch (DataTypeException e) {
287            throw e;
288        } //end catch
289
290        catch (Exception e) {
291            throw new DataTypeException( e );
292        } //end catch
293    } //end method
294
295    /**
296     * This method takes in integer values for the year and month and day
297     * and performs validations, it then sets the value in the object
298     * formatted as an HL7 date value with year&month&day precision (YYYYMMDD).
299     */
300    public void setYearMonthDayPrecision(int yr, int mnth, int dy) throws DataTypeException {
301        try {
302            GregorianCalendar cal = new GregorianCalendar();
303            cal.clear();
304            cal.setLenient(false);
305
306            //ensure that the year field is four digits long
307            if (Integer.toString(yr).length() != 4) {
308                String msg = "The input year value must be four digits long";
309                throw new DataTypeException(msg);
310            }
311            //validate the input month/day combination
312            cal.set(yr, (mnth - 1), dy);
313            cal.getTime(); //for error detection
314            year = yr;
315            month = mnth;
316            day = dy;
317            value = yr + DataTypeUtil.preAppendZeroes(mnth, 2) + DataTypeUtil.preAppendZeroes(dy, 2);
318        }
319
320        catch (DataTypeException e) {
321            throw e;
322        } //end catch
323
324        catch (Exception e) {
325            throw new DataTypeException( e );
326        } //end catch
327
328    } //end method
329
330    /**
331     * Returns the HL7 DT string value.
332     */
333    public String getValue() {
334        return value;
335    } //end method
336
337    /**
338     * Returns the year as an integer.
339     */
340    public int getYear() {
341        return year;
342    } //end method
343
344    /**
345     * Returns the month as an integer.
346     */
347    public int getMonth() {
348        return month;
349    } //end method
350
351    /**
352     * Returns the day as an integer.
353     */
354    public int getDay() {
355        return day;
356    } //end method
357
358    
359    /**
360     * Returns a string value representing the input Gregorian Calendar object in
361     * an Hl7 Date Format.
362     */
363    public static String toHl7DTFormat(GregorianCalendar cal) throws DataTypeException {
364        String val;
365        try {
366            //set the input cal object so that it can report errors
367            //on it's value
368            cal.setLenient(false);
369            int calYear = cal.get(GregorianCalendar.YEAR);
370            int calMonth = cal.get(GregorianCalendar.MONTH) + 1;
371            int calDay = cal.get(GregorianCalendar.DAY_OF_MONTH);
372            CommonDT dt = new CommonDT();
373            dt.setYearMonthDayPrecision(calYear, calMonth, calDay);
374            val = dt.getValue();
375        } //end try
376
377        catch (DataTypeException e) {
378            throw e;
379        } //end catch
380
381        catch (Exception e) {
382            throw new DataTypeException( e );
383        } //end catch
384        return val;
385    } //end method
386
387} //end class