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

net.fortuna.ical4j.model.CalendarDateFormat Maven / Gradle / Ivy

The newest version!
package net.fortuna.ical4j.model;

import java.io.Serializable;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * Support conversion of temporal values to/from iCalendar string representations.
 *
 * 
 * 3.3.4.  Date
 *
 * Value Name:  DATE
 *
 * Purpose:  This value type is used to identify values that contain a
 * calendar date.
 *
 * Format Definition:  This value type is defined by the following
 * notation:
 *
 * date               = date-value
 *
 * date-value         = date-fullyear date-month date-mday
 * date-fullyear      = 4DIGIT
 * date-month         = 2DIGIT        ;01-12
 * date-mday          = 2DIGIT        ;01-28, 01-29, 01-30, 01-31
 * ;based on month/year
 *
 * Description:  If the property permits, multiple "date" values are
 * specified as a COMMA-separated list of values.  The format for the
 * value type is based on the [ISO.8601.2004] complete
 * representation, basic format for a calendar date.  The textual
 * format specifies a four-digit year, two-digit month, and two-digit
 * day of the month.  There are no separator characters between the
 * year, month, and day component text.
 *
 * No additional content value encoding (i.e., BACKSLASH character
 * encoding, see Section 3.3.11) is defined for this value type.
 *
 * Example:  The following represents July 14, 1997:
 *
 * 19970714
 *
 * 3.3.5.  Date-Time
 *
 * Value Name:  DATE-TIME
 *
 * Purpose:  This value type is used to identify values that specify a
 * precise calendar date and time of day.
 *
 * Format Definition:  This value type is defined by the following
 * notation:
 *
 * date-time  = date "T" time ;As specified in the DATE and TIME
 * ;value definitions
 *
 * Description:  If the property permits, multiple "DATE-TIME" values
 * are specified as a COMMA-separated list of values.  No additional
 * content value encoding (i.e., BACKSLASH character encoding, see
 * Section 3.3.11) is defined for this value type.
 *
 * The "DATE-TIME" value type is used to identify values that contain
 * a precise calendar date and time of day.  The format is based on
 * the [ISO.8601.2004] complete representation, basic format for a
 * calendar date and time of day.  The text format is a concatenation
 * of the "date", followed by the LATIN CAPITAL LETTER T character,
 * the time designator, followed by the "time" format.
 *
 * The "DATE-TIME" value type expresses time values in three forms:
 *
 * The form of date and time with UTC offset MUST NOT be used.  For
 * example, the following is not valid for a DATE-TIME value:
 *
 * 19980119T230000-0800       ;Invalid time format
 *
 * FORM #1: DATE WITH LOCAL TIME
 *
 * The date with local time form is simply a DATE-TIME value that
 * does not contain the UTC designator nor does it reference a time
 * zone.  For example, the following represents January 18, 1998, at
 * 11 PM:
 *
 * 19980118T230000
 *
 * DATE-TIME values of this type are said to be "floating" and are
 * not bound to any time zone in particular.  They are used to
 * represent the same hour, minute, and second value regardless of
 * which time zone is currently being observed.  For example, an
 * event can be defined that indicates that an individual will be
 * busy from 11:00 AM to 1:00 PM every day, no matter which time zone
 * the person is in.  In these cases, a local time can be specified.
 * The recipient of an iCalendar object with a property value
 * consisting of a local time, without any relative time zone
 * information, SHOULD interpret the value as being fixed to whatever
 * time zone the "ATTENDEE" is in at any given moment.  This means
 * that two "Attendees", in different time zones, receiving the same
 * event definition as a floating time, may be participating in the
 * event at different actual times.  Floating time SHOULD only be
 * used where that is the reasonable behavior.
 *
 * In most cases, a fixed time is desired.  To properly communicate a
 * fixed time in a property value, either UTC time or local time with
 * time zone reference MUST be specified.
 *
 * The use of local time in a DATE-TIME value without the "TZID"
 * property parameter is to be interpreted as floating time,
 * regardless of the existence of "VTIMEZONE" calendar components in
 * the iCalendar object.
 *
 * FORM #2: DATE WITH UTC TIME
 *
 * The date with UTC time, or absolute time, is identified by a LATIN
 * CAPITAL LETTER Z suffix character, the UTC designator, appended to
 * the time value.  For example, the following represents January 19,
 * 1998, at 0700 UTC:
 *
 * 19980119T070000Z
 *
 * The "TZID" property parameter MUST NOT be applied to DATE-TIME
 * properties whose time values are specified in UTC.
 *
 * FORM #3: DATE WITH LOCAL TIME AND TIME ZONE REFERENCE
 *
 * The date and local time with reference to time zone information is
 * identified by the use the "TZID" property parameter to reference
 * the appropriate time zone definition.  "TZID" is discussed in
 * detail in Section 3.2.19.  For example, the following represents
 * 2:00 A.M. in New York on January 19, 1998:
 *
 * TZID=America/New_York:19980119T020000
 *
 * If, based on the definition of the referenced time zone, the local
 * time described occurs more than once (when changing from daylight
 * to standard time), the DATE-TIME value refers to the first
 * occurrence of the referenced time.  Thus, TZID=America/
 * New_York:20071104T013000 indicates November 4, 2007 at 1:30 A.M.
 * EDT (UTC-04:00).  If the local time described does not occur (when
 * changing from standard to daylight time), the DATE-TIME value is
 * interpreted using the UTC offset before the gap in local times.
 * Thus, TZID=America/New_York:20070311T023000 indicates March 11,
 * 2007 at 3:30 A.M. EDT (UTC-04:00), one hour after 1:30 A.M. EST
 * (UTC-05:00).
 *
 * A time value MUST only specify the second 60 when specifying a
 * positive leap second.  For example:
 *
 * 19970630T235960Z
 *
 * Implementations that do not support leap seconds SHOULD interpret
 * the second 60 as equivalent to the second 59.
 *
 * Example:  The following represents July 14, 1997, at 1:30 PM in New
 * York City in each of the three time formats, using the "DTSTART"
 * property.
 *
 * DTSTART:19970714T133000                   ; Local time
 * DTSTART:19970714T173000Z                  ; UTC time
 * DTSTART;TZID=America/New_York:19970714T133000
 * ; Local time and time
 * ; zone reference
 * 
