Package org.fao.geonet.domain

Source Code of org.fao.geonet.domain.ISODate

//==============================================================================
//===
//===   ISODate
//===
//==============================================================================
//===  Copyright (C) 2001-2007 Food and Agriculture Organization of the
//===  United Nations (FAO-UN), United Nations World Food Programme (WFP)
//===  and United Nations Environment Programme (UNEP)
//===
//===  This program is free software; you can redistribute it and/or modify
//===  it under the terms of the GNU General Public License as published by
//===  the Free Software Foundation; either version 2 of the License, or (at
//===  your option) any later version.
//===
//===  This program is distributed in the hope that it will be useful, but
//===  WITHOUT ANY WARRANTY; without even the implied warranty of
//===  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//===  General Public License for more details.
//===
//===  You should have received a copy of the GNU General Public License
//===  along with this program; if not, write to the Free Software
//===  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
//===
//===  Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
//===  Rome - Italy. email: geonetwork@osgeo.org
//==============================================================================

package org.fao.geonet.domain;

import static java.util.Calendar.DAY_OF_MONTH;
import static java.util.Calendar.HOUR_OF_DAY;
import static java.util.Calendar.MINUTE;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.SECOND;
import static java.util.Calendar.YEAR;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nonnull;
import javax.persistence.Embeddable;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlValue;

import org.jdom.Element;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Period;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.joda.time.format.ISOPeriodFormat;
import org.joda.time.format.PeriodFormatter;

/**
* Represents a date at a given time.  Provides methods for representing the date as a string and parsing from string.
* <p>
* String format is: yyyy-mm-ddThh:mm:ss
* </p>
*/
@Embeddable
@XmlRootElement
public class ISODate implements Cloneable, Comparable<ISODate>, Serializable, XmlEmbeddable {
    private static final String DEFAULT_DATE_TIME = "3000-01-01T00:00:00.000Z"; // JUNK Value

    // Pattern to check dates
    @XmlTransient
    private static Pattern gsYear = Pattern
            .compile("([0-9]{4})(-([0-2][0-9]):([0-5][0-9])([A-Z]))?");
    @XmlTransient
    private static Pattern gsYearMonth = Pattern
            .compile("([0-9]{4})-([0-1][0-9])(-([0-2][0-9]):([0-5][0-9])([A-Z]))?");

    @XmlTransient
    private boolean _shortDate; // --- 'true' if the format is yyyy-mm-dd

    @XmlTransient
    private Calendar _calendar = Calendar.getInstance();

    // ---------------------------------------------------------------------------
    // ---
    // --- Constructor
    // ---
    // ---------------------------------------------------------------------------

    public ISODate() {
    }

    // ---------------------------------------------------------------------------

    public ISODate(final long time, final boolean shortDate) {
        _calendar.setTimeInMillis(time);
        _shortDate = shortDate;
    }

    public ISODate(final long time) {
        _calendar.setTimeInMillis(time);
        _shortDate = false;
    }

    // ---------------------------------------------------------------------------

    public ISODate(@Nonnull final String isoDate) {
        setDateAndTime(isoDate);
    }

    /**
     * Converts a given ISO date time into the form used to index in Lucene.
     * Returns null if it gets back a ridiculous value
     *
     * @param stringToParse the string to parse
     */
    public static String parseISODateTime(final String stringToParse) {
        String newDateTime = parseISODateTimes(stringToParse, null);
        if (newDateTime.equals(DEFAULT_DATE_TIME)) {
            return null;
        } else {
            return newDateTime;
        }
    }

