001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.model.primitive;
021
022import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
023import ca.uhn.fhir.model.api.annotation.DatatypeDef;
024import ca.uhn.fhir.model.api.annotation.SimpleSetter;
025import ca.uhn.fhir.parser.DataFormatException;
026
027import java.util.Calendar;
028import java.util.Date;
029import java.util.TimeZone;
030
031/**
032 * Represents a FHIR instant datatype. Valid precisions values for this type are:
033 * <ul>
034 * <li>{@link TemporalPrecisionEnum#SECOND}
035 * <li>{@link TemporalPrecisionEnum#MILLI}
036 * </ul>
037 */
038@DatatypeDef(name = "instant")
039public class InstantDt extends BaseDateTimeDt {
040
041        /**
042         * The default precision for this type
043         */
044        public static final TemporalPrecisionEnum DEFAULT_PRECISION = TemporalPrecisionEnum.MILLI;
045
046        /**
047         * Constructor which creates an InstantDt with <b>no timne value</b>. Note
048         * that unlike the default constructor for the Java {@link Date} or
049         * {@link Calendar} objects, this constructor does not initialize the object
050         * with the current time.
051         *
052         * @see #withCurrentTime() to create a new object that has been initialized
053         *      with the current time.
054         */
055        public InstantDt() {
056                super();
057        }
058
059        /**
060         * Create a new DateTimeDt
061         */
062        public InstantDt(Calendar theCalendar) {
063                super(theCalendar.getTime(), DEFAULT_PRECISION, theCalendar.getTimeZone());
064        }
065
066        /**
067         * Create a new instance using the given date, precision level, and time zone
068         *
069         * @throws DataFormatException
070         *             If the specified precision is not allowed for this type
071         */
072        public InstantDt(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimezone) {
073                super(theDate, thePrecision, theTimezone);
074        }
075
076        /**
077         * Create a new DateTimeDt using an existing value. <b>Use this constructor with caution</b>,
078         * as it may create more precision than warranted (since for example it is possible to pass in
079         * a DateTime with only a year, and this constructor will convert to an InstantDt with
080         * milliseconds precision).
081         */
082        public InstantDt(BaseDateTimeDt theDateTime) {
083                // Do not call super(foo) here, we don't want to trigger a DataFormatException
084                setValue(theDateTime.getValue());
085                setPrecision(DEFAULT_PRECISION);
086                setTimeZone(theDateTime.getTimeZone());
087        }
088
089        /**
090         * Create a new DateTimeDt with the given date/time and {@link TemporalPrecisionEnum#MILLI} precision
091         */
092        @SimpleSetter(suffix = "WithMillisPrecision")
093        public InstantDt(@SimpleSetter.Parameter(name = "theDate") Date theDate) {
094                super(theDate, DEFAULT_PRECISION, TimeZone.getDefault());
095        }
096
097        /**
098         * Constructor which accepts a date value and a precision value. Valid
099         * precisions values for this type are:
100         * <ul>
101         * <li>{@link TemporalPrecisionEnum#SECOND}
102         * <li>{@link TemporalPrecisionEnum#MILLI}
103         * </ul>
104         */
105        @SimpleSetter
106        public InstantDt(
107                        @SimpleSetter.Parameter(name = "theDate") Date theDate,
108                        @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}