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.swaps;
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.swap.*;
023
024/**
025 * Swap that converts {@link Calendar} objects to and from strings.
026 *
027 * <p>
028 * Uses the {@link DateTimeFormatter} class for converting {@link Calendar} objects.
029 *
030 * <h5 class='section'>See Also:</h5><ul>
031 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.Swaps">Swaps</a>
032 * </ul>
033 */
034public class TemporalCalendarSwap extends StringSwap<Calendar> {
035
036   /**
037    * Default swap to {@link DateTimeFormatter#BASIC_ISO_DATE}.
038    * <p>
039    * Example: <js>"20111203"</js>
040    */
041   public static class BasicIsoDate extends TemporalCalendarSwap {
042
043      /** Default instance.*/
044      public static final TemporalCalendarSwap DEFAULT = new BasicIsoDate();
045
046      /** Constructor.*/
047      public BasicIsoDate() {
048         super("BASIC_ISO_DATE");
049      }
050   }
051
052   /**
053    * Default swap to {@link DateTimeFormatter#ISO_DATE}.
054    * <p>
055    * Example: <js>"2011-12-03+01:00"</js> or <js>"2011-12-03"</js>
056    */
057   public static class IsoDate extends TemporalCalendarSwap {
058
059      /** Default instance.*/
060      public static final TemporalCalendarSwap DEFAULT = new IsoDate();
061
062      /** Constructor.*/
063      public IsoDate() {
064         super("ISO_DATE");
065      }
066   }
067
068   /**
069    * Default swap to {@link DateTimeFormatter#ISO_DATE_TIME}.
070    * <p>
071    * Example: <js>"2011-12-03T10:15:30+01:00[Europe/Paris]"</js>
072    */
073   public static class IsoDateTime extends TemporalCalendarSwap {
074
075      /** Default instance.*/
076      public static final TemporalCalendarSwap DEFAULT = new IsoDateTime();
077
078      /** Constructor.*/
079      public IsoDateTime() {
080         super("ISO_DATE_TIME");
081      }
082   }
083
084   /**
085    * Default swap to {@link DateTimeFormatter#ISO_INSTANT}.
086    * <p>
087    * Example: <js>"2011-12-03T10:15:30Z"</js>
088    */
089   public static class IsoInstant extends TemporalCalendarSwap {
090
091      /** Default instance.*/
092      public static final TemporalCalendarSwap DEFAULT = new IsoInstant();
093
094      /** Constructor.*/
095      public IsoInstant() {
096         super("ISO_INSTANT");
097      }
098   }
099
100   /**
101    * Default swap to {@link DateTimeFormatter#ISO_LOCAL_DATE}.
102    * <p>
103    * Example: <js>"2011-12-03"</js>
104    */
105   public static class IsoLocalDate extends TemporalCalendarSwap {
106
107      /** Default instance.*/
108      public static final TemporalCalendarSwap DEFAULT = new IsoLocalDate();
109
110      /** Constructor.*/
111      public IsoLocalDate() {
112         super("ISO_LOCAL_DATE");
113      }
114   }
115
116   /**
117    * Default swap to {@link DateTimeFormatter#ISO_LOCAL_DATE_TIME}.
118    * <p>
119    * Example: <js>"2011-12-03T10:15:30"</js>
120    */
121   public static class IsoLocalDateTime extends TemporalCalendarSwap {
122
123      /** Default instance.*/
124      public static final TemporalCalendarSwap DEFAULT = new IsoLocalDateTime();
125
126      /** Constructor.*/
127      public IsoLocalDateTime() {
128         super("ISO_LOCAL_DATE_TIME");
129      }
130   }
131
132   /**
133    * Default swap to {@link DateTimeFormatter#ISO_LOCAL_TIME}.
134    * <p>
135    * Example: <js>"10:15:30"</js>
136    */
137   public static class IsoLocalTime extends TemporalCalendarSwap {
138
139      /** Default instance.*/
140      public static final TemporalCalendarSwap DEFAULT = new IsoLocalTime();
141
142      /** Constructor.*/
143      public IsoLocalTime() {
144         super("ISO_LOCAL_TIME");
145      }
146   }
147
148   /**
149    * Default swap to {@link DateTimeFormatter#ISO_OFFSET_DATE}.
150    * <p>
151    * Example: <js>"2011-12-03"</js>
152    */
153   public static class IsoOffsetDate extends TemporalCalendarSwap {
154
155      /** Default instance.*/
156      public static final TemporalCalendarSwap DEFAULT = new IsoOffsetDate();
157
158      /** Constructor.*/
159      public IsoOffsetDate() {
160         super("ISO_OFFSET_DATE");
161      }
162   }
163
164   /**
165    * Default swap to {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME}.
166    * <p>
167    * Example: <js>"2011-12-03T10:15:30+01:00"</js>
168    */
169   public static class IsoOffsetDateTime extends TemporalCalendarSwap {
170
171      /** Default instance.*/
172      public static final TemporalCalendarSwap DEFAULT = new IsoOffsetDateTime();
173
174      /** Constructor.*/
175      public IsoOffsetDateTime() {
176         super("ISO_OFFSET_DATE_TIME");
177      }
178   }
179
180   /**
181    * Default swap to {@link DateTimeFormatter#ISO_OFFSET_TIME}.
182    * <p>
183    * Example: <js>"10:15:30+01:00"</js>
184    */
185   public static class IsoOffsetTime extends TemporalCalendarSwap {
186
187      /** Default instance.*/
188      public static final TemporalCalendarSwap DEFAULT = new IsoOffsetTime();
189
190      /** Constructor.*/
191      public IsoOffsetTime() {
192         super("ISO_OFFSET_TIME");
193      }
194   }
195
196   /**
197    * Default swap to {@link DateTimeFormatter#ISO_ORDINAL_DATE}.
198    * <p>
199    * Example: <js>"2012-337"</js>
200    */
201   public static class IsoOrdinalDate extends TemporalCalendarSwap {
202
203      /** Default instance.*/
204      public static final TemporalCalendarSwap DEFAULT = new IsoOrdinalDate();
205
206      /** Constructor.*/
207      public IsoOrdinalDate() {
208         super("ISO_ORDINAL_DATE");
209      }
210   }
211
212   /**
213    * Default swap to {@link DateTimeFormatter#ISO_TIME}.
214    * <p>
215    * Example: <js>"10:15:30+01:00"</js> or <js>"10:15:30"</js>
216    */
217   public static class IsoTime extends TemporalCalendarSwap {
218
219      /** Default instance.*/
220      public static final TemporalCalendarSwap DEFAULT = new IsoTime();
221
222      /** Constructor.*/
223      public IsoTime() {
224         super("ISO_TIME");
225      }
226   }
227
228   /**
229    * Default swap to {@link DateTimeFormatter#ISO_WEEK_DATE}.
230    * <p>
231    * Example: <js>"2012-W48-6"</js>
232    */
233   public static class IsoWeekDate extends TemporalCalendarSwap {
234
235      /** Default instance.*/
236      public static final TemporalCalendarSwap DEFAULT = new IsoWeekDate();
237
238      /** Constructor.*/
239      public IsoWeekDate() {
240         super("ISO_WEEK_DATE");
241      }
242   }
243
244   /**
245    * Default swap to {@link DateTimeFormatter#ISO_ZONED_DATE_TIME}.
246    * <p>
247    * Example: <js>"2011-12-03T10:15:30+01:00[Europe/Paris]"</js>
248    */
249   public static class IsoZonedDateTime extends TemporalCalendarSwap {
250
251      /** Default instance.*/
252      public static final TemporalCalendarSwap DEFAULT = new IsoZonedDateTime();
253
254      /** Constructor.*/
255      public IsoZonedDateTime() {
256         super("ISO_ZONED_DATE_TIME");
257      }
258   }
259
260   /**
261    * Default swap to {@link DateTimeFormatter#RFC_1123_DATE_TIME}.
262    * <p>
263    * Example: <js>"Tue, 3 Jun 2008 11:05:30 GMT"</js>
264    */
265   public static class Rfc1123DateTime extends TemporalCalendarSwap {
266
267      /** Default instance.*/
268      public static final TemporalCalendarSwap DEFAULT = new Rfc1123DateTime();
269
270      /** Constructor.*/
271      public Rfc1123DateTime() {
272         super("RFC_1123_DATE_TIME");
273      }
274   }
275
276
277   private final DateTimeFormatter formatter;
278
279   /**
280    * Constructor.
281    *
282    * @param pattern The timestamp format or name of predefined {@link DateTimeFormatter}.
283    */
284   public TemporalCalendarSwap(String pattern) {
285      super(Calendar.class);
286      this.formatter = DateUtils.getFormatter(pattern);
287   }
288
289   @Override /* ObjectSwap */
290   public String swap(BeanSession session, Calendar o) throws Exception {
291      if (o == null)
292         return null;
293      ZonedDateTime t = o instanceof GregorianCalendar ? ((GregorianCalendar)o).toZonedDateTime() : o.toInstant().atZone(session.getTimeZoneId());
294      return formatter.format(t);
295   }
296
297   @Override /* ObjectSwap */
298   public Calendar unswap(BeanSession session, String f, ClassMeta<?> hint) throws Exception {
299      if (f == null)
300         return null;
301
302      ZoneId offset = session.getTimeZoneId();
303      TemporalAccessor ta = new DefaultingTemporalAccessor(formatter.parse(f), offset);
304      return GregorianCalendar.from(ZonedDateTime.from(ta));
305   }
306}