    /*
     * Converts two ISO date times into standard form used to index in Lucene
     * Always returns something because it is used during the indexing of the
     * metadata record in Lucene - if exception during parsing then it is
     * something ridiculous like JUNK value above
     */
    public static String parseISODateTimes(String input1, String input2) {
        DateTimeFormatter dto = ISODateTimeFormat.dateTime();
        PeriodFormatter p = ISOPeriodFormat.standard();
        DateTime odt1;
        String odt = "";

        // input1 should be some sort of ISO time
        // eg. basic: 20080909, full: 2008-09-09T12:21:00 etc
        // convert everything to UTC so that we remove any timezone
        // problems
        try {
            DateTime idt = parseBasicOrFullDateTime(input1);
            odt1 = dto.parseDateTime(idt.toString()).withZone(
                    DateTimeZone.forID("UTC"));
            odt = odt1.toString();

        } catch (Exception e) {
            e.printStackTrace();
            return DEFAULT_DATE_TIME;
        }

        if (input2 == null || input2.equals(""))
            return odt;

        // input2 can be an ISO time as for input1 but also an ISO time period
        // eg. -P3D or P3D - if an ISO time period then it must be added to the
        // DateTime generated for input1 (odt1)
        // convert everything to UTC so that we remove any timezone
        // problems
        try {
            boolean minus = false;
            if (input2.startsWith("-P")) {
                input2 = input2.substring(1);
                minus = true;
            }

            if (input2.startsWith("P")) {
                Period ip = p.parsePeriod(input2);
                DateTime odt2;
                if (!minus)
                    odt2 = odt1.plus(ip.toStandardDuration().getMillis());
                else
                    odt2 = odt1.minus(ip.toStandardDuration().getMillis());
                odt = odt + "|" + odt2.toString();
            } else {
                DateTime idt = parseBasicOrFullDateTime(input2);
                DateTime odt2 = dto.parseDateTime(idt.toString()).withZone(
                        DateTimeZone.forID("UTC"));
                odt = odt + "|" + odt2.toString();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return odt + "|" + DEFAULT_DATE_TIME;
        }

        return odt;
    }

    public static DateTime parseBasicOrFullDateTime(String input1)
            throws Exception {
        DateTimeFormatter bd = ISODateTimeFormat.basicDate();
        DateTimeFormatter bt = ISODateTimeFormat.basicTime();
        DateTimeFormatter bdt = ISODateTimeFormat.basicDateTime();
        DateTimeFormatter dtp = ISODateTimeFormat.dateTimeParser();
        DateTime idt;
        Matcher matcher;
        if (input1.length() == 8 && !input1.startsWith("T")) {
            idt = bd.parseDateTime(input1);
        } else if (input1.startsWith("T") && !input1.contains(":")) {
            idt = bt.parseDateTime(input1);
        } else if (input1.contains("T") && !input1.contains(":")
                   && !input1.contains("-")) {
            idt = bdt.parseDateTime(input1);
        } else if ((matcher = gsYearMonth.matcher(input1)).matches()) {
            String year = matcher.group(1);
            String month = matcher.group(2);
            String minute = "00";
            String hour = "00";
            String timezone = "Z";
            if (matcher.group(4) != null) {
                minute = matcher.group(5);
                hour = matcher.group(4);
                timezone = matcher.group(6);
            }

            idt = generateDate(year, month, minute, hour, timezone);
        } else if ((matcher = gsYear.matcher(input1)).matches()) {
            String year = matcher.group(1);
            String month = "01";
            String minute = "00";
            String hour = "00";
            String timezone = "Z";
            if (matcher.group(3) != null) {
                minute = matcher.group(4);
                hour = matcher.group(3);
                timezone = matcher.group(5);
            }

            idt = generateDate(year, month, minute, hour, timezone);
        } else {
            idt = dtp.parseDateTime(input1);
        }
        return idt;
    }

    /**
     * @param year
     * @param month
     * @param minute
     * @param hour
     * @return
     */
    private static DateTime generateDate(String year, String month,
                                         String minute, String hour, String timezone) {

        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, Integer.valueOf(year));
        c.set(Calendar.MONTH, Integer.valueOf(month) - 1);
        c.set(Calendar.DAY_OF_MONTH, 1);

        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        c.set(Calendar.HOUR_OF_DAY, Integer.valueOf(hour));
        c.set(Calendar.MINUTE, Integer.valueOf(minute));

        TimeZone zone = TimeZone.getTimeZone(timezone);
        c.setTimeZone(zone );

        return new DateTime(c.getTimeInMillis());
    }
    // ---------------------------------------------------------------------------
    // ---
    // --- API methods
    // ---
    // ---------------------------------------------------------------------------

    public ISODate clone() {
        ISODate clone;
        try {
            clone = (ISODate) super.clone();
            clone._calendar = (Calendar) _calendar.clone();
            clone._shortDate = _shortDate;
            return clone;
        } catch (CloneNotSupportedException e) {
            return new ISODate(_calendar.getTimeInMillis(), _shortDate);
        }
    }

    // ---------------------------------------------------------------------------

    /**
     * Subtract a date from this date and return the seconds between them.
     * <p>
     * The value is always positive so that date1.timeDifferenceInSeconds(date2) == date2.timeDifferenceInSeconds(date1)
     * </p>
     */
    public long timeDifferenceInSeconds(ISODate date) {
        return getTimeInSeconds() - date.getTimeInSeconds();
    }

    // --------------------------------------------------------------------------
    @Transient
    public String getDateAsString() {
        return getYears() + "-" + pad(getMonths()) + "-" + pad(getDays());
    }

    // --------------------------------------------------------------------------

    public String toString() {
        return getDateAndTime();
    }

    /**
     * Create a java.util.Date object from this.
     *
     * @return a java.util.Date object from this.
     */
    public Date toDate() {
        return (Date) _calendar.getTime().clone();
    }

    // ---------------------------------------------------------------------------
    @Transient
    public long getTimeInSeconds() {
        return _calendar.getTimeInMillis() / 1000;
    }

    /**
     * Get the Time and Date encoded as a String.
     */

  @XmlValue
    public String getDateAndTime() {
        if (_shortDate) {
            return getDateAsString();
        }
        return getDateAsString() + "T" + getTimeAsString();
    }

