001package co.codewizards.cloudstore.core.dto; 002 003import static co.codewizards.cloudstore.core.util.Util.*; 004 005import java.util.Date; 006 007import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 008 009import co.codewizards.cloudstore.core.dto.jaxb.DateTimeXmlAdapter; 010import co.codewizards.cloudstore.core.util.ISO8601; 011import co.codewizards.cloudstore.core.util.Util; 012 013/** 014 * Immutable representation of a timestamp (a date and a time). 015 * <p> 016 * This object serves as a DTO both inside XML and in URLs (usually as 017 * a query parameter, but it may be used inside a path, too). For this 018 * purpose, its {@link #toString()} method and its {@linkplain #DateTime(String) single-String-argument-constructor} 019 * are used. 020 * @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co 021 */ 022@XmlJavaTypeAdapter(type=DateTime.class, value=DateTimeXmlAdapter.class) 023public class DateTime { 024 025 private final Date date; 026 027 /** 028 * Creates a new instance from the given ISO-8601-encoded {@code dateString}. 029 * <p> 030 * The result of the {@link #toString()} method can be passed to this constructor 031 * to obtain a copy of the original {@code DateTime} instance. This feature should 032 * be used to transport ISO-8601-encoded timestamps over the network: 033 * <p> 034 * <pre> DateTime original = new DateTime(new Date()); 035 * String iso8601encoded = original.toString(); 036 * // iso8601encoded could now be transported to a remote machine as part of a 037 * // REST URL (e.g. as query parameter). 038 * 039 * // The remote machine might then decode it using this REST-conform constructor: 040 * DateTime copy = new DateTime(iso8601encoded);</pre> 041 * <p> 042 * Because of this constructor, {@code DateTime} parameters can be directly used in 043 * REST resource (a.k.a. service) methods. 044 * @param dateString the ISO-8601-encoded form of a timestamp. Must not be <code>null</code>. 045 * @see #toString() 046 */ 047 public DateTime(String dateString) { 048 date = ISO8601.parseDate(assertNotNull("dateString", dateString)); 049 } 050 051 /** 052 * Creates a new instance from the given {@code date}. 053 * <p> 054 * Because {@link Date} instances are mutable, the given {@code date} is cloned. 055 * This way it can be guaranteed that {@code DateTime} instances are immutable. 056 * @param date the date to be cloned and wrapped in the new {@code DateTime} instance. Must not be <code>null</code>. 057 */ 058 public DateTime(Date date) { 059 this.date = (Date) assertNotNull("date", date).clone(); 060 } 061 062 /** 063 * Gets the number of milliseconds since 1970 January 1 00:00:00 GMT represented by this {@code DateTime} object. 064 * @return the number of milliseconds since 1970 January 1 00:00:00 GMT represented by this {@code DateTime} object. 065 * @see Date#getTime() 066 */ 067 public long getMillis() { 068 return date.getTime(); 069 } 070 071 @Override 072 public int hashCode() { 073 return date == null ? 0 : date.hashCode(); 074 } 075 076 @Override 077 public boolean equals(Object obj) { 078 if (this == obj) 079 return true; 080 if (obj == null) 081 return false; 082 if (getClass() != obj.getClass()) 083 return false; 084 DateTime other = (DateTime) obj; 085 return Util.equal(this.date, other.date); 086 } 087 088 /** 089 * Returns an ISO-8601-encoded timestamp which can be passed to {@link #DateTime(String)}. 090 * <p> 091 * <b><u>Inherited javadoc:</u></b> 092 * <p> 093 * {@inheritDoc} 094 * @see #DateTime(String) 095 */ 096 @Override 097 public String toString() { 098 return ISO8601.formatDate(date); 099 } 100 101 /** 102 * Converts this {@code DateTime} into a new {@link Date} instance. 103 * @return a new {@link Date} instance representing the same timestamp as this {@code DateTime}. Never <code>null</code>. 104 */ 105 public Date toDate() { 106 return (Date) date.clone(); 107 } 108}