/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. 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. For additional information regarding * copyright in this work, please see the NOTICE file in the top level * directory of this distribution. */ package org.apache.abdera.model; import java.text.FieldPosition; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; /** * <p>Provides an implementation of the Atom Date Construct, * which is itself a specialization of the RFC3339 date-time.</p> * * <p>Per RFC4287:</p> * * <pre> * 3.3. Date Constructs * * A Date construct is an element whose content MUST conform to the * "date-time" production in [RFC3339]. In addition, an uppercase "T" * character MUST be used to separate date and time, and an uppercase * "Z" character MUST be present in the absence of a numeric time zone * offset. * * atomDateConstruct = * atomCommonAttributes, * xsd:dateTime * * Such date values happen to be compatible with the following * specifications: [ISO.8601.1988], [W3C.NOTE-datetime-19980827], and * [W3C.REC-xmlschema-2-20041028]. * * Example Date constructs: * * <updated>2003-12-13T18:30:02Z</updated> * <updated>2003-12-13T18:30:02.25Z</updated> * <updated>2003-12-13T18:30:02+01:00</updated> * <updated>2003-12-13T18:30:02.25+01:00</updated> * * Date values SHOULD be as accurate as possible. For example, it would * be generally inappropriate for a publishing system to apply the same * timestamp to several entries that were published during the course of * a single day. * </pre> * */ public final class AtomDate { private Date value = null; public AtomDate() {} /** * Create an AtomDate using the serialized string format (e.g. 2003-12-13T18:30:02Z). * @param value The serialized date/time value */ public AtomDate(String value) { this(parse(value)); } /** * Create an AtomDate using a java.util.Date * @param value The java.util.Date value */ public AtomDate(Date value) { this.value = value; } /** * Create an AtomDate using a java.util.Calendar. * @param value The java.util.Calendar value */ public AtomDate(Calendar value) { this(value.getTime()); } /** * Create an AtomDate using the number of milliseconds since January 1, 1970, 00:00:00 GMT * @param value The number of milliseconds since January 1, 1970, 00:00:00 GMT */ public AtomDate(long value) { this(new Date(value)); } /** * Return the serialized string form of the Atom date * @return the serialized string form of the date as specified by RFC4287 */ public String getValue() { return format(value); } /** * Sets the value of the Atom date using the serialized string form * @param value The serialized string form of the date */ public void setValue(String value) { this.value = parse(value); } /** * Sets the value of the Atom date using java.util.Date * @param date A java.util.Date */ public void setValue(Date date) { this.value = date; } /** * Sets the value of the Atom date using java.util.Calendar * @param calendar a java.util.Calendar */ public void setValue(Calendar calendar) { this.value = calendar.getTime(); } /** * Sets the value of the Atom date using the number of milliseconds since January 1, 1970, 00:00:00 GMT * @param timestamp The number of milliseconds since January 1, 1970, 00:00:00 GMT */ public void setValue(long timestamp) { this.value = new Date(timestamp); } /** * Returns the value of this Atom Date * @return A java.util.Date representing this Atom Date */ public Date getDate() { return value; } /** * Returns the value of this Atom Date as a java.util.Calendar * @return A java.util.Calendar representing this Atom Date */ public Calendar getCalendar() { Calendar cal = Calendar.getInstance(); cal.setTime(value); return cal; } /** * Returns the value of this Atom Date as the number of milliseconds since January 1, 1970, 00:00:00 GMT * @return The number of milliseconds since January 1, 1970, 00:00:00 GMT */ public long getTime() { return value.getTime(); } @Override public String toString() { return getValue(); } @Override public boolean equals(Object obj) { boolean answer = false; if (obj instanceof Date) { Date d = (Date) obj; answer = (this.value.equals(d)); } else if (obj instanceof String) { Date d = parse((String) obj); answer = (this.value.equals(d)); } else if (obj instanceof Calendar) { Calendar c = (Calendar) obj; answer = (this.value.equals(c.getTime())); } else if (obj instanceof AtomDate) { Date d = ((AtomDate)obj).value; answer = (this.value.equals(d)); } return answer; } /** * The masks used to validate and parse the input to this Atom date. * These are a lot more forgiving than what the Atom spec allows. * The forms that are invalid according to the spec are indicated. */ private static final String[] masks = { "yyyy-MM-dd'T'HH:mm:ss.SSSz", "yyyy-MM-dd't'HH:mm:ss.SSSz", // invalid "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "yyyy-MM-dd't'HH:mm:ss.SSS'z'", // invalid "yyyy-MM-dd'T'HH:mm:ssz", "yyyy-MM-dd't'HH:mm:ssz", // invalid "yyyy-MM-dd'T'HH:mm:ss'Z'", "yyyy-MM-dd't'HH:mm:ss'z'", // invalid "yyyy-MM-dd'T'HH:mmz", // invalid "yyyy-MM-dd't'HH:mmz", // invalid "yyyy-MM-dd'T'HH:mm'Z'", // invalid "yyyy-MM-dd't'HH:mm'z'", // invalid "yyyy-MM-dd", "yyyy-MM", "yyyy" }; /** * Parse the serialized string form into a java.util.Date * @param date The serialized string form of the date * @return The created java.util.Date */ public static Date parse(String date) { Date d = null; SimpleDateFormat sdf = new SimpleDateFormat(); for (int n = 0; n < masks.length; n++) { try { sdf.applyPattern(masks[n]); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); sdf.setLenient(true); d = sdf.parse(date, new ParsePosition(0)); if (d != null) break; } catch (Exception e) {} } if (d == null) throw new IllegalArgumentException(); return d; } /** * Create the serialized string form from a java.util.Date * @param d A java.util.Date * @return The serialized string form of the date */ public static String format (Date d) { StringBuffer iso8601 = new StringBuffer(); SimpleDateFormat sdf = new SimpleDateFormat(masks[2]); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); sdf.format(d, iso8601, new FieldPosition(0)); return iso8601.toString(); } /** * Create a new Atom Date instance from the serialized string form * @param value The serialized string form of the date * @return The created AtomDate */ public static AtomDate valueOf(String value) { return new AtomDate(value); } /** * Create a new Atom Date instance from a java.util.Date * @param value a java.util.Date * @return The created AtomDate */ public static AtomDate valueOf(Date value) { return new AtomDate(value); } /** * Create a new Atom Date instance from a java.util.Calendar * @param value A java.util.Calendar * @return The created AtomDate */ public static AtomDate valueOf(Calendar value) { return new AtomDate(value); } /** * Create a new Atom Date instance using the number of milliseconds since January 1, 1970, 00:00:00 GMT * @param value The number of milliseconds since January 1, 1970, 00:00:00 GMT * @return The created AtomDate */ public static AtomDate valueOf(long value) { return new AtomDate(value); } }