    public void setDateAndTime(String isoDate) {

        String timeAndDate = isoDate;
        if (timeAndDate == null) {
            throw new IllegalArgumentException("date string is null");
        }

        int indexOfT = timeAndDate.indexOf('T');
        if (indexOfT > -1) {
            // Check if iso date contains time info and if using non UTC time zone to parse the date with
            // JODAISODate. This class converts to UTC format to avoid timezones issues.
            String afterT = timeAndDate.substring(indexOfT + 1);
            boolean timeZoneInfo = afterT.contains("+") || afterT.contains("-");

            if (timeZoneInfo) {
                timeAndDate = parseISODateTime(timeAndDate);
            }
        }
        String[] parts = timeAndDate.toUpperCase().split("T", 2);

        if (parts.length == 1) {
            if (parts[0].contains(":")) {
                parseTime(parts[0]);
            } else {
                parseDate(parts[0]);
            }
        } else {
            if (!parts[0].trim().isEmpty()) {
                parseDate(parts[0]);
            }
            if (!parts[1].trim().isEmpty()) {
                parseTime(parts[1]);
            }
        }
    }

    /**
     * Return true if this object is only the date (year, month, day) and time should be ignored.
     *
     * @return true if this object is only the date (year, month, day) and time should be ignored.
     */
    @Transient
    public boolean isDateOnly() {
        return _shortDate;
    }

    /**
     * Get the date's year.
     */
    @Transient
    public int getYears() {
        return _calendar.get(YEAR);
    }

    /**
     * Get the date's day of month starting at 1.
     */
    @Transient
    public int getDays() {
        return _calendar.get(DAY_OF_MONTH);
    }

    /**
     * Get the date's month of the year starting at 1 and going to 12.
     */
    @Transient
    public int getMonths() {
        return _calendar.get(MONTH) + 1;
    }

    /**
     * Get the date's hour in 24 hour time starting at 0 and going to 23
     */
    @Transient
    public int getHours() {
        return _calendar.get(HOUR_OF_DAY);
    }

    /**
     * Get the date's minute starting at 0 and going to 59
     */
    @Transient
    public int getMinutes() {
        return _calendar.get(MINUTE);
    }

    /**
     * Get the date's second starting at 0 and going to 59
     */
    @Transient
    public int getSeconds() {
        return _calendar.get(SECOND);
    }

    // ------------------------------- Private methods ----------------------------------------------------

    @Override
    public int hashCode() {
        return getTimeAsString().hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ISODate other = (ISODate) obj;
        return getTimeAsString().equals(other.getTimeAsString());
    }

    private void parseDate(@Nonnull String isoDate) {
        try {
            String[] parts = isoDate.split("-|/");
            if (parts.length != 3) {
                throw new IllegalArgumentException("Invalid ISO date : " + isoDate);
            }
            int year;
            if (parts[0].length() < 4) {
                int shortYear = Integer.parseInt(parts[0]);
                String thisYear = String.valueOf(Calendar.getInstance().get(YEAR));
                int century = Integer.parseInt(thisYear.substring(0, 2)) * 100;
                int yearInCentury = Integer.parseInt(thisYear.substring(2));

                if (shortYear <= yearInCentury) {
                    year = century + shortYear;
                } else {
                    year = century - 100 + shortYear;
                }
            } else {
                year = Integer.parseInt(parts[0]);
            }
            int month = Integer.parseInt(parts[1]);
            int day;
            if (parts[2].toLowerCase().endsWith("z")) {
                day = Integer.parseInt(parts[2].substring(0, parts[2].length() - 1));
            } else {
                day = Integer.parseInt(parts[2]);
            }

            _shortDate = true;

            int hour = 0;
            int minute = 0;
            int second = 0;

            _calendar.set(year, month - 1, day, hour, minute, second);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid ISO date : " + isoDate, e);
        }
    }

    private void parseTime(@Nonnull String isoDate) {
        try {
            String[] parts = isoDate.split(":");
            if (parts.length == 1 || parts.length > 3) {
                throw new IllegalArgumentException("Invalid ISO date : " + isoDate);
            }

            int hour = Integer.parseInt(parts[0]);
            int minute = Integer.parseInt(parts[1]);
            int second = 0;
            if (parts.length == 3) {
                String secondsToParse = parts[2];
                int indexOfZ = secondsToParse.toUpperCase().indexOf('Z');
                if (indexOfZ > -1) {
                    secondsToParse = secondsToParse.substring(0, indexOfZ);
                }

                second = (int) Float.parseFloat(secondsToParse);
            }

            _calendar.set(HOUR_OF_DAY, hour);
            _calendar.set(MINUTE, minute);
            _calendar.set(SECOND, second);

            _shortDate = false;
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid ISO date : " + isoDate, e);
        }
    }

    @Transient
    public String getTimeAsString() {
        return pad(getHours()) + ":" + pad(getMinutes()) + ":" + pad(getSeconds());
    }

    private String pad(int value) {
        if (value > 9)
            return Integer.toString(value);

        return "0" + value;
    }

    @Override
    public int compareTo(ISODate o) {
        return _calendar.compareTo(o._calendar);
    }

    @Override
    public void addToXml(Element element) {
        if (isDateOnly()) {
            element.addContent(getDateAsString());
        } else {
            element.addContent(getDateAndTime());
        }
    }
}
TOP

Related Classes of org.fao.geonet.domain.ISODate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.