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}