001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.transforms;
014
015import java.time.*;
016import java.time.format.*;
017import java.time.temporal.*;
018import java.util.*;
019
020import org.apache.juneau.*;
021import org.apache.juneau.internal.*;
022import org.apache.juneau.transform.*;
023
024/**
025 * Swap that converts {@link Date} objects to and from strings.
026 *
027 * <p>
028 * Uses the {@link DateTimeFormatter} class for converting {@link Date} objects.
029 */
030public class TemporalDateSwap extends StringSwap<Date> {
031
032   /**
033    * Default swap to {@link DateTimeFormatter#BASIC_ISO_DATE}.
034    * <p>
035    * Example: <js>"20111203"</js>
036    */
037   public static class BasicIsoDate extends TemporalDateSwap {
038
039      /** Default instance.*/
040      public static final TemporalDateSwap DEFAULT = new BasicIsoDate();
041
042      /** Constructor.*/
043      public BasicIsoDate() {
044         super("BASIC_ISO_DATE");
045      }
046   };
047
048   /**
049    * Default swap to {@link DateTimeFormatter#ISO_DATE}.
050    * <p>
051    * Example: <js>"2011-12-03+01:00"</js> or <js>"2011-12-03"</js>
052    */
053   public static class IsoDate extends TemporalDateSwap {
054
055      /** Default instance.*/
056      public static final TemporalDateSwap DEFAULT = new IsoDate();
057
058      /** Constructor.*/
059      public IsoDate() {
060         super("ISO_DATE");
061      }
062   };
063
064   /**
065    * Default swap to {@link DateTimeFormatter#ISO_DATE_TIME}.
066    * <p>
067    * Example: <js>"2011-12-03T10:15:30+01:00[Europe/Paris]"</js>
068    */
069   public static class IsoDateTime extends TemporalDateSwap {
070
071      /** Default instance.*/
072      public static final TemporalDateSwap DEFAULT = new IsoDateTime();
073
074      /** Constructor.*/
075      public IsoDateTime() {
076         super("ISO_DATE_TIME");
077      }
078   };
079
080   /**
081    * Default swap to {@link DateTimeFormatter#ISO_INSTANT}.
082    * <p>
083    * Example: <js>"2011-12-03T10:15:30Z"</js>
084    */
085   public static class IsoInstant extends TemporalDateSwap {
086
087      /** Default instance.*/
088      public static final TemporalDateSwap DEFAULT = new IsoInstant();
089
090      /** Constructor.*/
091      public IsoInstant() {
092         super("ISO_INSTANT");
093      }
094   };
095
096   /**
097    * Default swap to {@link DateTimeFormatter#ISO_LOCAL_DATE}.
098    * <p>
099    * Example: <js>"2011-12-03"</js>
100    */
101   public static class IsoLocalDate extends TemporalDateSwap {
102
103      /** Default instance.*/
104      public static final TemporalDateSwap DEFAULT = new IsoLocalDate();
105
106      /** Constructor.*/
107      public IsoLocalDate() {
108         super("ISO_LOCAL_DATE");
109      }
110   };
111
112   /**
113    * Default swap to {@link DateTimeFormatter#ISO_LOCAL_DATE_TIME}.
114    * <p>
115    * Example: <js>"2011-12-03T10:15:30"</js>
116    */
117   public static class IsoLocalDateTime extends TemporalDateSwap {
118
119      /** Default instance.*/
120      public static final TemporalDateSwap DEFAULT = new IsoLocalDateTime();
121
122      /** Constructor.*/
123      public IsoLocalDateTime() {
124         super("ISO_LOCAL_DATE_TIME");
125      }
126   };
127
128   /**
129    * Default swap to {@link DateTimeFormatter#ISO_LOCAL_TIME}.
130    * <p>
131    * Example: <js>"10:15:30"</js>
132    */
133   public static class IsoLocalTime extends TemporalDateSwap {
134
135      /** Default instance.*/
136      public static final TemporalDateSwap DEFAULT = new IsoLocalTime();
137
138      /** Constructor.*/
139      public IsoLocalTime() {
140         super("ISO_LOCAL_TIME");
141      }
142   };
143
144   /**
145    * Default swap to {@link DateTimeFormatter#ISO_OFFSET_DATE}.
146    * <p>
147    * Example: <js>"2011-12-03"</js>
148    */
149   public static class IsoOffsetDate extends TemporalDateSwap {
150
151      /** Default instance.*/
152      public static final TemporalDateSwap DEFAULT = new IsoOffsetDate();
153
154      /** Constructor.*/
155      public IsoOffsetDate() {
156         super("ISO_OFFSET_DATE");
157      }
158   };
159
160   /**
161    * Default swap to {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME}.
162    * <p>
163    * Example: <js>"2011-12-03T10:15:30+01:00"</js>
164    */
165   public static class IsoOffsetDateTime extends TemporalDateSwap {
166
167      /** Default instance.*/
168      public static final TemporalDateSwap DEFAULT = new IsoOffsetDateTime();
169
170      /** Constructor.*/
171      public IsoOffsetDateTime() {
172         super("ISO_OFFSET_DATE_TIME");
173      }
174   };
175
176   /**
177    * Default swap to {@link DateTimeFormatter#ISO_OFFSET_TIME}.
178    * <p>
179    * Example: <js>"10:15:30+01:00"</js>
180    */
181   public static class IsoOffsetTime extends TemporalDateSwap {
182
183      /** Default instance.*/
184      public static final TemporalDateSwap DEFAULT = new IsoOffsetTime();
185
186      /** Constructor.*/
187      public IsoOffsetTime() {
188         super("ISO_OFFSET_TIME");
189      }
190   };
191
192   /**
193    * Default swap to {@link DateTimeFormatter#ISO_ORDINAL_DATE}.
194    * <p>
195    * Example: <js>"2012-337"</js>
196    */
197   public static class IsoOrdinalDate extends TemporalDateSwap {
198
199      /** Default instance.*/
200      public static final TemporalDateSwap DEFAULT = new IsoOrdinalDate();
201
202      /** Constructor.*/
203      public IsoOrdinalDate() {
204         super("ISO_ORDINAL_DATE");
205      }
206   };
207
208   /**
209    * Default swap to {@link DateTimeFormatter#ISO_TIME}.
210    * <p>
211    * Example: <js>"10:15:30+01:00"</js> or <js>"10:15:30"</js>
212    */
213   public static class IsoTime extends TemporalDateSwap {
214
215      /** Default instance.*/
216      public static final TemporalDateSwap DEFAULT = new IsoTime();
217
218      /** Constructor.*/
219      public IsoTime() {
220         super("ISO_TIME");
221      }
222   };
223
224   /**
225    * Default swap to {@link DateTimeFormatter#ISO_WEEK_DATE}.
226    * <p>
227    * Example: <js>"2012-W48-6"</js>
228    */
229   public static class IsoWeekDate extends TemporalDateSwap {
230
231      /** Default instance.*/
232      public static final TemporalDateSwap DEFAULT = new IsoWeekDate();
233
234      /** Constructor.*/
235      public IsoWeekDate() {
236         super("ISO_WEEK_DATE");
237      }
238   };
239
240   /**
241    * Default swap to {@link DateTimeFormatter#ISO_ZONED_DATE_TIME}.
242    * <p>
243    * Example: <js>"2011-12-03T10:15:30+01:00[Europe/Paris]"</js>
244    */
245   public static class IsoZonedDateTime extends TemporalDateSwap {
246
247      /** Default instance.*/
248      public static final TemporalDateSwap DEFAULT = new IsoZonedDateTime();
249
250      /** Constructor.*/
251      public IsoZonedDateTime() {
252         super("ISO_ZONED_DATE_TIME");
253      }
254   };
255
256   /**
257    * Default swap to {@link DateTimeFormatter#RFC_1123_DATE_TIME}.
258    * <p>
259    * Example: <js>"Tue, 3 Jun 2008 11:05:30 GMT"</js>
260    */
261   public static class Rfc1123DateTime extends TemporalDateSwap {
262
263      /** Default instance.*/
264      public static final TemporalDateSwap DEFAULT = new Rfc1123DateTime();
265
266      /** Constructor.*/
267      public Rfc1123DateTime() {
268         super("RFC_1123_DATE_TIME");
269      }
270   };
271
272
273   private final DateTimeFormatter formatter;
274
275   /**
276    * Constructor.
277    *
278    * @param pattern The timestamp format or name of predefined {@link DateTimeFormatter}.
279    */
280   public TemporalDateSwap(String pattern) {
281      super(Date.class);
282      this.formatter = DateUtils.getFormatter(pattern);
283   }
284
285   @Override /* PojoSwap */
286   public String swap(BeanSession session, Date o) throws Exception {
287      if (o == null)
288         return null;
289      return formatter.format(o.toInstant().atZone(session.getTimeZoneId()));
290   }
291
292   @Override /* PojoSwap */
293   public Date unswap(BeanSession session, String f, ClassMeta<?> hint) throws Exception {
294      if (f == null)
295         return null;
296      ZoneId offset = session.getTimeZoneId();
297      TemporalAccessor ta = new DefaultingTemporalAccessor(formatter.parse(f), offset);
298      return Date.from(ZonedDateTime.from(ta).toInstant());
299   }
300}