001package org.hl7.fhir.r4.model;
002
003import java.util.Calendar;
004import java.util.Date;
005import java.util.TimeZone;
006import java.util.zip.DataFormatException;
007
008import org.apache.commons.lang3.time.DateUtils;
009
010/*
011  Copyright (c) 2011+, HL7, Inc.
012  All rights reserved.
013  
014  Redistribution and use in source and binary forms, with or without modification, 
015  are permitted provided that the following conditions are met:
016    
017   * Redistributions of source code must retain the above copyright notice, this 
018     list of conditions and the following disclaimer.
019   * Redistributions in binary form must reproduce the above copyright notice, 
020     this list of conditions and the following disclaimer in the documentation 
021     and/or other materials provided with the distribution.
022   * Neither the name of HL7 nor the names of its contributors may be used to 
023     endorse or promote products derived from this software without specific 
024     prior written permission.
025  
026  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
027  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
028  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
029  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
030  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
031  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
032  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
033  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
034  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
035  POSSIBILITY OF SUCH DAMAGE.
036  
037 */
038
039import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
040import ca.uhn.fhir.model.api.annotation.DatatypeDef;
041
042/**
043 * Represents a FHIR dateTime datatype. Valid precisions values for this type
044 * are:
045 * <ul>
046 * <li>{@link TemporalPrecisionEnum#YEAR}
047 * <li>{@link TemporalPrecisionEnum#MONTH}
048 * <li>{@link TemporalPrecisionEnum#DAY}
049 * <li>{@link TemporalPrecisionEnum#SECOND}
050 * <li>{@link TemporalPrecisionEnum#MILLI}
051 * </ul>
052 */
053@DatatypeDef(name = "dateTime")
054public class DateTimeType extends BaseDateTimeType {
055
056  private static final long serialVersionUID = 3L;
057
058  /**
059   * The default precision for this type
060   */
061  public static final TemporalPrecisionEnum DEFAULT_PRECISION = TemporalPrecisionEnum.SECOND;
062
063  /**
064   * Constructor
065   */
066  public DateTimeType() {
067    super();
068  }
069
070  /**
071   * Create a new DateTimeDt with seconds precision and the local time zone
072   */
073  public DateTimeType(Date theDate) {
074    super(theDate, DEFAULT_PRECISION, TimeZone.getDefault());
075  }
076
077  /**
078   * Constructor which accepts a date value and a precision value. Valid
079   * precisions values for this type are:
080   * <ul>
081   * <li>{@link TemporalPrecisionEnum#YEAR}
082   * <li>{@link TemporalPrecisionEnum#MONTH}
083   * <li>{@link TemporalPrecisionEnum#DAY}
084   * <li>{@link TemporalPrecisionEnum#SECOND}
085   * <li>{@link TemporalPrecisionEnum#MILLI}
086   * </ul>
087   * 
088   * @throws DataFormatException If the specified precision is not allowed for
089   *                             this type
090   */
091  public DateTimeType(Date theDate, TemporalPrecisionEnum thePrecision) {
092    super(theDate, thePrecision, TimeZone.getDefault());
093  }
094
095  /**
096   * Create a new instance using a string date/time
097   * 
098   * @throws DataFormatException If the specified precision is not allowed for
099   *                             this type
100   */
101  public DateTimeType(String theValue) {
102    super(theValue);
103  }
104
105  /**
106   * Constructor which accepts a date value, precision value, and time zone. Valid
107   * precisions values for this type are:
108   * <ul>
109   * <li>{@link TemporalPrecisionEnum#YEAR}
110   * <li>{@link TemporalPrecisionEnum#MONTH}
111   * <li>{@link TemporalPrecisionEnum#DAY}
112   * <li>{@link TemporalPrecisionEnum#SECOND}
113   * <li>{@link TemporalPrecisionEnum#MILLI}
114   * </ul>
115   */
116  public DateTimeType(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimezone) {
117    super(theDate, thePrecision, theTimezone);
118  }
119
120  /**
121   * Constructor
122   */
123  public DateTimeType(Calendar theCalendar) {
124    if (theCalendar != null) {
125      setValue(theCalendar.getTime());
126      setPrecision(DEFAULT_PRECISION);
127      setTimeZone(theCalendar.getTimeZone());
128    }
129  }
130
131  @Override
132  boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
133    switch (thePrecision) {
134    case YEAR:
135    case MONTH:
136    case DAY:
137    case SECOND:
138    case MILLI:
139      return true;
140    default:
141      return false;
142    }
143  }
144
145  /**
146   * Returns a new instance of DateTimeType with the current system time and
147   * SECOND precision and the system local time zone
148   */
149  public static DateTimeType now() {
150    return new DateTimeType(new Date(), TemporalPrecisionEnum.SECOND, TimeZone.getDefault());
151  }
152
153  /**
154   * Returns the default precision for this datatype
155   * 
156   * @see #DEFAULT_PRECISION
157   */
158  @Override
159  protected TemporalPrecisionEnum getDefaultPrecisionForDatatype() {
160    return DEFAULT_PRECISION;
161  }
162
163  @Override
164  public DateTimeType copy() {
165    DateTimeType ret = new DateTimeType(getValueAsString());
166    copyValues(ret);
167    return ret;
168  }
169
170  /**
171   * Creates a new instance by parsing an HL7 v3 format date time string
172   */
173  public static DateTimeType parseV3(String theV3String) {
174    DateTimeType retVal = new DateTimeType();
175    retVal.setValueAsV3String(theV3String);
176    return retVal;
177  }
178
179  public static DateTimeType today() {
180    DateTimeType retVal = now();
181    retVal.setPrecision(TemporalPrecisionEnum.DAY);
182    return retVal;
183  }
184
185  public boolean getTzSign() {
186    return getTimeZone().getRawOffset() >= 0;
187  }
188
189  public int getTzHour() {
190    return (int) (getTimeZone().getRawOffset() / DateUtils.MILLIS_PER_MINUTE) / 60;
191  }
192
193  public int getTzMin() {
194    return (int) (getTimeZone().getRawOffset() / DateUtils.MILLIS_PER_MINUTE) % 60;
195  }
196
197  public String fhirType() {
198    return "dateTime";
199  }
200
201  public String getAsV3() {
202    String r = getValueAsString();
203    r = stripChar(r, 16, ':');
204    r = stripChar(r, 13, ':');
205    r = stripChar(r, 10, 'T');
206    r = stripChar(r, 7, '-');
207    r = stripChar(r, 4, '-');
208    r = r.replaceAll(":", ""); // might be in the timezone
209    return r;
210  }
211
212  private String stripChar(String r, int i, char c) {
213    if (r.length() <= i || r.charAt(i) != c)
214      return r;
215    return r.substring(0, i) + r.substring(i + 1);
216  }
217
218  @Override
219  public boolean isDateTime() {
220    return true;
221  }
222
223}