* */ public class CalendarDateFormat implements Serializable { public static class LocalDateTemporalQuery implements TemporalQuery, Serializable { @Override public LocalDate queryFrom(TemporalAccessor temporal) { return LocalDate.from(temporal); } @Override public boolean equals(Object obj) { if (this == obj) return true; return obj != null && getClass() == obj.getClass(); } } public static class LocalDateTimeTemporalQuery implements TemporalQuery, Serializable { @Override public LocalDateTime queryFrom(TemporalAccessor temporal) { return LocalDateTime.from(temporal); } @Override public boolean equals(Object obj) { if (this == obj) return true; return obj != null && getClass() == obj.getClass(); } } public static class OffsetDateTimeTemporalQuery implements TemporalQuery, Serializable { @Override public OffsetDateTime queryFrom(TemporalAccessor temporal) { return OffsetDateTime.from(temporal); } @Override public boolean equals(Object obj) { if (this == obj) return true; return obj != null && getClass() == obj.getClass(); } } public static class InstantTemporalQuery implements TemporalQuery, Serializable { @Override public Instant queryFrom(TemporalAccessor temporal) { return Instant.from(temporal); } @Override public boolean equals(Object obj) { if (this == obj) return true; return obj != null && getClass() == obj.getClass(); } } public static final CalendarDateFormat DATE_FORMAT = new CalendarDateFormat( "yyyyMMdd", new LocalDateTemporalQuery()); public static final CalendarDateFormat FLOATING_DATE_TIME_FORMAT = new CalendarDateFormat( "yyyyMMdd'T'HHmmss", new LocalDateTimeTemporalQuery()); public static final CalendarDateFormat UTC_DATE_TIME_FORMAT = new CalendarDateFormat( "yyyyMMdd'T'HHmmss'Z'", new InstantTemporalQuery()); public static final CalendarDateFormat RELAXED_DATE_TIME_FORMAT = new CalendarDateFormat( "yyyyMMdd'T'HHmmss[X]", new OffsetDateTimeTemporalQuery(), new LocalDateTimeTemporalQuery()); /** * A formatter capable of parsing to multiple temporal types based on the input string. */ public static final CalendarDateFormat DEFAULT_PARSE_FORMAT = new CalendarDateFormat( "yyyyMMdd['T'HHmmss[X]]", new OffsetDateTimeTemporalQuery(), new LocalDateTimeTemporalQuery(), new LocalDateTemporalQuery()); private final String pattern; private transient volatile DateTimeFormatter formatter; private final TemporalQuery[] parsers; /** * Construct a calendar date format instance by deriving a {@link DateTimeFormatter} from the specified * pattern. * @param pattern a pattern to match against parsed value strings * @param parsers a list of parsers to apply in order to determine the best parsed value */ @SafeVarargs public CalendarDateFormat(String pattern, TemporalQuery...parsers) { Objects.requireNonNull(pattern, "pattern"); this.pattern = pattern; this.parsers = parsers; } /** * Construct a calendar date format instances using an explicit {@link DateTimeFormatter}. Note that because * {@link DateTimeFormatter} is not serializable, the volatile formatter value may be lost using this constructor, * in which case it will fall back to using the same pattern as the DEFAULT_PARSE_FORMAT. * * @param formatter the formatter used to derive temporal values from parsed strings */ @SafeVarargs public CalendarDateFormat(DateTimeFormatter formatter, TemporalQuery...parsers) { this("yyyyMMdd['T'HHmmss[X]]", parsers); this.formatter = formatter; } private DateTimeFormatter getFormatter() { if (formatter == null) { synchronized (pattern) { if (formatter == null) { formatter = DateTimeFormatter.ofPattern(pattern); if (pattern.endsWith("'Z'")) { formatter = formatter.withZone(ZoneOffset.UTC); } } } } return formatter; } public TemporalAccessor parse(String dateString) { if (parsers.length > 1) { return getFormatter().parseBest(dateString, parsers); } else if (parsers.length > 0) { return getFormatter().parse(dateString, parsers[0]); } else { return getFormatter().parse(dateString); } } public ZonedDateTime parse(String dateString, ZoneId zoneId) { return ZonedDateTime.parse(dateString, getFormatter().withZone(zoneId)); } public String format(TemporalAccessor date) { return getFormatter().format(date); } public String format(TemporalAccessor date, ZoneId zoneId) { return getFormatter().withZone(zoneId).format(date); } /** * Identify the most applicable date format for the specified temporal list * @param list a list of temporal values * @return a date format instance applicable to the given temporal values */ public static CalendarDateFormat from(List list) { if (!list.isEmpty()) { return from(list.get(0)); } return FLOATING_DATE_TIME_FORMAT; } /** * Identify the most applicable date format for the specified temporal value * @param temporal a temporal value * @return a date format instance applicable to the given temporal value */ public static CalendarDateFormat from(Temporal temporal) { if (TemporalAdapter.isUtc(temporal)) { return UTC_DATE_TIME_FORMAT; } else if (!TemporalAdapter.isDateTimePrecision(temporal)) { return DATE_FORMAT; } else { return FLOATING_DATE_TIME_FORMAT; } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CalendarDateFormat that = (CalendarDateFormat) o; return pattern.equals(that.pattern) && Arrays.equals(parsers, that.parsers); } @Override public int hashCode() { int result = Objects.hash(pattern); result = 31 * result + Arrays.hashCode(parsers); return result; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy