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