001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2023 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 java.util.Calendar;
023import java.util.Date;
024import java.util.TimeZone;
025
026import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
027import ca.uhn.fhir.model.api.annotation.DatatypeDef;
028import ca.uhn.fhir.model.api.annotation.SimpleSetter;
029import ca.uhn.fhir.parser.DataFormatException;
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        /**
078         * Create a new DateTimeDt using an existing value. <b>Use this constructor with caution</b>,
079         * as it may create more precision than warranted (since for example it is possible to pass in
080         * a DateTime with only a year, and this constructor will convert to an InstantDt with 
081         * milliseconds precision).
082         */
083        public InstantDt(BaseDateTimeDt theDateTime) {
084                // Do not call super(foo) here, we don't want to trigger a DataFormatException
085                setValue(theDateTime.getValue());
086                setPrecision(DEFAULT_PRECISION);
087                setTimeZone(theDateTime.getTimeZone());
088        }
089
090        /**
091         * Create a new DateTimeDt with the given date/time and {@link TemporalPrecisionEnum#MILLI} precision
092         */
093        @SimpleSetter(suffix = "WithMillisPrecision")
094        public InstantDt(@SimpleSetter.Parameter(name = "theDate") Date theDate) {
095                super(theDate, DEFAULT_PRECISION, TimeZone.getDefault());
096        }
097
098        /**
099         * Constructor which accepts a date value and a precision value. Valid
100         * precisions values for this type are:
101         * <ul>
102         * <li>{@link TemporalPrecisionEnum#SECOND}
103         * <li>{@link TemporalPrecisionEnum#MILLI}
104         * </ul>
105         */
106        @SimpleSetter
107        public InstantDt(@SimpleSetter.Parameter(name = "theDate") Date theDate, @SimpleSetter.Parameter(name = "thePrecision") TemporalPrecisionEnum thePrecision) {
108                setValue(theDate);
109                setPrecision(thePrecision);
110                setTimeZone(TimeZone.getDefault());
111        }
112
113        /**
114         * Create a new InstantDt from a string value
115         * 
116         * @param theString
117         *            The string representation of the string. Must be in a valid
118         *            format according to the FHIR specification
119         * @throws DataFormatException
120         */
121        public InstantDt(String theString) {
122                super(theString);
123        }
124
125        /**
126         * Invokes {@link Date#after(Date)} on the contained Date against the given
127         * date
128         * 
129         * @throws NullPointerException
130         *             If the {@link #getValue() contained Date} is null
131         */
132        public boolean after(Date theDate) {
133                return getValue().after(theDate);
134        }
135
136        /**
137         * Invokes {@link Date#before(Date)} on the contained Date against the given
138         * date
139         * 
140         * @throws NullPointerException
141         *             If the {@link #getValue() contained Date} is null
142         */
143        public boolean before(Date theDate) {
144                return getValue().before(theDate);
145        }
146
147        /**
148         * Sets the value of this instant to the current time (from the system
149         * clock) and the local/default timezone (as retrieved using
150         * {@link TimeZone#getDefault()}. This TimeZone is generally obtained from
151         * the underlying OS.
152         */
153        public void setToCurrentTimeInLocalTimeZone() {
154                setValue(new Date());
155                setTimeZone(TimeZone.getDefault());
156        }
157
158        @Override
159        protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
160                switch (thePrecision) {
161                case SECOND:
162                case MILLI:
163                        return true;
164                default:
165                        return false;
166                }
167        }
168
169        /**
170         * Factory method which creates a new InstantDt with millisecond precision and initializes it with the
171         * current time and the system local timezone.
172         */
173        public static InstantDt withCurrentTime() {
174                return new InstantDt(new Date(), TemporalPrecisionEnum.MILLI, TimeZone.getDefault());
175        }
176
177        /**
178         * Returns the default precision for this datatype
179         * 
180         * @see #DEFAULT_PRECISION
181         */
182        @Override
183        protected TemporalPrecisionEnum getDefaultPrecisionForDatatype() {
184                return DEFAULT_PRECISION;
185        }
186
187}