001package ca.uhn.fhir.model.primitive;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2021 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import java.util.Calendar;
024import java.util.Date;
025import java.util.TimeZone;
026
027import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
028import ca.uhn.fhir.model.api.annotation.DatatypeDef;
029import ca.uhn.fhir.model.api.annotation.SimpleSetter;
030import ca.uhn.fhir.parser.DataFormatException;
031
032/**
033 * Represents a FHIR instant datatype. Valid precisions values for this type are:
034 * <ul>
035 * <li>{@link TemporalPrecisionEnum#SECOND}
036 * <li>{@link TemporalPrecisionEnum#MILLI}
037 * </ul>
038 */
039@DatatypeDef(name = "instant")
040public class InstantDt extends BaseDateTimeDt {
041
042        /**
043         * The default precision for this type
044         */
045        public static final TemporalPrecisionEnum DEFAULT_PRECISION = TemporalPrecisionEnum.MILLI;
046
047        /**
048         * Constructor which creates an InstantDt with <b>no timne value</b>. Note
049         * that unlike the default constructor for the Java {@link Date} or
050         * {@link Calendar} objects, this constructor does not initialize the object
051         * with the current time.
052         * 
053         * @see #withCurrentTime() to create a new object that has been initialized
054         *      with the current time.
055         */
056        public InstantDt() {
057                super();
058        }
059
060        /**
061         * Create a new DateTimeDt
062         */
063        public InstantDt(Calendar theCalendar) {
064                super(theCalendar.getTime(), DEFAULT_PRECISION, theCalendar.getTimeZone());
065        }
066
067        /**
068         * Create a new instance using the given date, precision level, and time zone
069         * 
070         * @throws DataFormatException
071         *             If the specified precision is not allowed for this type
072         */
073        public InstantDt(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimezone) {
074                super(theDate, thePrecision, theTimezone);
075        }
076
077
078        /**
079         * Create a new DateTimeDt using an existing value. <b>Use this constructor with caution</b>,
080         * as it may create more precision than warranted (since for example it is possible to pass in
081         * a DateTime with only a year, and this constructor will convert to an InstantDt with 
082         * milliseconds precision).
083         */
084        public InstantDt(BaseDateTimeDt theDateTime) {
085                // Do not call super(foo) here, we don't want to trigger a DataFormatException
086                setValue(theDateTime.getValue());
087                setPrecision(DEFAULT_PRECISION);
088                setTimeZone(theDateTime.getTimeZone());
089        }
090
091        /**
092         * Create a new DateTimeDt with the given date/time and {@link TemporalPrecisionEnum#MILLI} precision
093         */
094        @SimpleSetter(suffix = "WithMillisPrecision")
095        public InstantDt(@SimpleSetter.Parameter(name = "theDate") Date theDate) {
096                super(theDate, DEFAULT_PRECISION, TimeZone.getDefault());
097        }
098
099        /**
100         * Constructor which accepts a date value and a precision value. Valid
101         * precisions values for this type are:
102         * <ul>
103         * <li>{@link TemporalPrecisionEnum#SECOND}
104         * <li>{@link TemporalPrecisionEnum#MILLI}
105         * </ul>
106         */
107        @SimpleSetter
108        public InstantDt(@SimpleSetter.Parameter(name = "theDate") Date theDate, @SimpleSetter.Parameter(name = "thePrecision") TemporalPrecisionEnum thePrecision) {
109                setValue(theDate);
110                setPrecision(thePrecision);
111                setTimeZone(TimeZone.getDefault());
112        }
113
114        /**
115         * Create a new InstantDt from a string value
116         * 
117         * @param theString
118         *            The string representation of the string. Must be in a valid
119         *            format according to the FHIR specification
120         * @throws DataFormatException
121         */
122        public InstantDt(String theString) {
123                super(theString);
124        }
125
126        /**
127         * Invokes {@link Date#after(Date)} on the contained Date against the given
128         * date
129         * 
130         * @throws NullPointerException
131         *             If the {@link #getValue() contained Date} is null
132         */
133        public boolean after(Date theDate) {
134                return getValue().after(theDate);
135        }
136
137        /**
138         * Invokes {@link Date#before(Date)} on the contained Date against the given
139         * date
140         * 
141         * @throws NullPointerException
142         *             If the {@link #getValue() contained Date} is null
143         */
144        public boolean before(Date theDate) {
145                return getValue().before(theDate);
146        }
147
148        /**
149         * Sets the value of this instant to the current time (from the system
150         * clock) and the local/default timezone (as retrieved using
151         * {@link TimeZone#getDefault()}. This TimeZone is generally obtained from
152         * the underlying OS.
153         */
154        public void setToCurrentTimeInLocalTimeZone() {
155                setValue(new Date());
156                setTimeZone(TimeZone.getDefault());
157        }
158
159        @Override
160        protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
161                switch (thePrecision) {
162                case SECOND:
163                case MILLI:
164                        return true;
165                default:
166                        return false;
167                }
168        }
169
170        /**
171         * Factory method which creates a new InstantDt with millisecond precision and initializes it with the
172         * current time and the system local timezone.
173         */
174        public static InstantDt withCurrentTime() {
175                return new InstantDt(new Date(), TemporalPrecisionEnum.MILLI, TimeZone.getDefault());
176        }
177
178        /**
179         * Returns the default precision for this datatype
180         * 
181         * @see #DEFAULT_PRECISION
182         */
183        @Override
184        protected TemporalPrecisionEnum getDefaultPrecisionForDatatype() {
185                return DEFAULT_PRECISION;
186        }
187
188}