All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.utils.CalendarUtils Maven / Gradle / Ivy

There is a newer version: 9.0.1
Show newest version
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
// * with the License.  You may obtain a copy of the License at                                                              *
// *                                                                                                                         *
// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
// *                                                                                                                         *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
// * specific language governing permissions and limitations under the License.                                              *
// ***************************************************************************************************************************
package org.apache.juneau.utils;

import static org.apache.juneau.internal.DateUtils.*;

import java.text.*;
import java.util.*;
import java.util.concurrent.*;

import javax.xml.bind.*;

import org.apache.juneau.internal.*;

/**
 * Utility class for converting {@link Calendar} and {@link Date} objects to common serialized forms.
 */
public class CalendarUtils {

	private static final TimeZone GMT = TimeZone.getTimeZone("GMT");

	/**
	 * Valid conversion formats.
	 */
	public static enum Format {

		/**
		 * Transform to ISO8601 date-time-local strings.
		 *
		 * 
Example output:
*
    *
  • "2001-07-04T15:30:45" *
* *
Example input:
*
    *
  • "2001-07-04T15:30:45" *
  • "2001-07-04T15:30:45.1" *
  • "2001-07-04T15:30" *
  • "2001-07-04" *
  • "2001-07" *
  • "2001" *
*/ ISO8601_DTL, /** * Transform to ISO8601 date-time strings. * *
Example output:
*
    *
  • "2001-07-04T15:30:45-05:00" *
  • "2001-07-04T15:30:45Z" *
* *
Example input:
*
    *
  • "2001-07-04T15:30:45-05:00" *
  • "2001-07-04T15:30:45Z" *
  • "2001-07-04T15:30:45.1Z" *
  • "2001-07-04T15:30Z" *
  • "2001-07-04" *
  • "2001-07" *
  • "2001" *
*/ ISO8601_DT, /** * Same as {@link CalendarUtils.Format#ISO8601_DT}, except always serializes in GMT. * *
Example output:
* "2001-07-04T15:30:45Z" */ ISO8601_DTZ, /** * Same as {@link CalendarUtils.Format#ISO8601_DT} except serializes to millisecond precision. * *
Example output:
* "2001-07-04T15:30:45.123Z" */ ISO8601_DTP, /** * Same as {@link CalendarUtils.Format#ISO8601_DTZ} except serializes to millisecond precision. * *
Example output:
* "2001-07-04T15:30:45.123" */ ISO8601_DTPZ, /** * ISO8601 date only. * *
Example output:
* "2001-07-04" */ ISO8601_D, /** * Transform to {@link String Strings} using the {@code Date.toString()} method. * *
Example output:
*
    *
  • "Wed Jul 04 15:30:45 EST 2001" *
*/ TO_STRING, /** * Transform to RFC2822 date-time strings. * *
Example output:
*
    *
  • "Sat, 03 Mar 2001 10:11:12 +0000" // en_US *
  • "土, 03 3 2001 10:11:12 +0000" // ja_JP *
  • "토, 03 3월 2001 10:11:12 +0000" // ko_KR *
*/ RFC2822_DT, /** * Same as {@link CalendarUtils.Format#RFC2822_DT}, except always serializes in GMT. * *
Example output:
*
    *
  • "Sat, 03 Mar 2001 10:11:12 GMT" // en_US *
  • "土, 03 3 2001 10:11:12 GMT" // ja_JP *
  • "토, 03 3월 2001 10:11:12 GMT" // ko_KR *
*/ RFC2822_DTZ, /** * Transform to RFC2822 date strings. * *
Example output:
*
    *
  • "03 Mar 2001" // en_US *
  • "03 3 2001" // ja_JP *
  • "03 3월 2001" // ko_KR *
*/ RFC2822_D, /** * Transform to simple "yyyy/MM/dd HH:mm:ss" date-time strings. * *
Example output:
*
    *
  • "2001/03/03 10:11:12" *
*/ SIMPLE_DT, /** * Transform to simple "yyyy/MM/dd" date strings. * *
Example output:
*
    *
  • "2001/03/03" *
*/ SIMPLE_D, /** * Transform to simple "HH:mm:ss" time strings. * *
Example output:
*
    *
  • "10:11:12" *
*/ SIMPLE_T, /** * Transform to {@link DateFormat#FULL} date strings. * *
Example output:
*
    *
  • "Saturday, March 3, 2001" // en_US *
  • "2001年3月3日" // ja_JP *
  • "2001년 3월 3일 토요일" // ko_KR *
*/ FULL_D, /** * Transform to {@link DateFormat#LONG} date strings. * *
Example output:
*
    *
  • "March 3, 2001" // en_US *
  • "2001/03/03" // ja_JP *
  • "2001년 3월 3일 (토)" // ko_KR *
*/ LONG_D, /** * Transform to {@link DateFormat#MEDIUM} date strings. * *
Example output:
*
    *
  • "Mar 3, 2001" // en_US *
  • "2001/03/03" // ja_JP *
  • "2001. 3. 3" // ko_KR *
*/ MEDIUM_D, /** * Transform to {@link DateFormat#SHORT} date strings. * *
Example output:
*
    *
  • "3/3/01" // en_US *
  • "01/03/03" // ja_JP *
  • "01. 3. 3" // ko_KR *
*/ SHORT_D, /** * Transform to {@link DateFormat#FULL} time strings. * *
Example output:
*
    *
  • "10:11:12 AM GMT" // en_US *
  • "10時11分12秒 GMT" // ja_JP *
  • "오전 10시 11분 12초 GMT" // ko_KR *
*/ FULL_T, /** * Transform to {@link DateFormat#LONG} time strings. * *
Example output:
*
    *
  • "10:11:12 AM GMT" // en_US *
  • "10:11:12 GMT" // ja_JP *
  • "오전 10시 11분 12초" // ko_KR *
*/ LONG_T, /** * Transform to {@link DateFormat#MEDIUM} time strings. * *
Example output:
*
    *
  • "10:11:12 AM" // en_US *
  • "10:11:12" // ja_JP *
  • "오전 10:11:12" // ko_KR *
*/ MEDIUM_T, /** * Transform to {@link DateFormat#SHORT} time strings. * *
Example output:
*
    *
  • "10:11 AM" // en_US *
  • "10:11 AM" // ja_JP *
  • "오전 10:11" // ko_KR *
*/ SHORT_T, /** * Transform to {@link DateFormat#FULL} date-time strings. * *
Example output:
*
    *
  • "Saturday, March 3, 2001 10:11:12 AM GMT" // en_US *
  • "2001年3月3日 10時11分12秒 GMT" // ja_JP *
  • "2001년 3월 3일 토요일 오전 10시 11분 12초 GMT" // ko_KR *
*/ FULL_DT, /** * Transform to {@link DateFormat#LONG} date-time strings. * *
Example output:
*
    *
  • "March 3, 2001 10:11:12 AM GMT" // en_US *
  • "2001/03/03 10:11:12 GMT" // ja_JP *
  • "2001년 3월 3일 (토) 오전 10시 11분 12초" // ko_KR *
*/ LONG_DT, /** * Transform to {@link DateFormat#MEDIUM} date-time strings. * *
Example output:
*
    *
  • "Mar 3, 2001 10:11:12 AM" // en_US *
  • "2001/03/03 10:11:12" // ja_JP *
  • "2001. 3. 3 오전 10:11:12" // ko_KR *
*/ MEDIUM_DT, /** * Transform to {@link DateFormat#SHORT} date-time strings. * *
Example output:
*
    *
  • "3/3/01 10:11 AM" // en_US *
  • "01/03/03 10:11" // ja_JP *
  • "01. 3. 3 오전 10:11" // ko_KR *
*/ SHORT_DT } private static ThreadLocal> patternCache = new ThreadLocal>(); static class DateFormatKey { final CalendarUtils.Format format; final Locale locale; final TimeZone timeZone; final int hashCode; DateFormatKey(CalendarUtils.Format format, Locale locale, TimeZone timeZone) { this.format = format; this.locale = locale; this.timeZone = timeZone; this.hashCode = format.hashCode() + locale.hashCode() + timeZone.hashCode(); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object o) { if (o == null) return false; DateFormatKey key = (DateFormatKey)o; return format.equals(key.format) && locale.equals(key.locale) && timeZone.equals(key.timeZone); } } private static DateFormat getFormat(CalendarUtils.Format format, Locale locale, TimeZone timeZone) { if (locale == null) locale = Locale.getDefault(); if (timeZone == null) timeZone = TimeZone.getDefault(); DateFormatKey key = new DateFormatKey(format, locale, timeZone); Map m1 = patternCache.get(); if (m1 == null) { m1 = new ConcurrentHashMap(); patternCache.set(m1); } DateFormat df = m1.get(key); if (df == null) { String p = null; switch (format) { case ISO8601_DTL: p = "yyyy-MM-dd'T'HH:mm:ss"; break; case ISO8601_D: p = "yyyy-MM-dd"; break; case TO_STRING: p = "EEE MMM dd HH:mm:ss zzz yyyy"; break; case RFC2822_DT: p = "EEE, dd MMM yyyy HH:mm:ss Z"; break; case RFC2822_DTZ: p = "EEE, dd MMM yyyy HH:mm:ss 'GMT'"; break; case RFC2822_D: p = "dd MMM yyyy"; break; case SIMPLE_DT: p = "yyyy/MM/dd HH:mm:ss"; break; case SIMPLE_D: p = "yyyy/MM/dd"; break; case SIMPLE_T: p = "HH:mm:ss"; break; case FULL_D: df = DateFormat.getDateInstance(DateFormat.FULL, locale); break; case LONG_D: df = DateFormat.getDateInstance(DateFormat.LONG, locale); break; case MEDIUM_D: df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); break; case SHORT_D: df = DateFormat.getDateInstance(DateFormat.SHORT, locale); break; case FULL_T: df = DateFormat.getTimeInstance(DateFormat.FULL, locale); break; case LONG_T: df = DateFormat.getTimeInstance(DateFormat.LONG, locale); break; case MEDIUM_T: df = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale); break; case SHORT_T: df = DateFormat.getTimeInstance(DateFormat.SHORT, locale); break; case FULL_DT: df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, locale); break; case LONG_DT: df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); break; case MEDIUM_DT: df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale); break; case SHORT_DT: df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale); break; default: return null; } if (p != null) { df = new SimpleDateFormat(p, locale); } if (df != null) df.setTimeZone(timeZone); m1.put(key, df); } return df; } /** * Converts the specified calendar to a string of the specified format. * * @param c The calendar to serialize. * @param format The date format. * @param locale The locale to use. If null, uses {@link Locale#getDefault()}. * @param timeZone The time zone to use. If null, uses {@link TimeZone#getDefault()}. * @return The serialized date, or null if the calendar was null. * @throws Exception */ public static final String serialize(Calendar c, CalendarUtils.Format format, Locale locale, TimeZone timeZone) throws Exception { if (c == null) return null; if (timeZone == null) timeZone = c.getTimeZone(); switch(format) { case ISO8601_DTL: case ISO8601_D: case RFC2822_D: case RFC2822_DT: case TO_STRING: case FULL_D: case FULL_DT: case FULL_T: case LONG_D: case LONG_DT: case LONG_T: case MEDIUM_D: case MEDIUM_DT: case MEDIUM_T: case SHORT_D: case SHORT_DT: case SHORT_T: case SIMPLE_D: case SIMPLE_DT: case SIMPLE_T: return serializeFromDateFormat(c.getTime(), format, locale, timeZone); case ISO8601_DT: return DatatypeConverter.printDateTime(setTimeZone(c, timeZone)); case ISO8601_DTP: String s = DatatypeConverter.printDateTime(setTimeZone(c, timeZone)); return String.format("%s.%03d%s", s.substring(0, 19), c.get(Calendar.MILLISECOND), s.substring(19)); case ISO8601_DTZ: if (c.getTimeZone().getRawOffset() != 0) { Calendar c2 = Calendar.getInstance(GMT); c2.setTime(c.getTime()); c = c2; } return DatatypeConverter.printDateTime(c); case ISO8601_DTPZ: if (c.getTimeZone().getRawOffset() != 0) { Calendar c2 = Calendar.getInstance(GMT); c2.setTime(c.getTime()); c = c2; } s = DatatypeConverter.printDateTime(c); return String.format("%s.%03d%s", s.substring(0, 19), c.get(Calendar.MILLISECOND), s.substring(19)); case RFC2822_DTZ: return serializeFromDateFormat(c.getTime(), format, locale, GMT); default: break; } return null; } /** * Converts the specified date to a string of the specified format. * * @param format The date format. * @param d The date to serialize. * @param locale The locale to use. If null, uses {@link Locale#getDefault()}. * @param timeZone The time zone to use. If null, uses {@link TimeZone#getDefault()}. * @return The serialized date, or null if the calendar was null. * @throws Exception */ public static final String serialize(Date d, CalendarUtils.Format format, Locale locale, TimeZone timeZone) throws Exception { if (d == null) return null; if (timeZone == null) timeZone = TimeZone.getDefault(); switch(format) { case ISO8601_DTL: case ISO8601_D: case RFC2822_D: case RFC2822_DT: case TO_STRING: case FULL_D: case FULL_DT: case FULL_T: case LONG_D: case LONG_DT: case LONG_T: case MEDIUM_D: case MEDIUM_DT: case MEDIUM_T: case SHORT_D: case SHORT_DT: case SHORT_T: case SIMPLE_D: case SIMPLE_DT: case SIMPLE_T: return serializeFromDateFormat(d, format, locale, timeZone); case ISO8601_DT: Calendar c = new GregorianCalendar(); c.setTime(d); c.setTimeZone(timeZone); return DatatypeConverter.printDateTime(c); case ISO8601_DTP: c = new GregorianCalendar(); c.setTime(d); c.setTimeZone(timeZone); String s = DatatypeConverter.printDateTime(setTimeZone(c, timeZone)); return String.format("%s.%03d%s", s.substring(0, 19), c.get(Calendar.MILLISECOND), s.substring(19)); case ISO8601_DTZ: c = new GregorianCalendar(); c.setTime(d); c.setTimeZone(GMT); return DatatypeConverter.printDateTime(c); case ISO8601_DTPZ: c = new GregorianCalendar(); c.setTime(d); c.setTimeZone(GMT); s = DatatypeConverter.printDateTime(c); return String.format("%s.%03d%s", s.substring(0, 19), c.get(Calendar.MILLISECOND), s.substring(19)); case RFC2822_DTZ: return serializeFromDateFormat(d, format, locale, GMT); } return null; } /** * Converts the specified serialized date back into a {@link Calendar} object. * * @param format The date format. * @param in The serialized date. * @param locale * The locale to use. * If null, uses {@link Locale#getDefault()}. * @param timeZone * The timezone to assume if input string doesn't contain timezone info. * If null, uses {@link TimeZone#getDefault()}. * @return The date as a {@link Calendar}, or null if the input was null or empty. * @throws Exception */ public static final Calendar parseCalendar(String in, CalendarUtils.Format format, Locale locale, TimeZone timeZone) throws Exception { if (StringUtils.isEmpty(in)) return null; if (timeZone == null) timeZone = TimeZone.getDefault(); Date d = null; switch(format) { // These use DatatypeConverter to parse the date. case ISO8601_DTL: case ISO8601_DT: case ISO8601_DTZ: case ISO8601_DTP: case ISO8601_DTPZ: case ISO8601_D: return DatatypeConverter.parseDateTime(toValidISO8601DT(in)); // These don't specify timezones, so we have to assume the timezone is whatever is specified. case RFC2822_D: case SIMPLE_DT: case SIMPLE_D: case SIMPLE_T: case FULL_D: case LONG_D: case MEDIUM_D: case SHORT_D: case MEDIUM_T: case SHORT_T: case MEDIUM_DT: case SHORT_DT: d = getFormat(format, locale, GMT).parse(in); d.setTime(d.getTime() - timeZone.getRawOffset()); break; // This is always in GMT. case RFC2822_DTZ: DateFormat f = getFormat(format, locale, GMT); d = f.parse(in); break; // These specify timezones in the strings, so we don't use the specified timezone. case TO_STRING: case FULL_DT: case FULL_T: case LONG_DT: case LONG_T: case RFC2822_DT: d = getFormat(format, locale, timeZone).parse(in); break; } if (d == null) return null; Calendar c = new GregorianCalendar(); c.setTime(d); c.setTimeZone(timeZone); return c; } /** * Converts the specified serialized date back into a {@link Date} object. * * @param format The date format. * @param in The serialized date. * @param locale * The locale to use. * If null, uses {@link Locale#getDefault()}. * @param timeZone * The timezone to assume if input string doesn't contain timezone info. * If null, uses {@link TimeZone#getDefault()}. * @return The date as a {@link Date}, or null if the input was null or empty. * @throws Exception */ public static final Date parseDate(String in, CalendarUtils.Format format, Locale locale, TimeZone timeZone) throws Exception { if (StringUtils.isEmpty(in)) return null; if (timeZone == null) timeZone = TimeZone.getDefault(); switch(format) { // These use DatatypeConverter to parse the date. case ISO8601_DTL: case ISO8601_D: case ISO8601_DT: case ISO8601_DTZ: case ISO8601_DTP: case ISO8601_DTPZ: return DatatypeConverter.parseDateTime(toValidISO8601DT(in)).getTime(); // These don't specify timezones, so we have to assume the timezone is whatever is specified. case FULL_D: case LONG_D: case MEDIUM_D: case MEDIUM_DT: case MEDIUM_T: case RFC2822_D: case SHORT_D: case SHORT_DT: case SHORT_T: case SIMPLE_D: case SIMPLE_DT: case SIMPLE_T: return getFormat(format, locale, timeZone).parse(in); // This is always in GMT. case RFC2822_DTZ: Date d = getFormat(format, locale, TimeZone.getDefault()).parse(in); d.setTime(d.getTime() + TimeZone.getDefault().getRawOffset()); return d; // These specify timezones in the strings, so we don't use the specified timezone. case TO_STRING: case FULL_DT: case FULL_T: case LONG_DT: case LONG_T: case RFC2822_DT: return getFormat(format, locale, timeZone).parse(in); } return null; } private static String serializeFromDateFormat(Date date, CalendarUtils.Format format, Locale locale, TimeZone timeZone) { DateFormat df = getFormat(format, locale, timeZone); String s = df.format(date); return s; } private static Calendar setTimeZone(Calendar c, TimeZone tz) { if (tz != null && ! tz.equals(c.getTimeZone())) { c = (Calendar)c.clone(); c.setTimeZone(tz); } return c; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy