/* * Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata * See LICENSE for license information. */ package ucar.nc2.units; import java.text.SimpleDateFormat; import java.util.Date; import ucar.nc2.time.CalendarDate; import ucar.nc2.time.CalendarDateFormatter; import ucar.nc2.time.CalendarPeriod; /** * Implements the thredds "dateType" and "dateTypeFormatted" XML element types. * This is mostly a general way to specify dates in a string. * It allows a date to mean "present". <strong>"Present" always sorts after any date, including dates in the * future.</strong> * It allows an optional attribute called "type" which is an enumeration like "created", "modified", etc * taken from Dublin Core vocabulary. * <p/> * A DateType can be specified in the following ways: * <ol> * <li>an xsd:date, with form "CCYY-MM-DD" * <li>an xsd:dateTime with form "CCYY-MM-DDThh:mm:ss" * <li>a valid udunits date string * <li>the string "present" * </ol> * * @author john caron * @see <a href=""https://www.unidata.ucar.edu/projects/THREDDS/tech/catalog/InvCatalogSpec.html#dateType"">THREDDS * dateType</a> */ public class DateType { private String text, format, type; private boolean isPresent, isBlank; private final CalendarDate date; /** * Constructor using a java.util.Date * * @param isPresent if true, this represents the "present time" * @param date the given Date */ public DateType(boolean isPresent, java.util.Date date) { this.isPresent = isPresent; this.date = isPresent ? null : CalendarDate.of(date); } /** * Constructor using a java.util.CalendarDate * * @param date the given CalendarDate */ public DateType(CalendarDate date) { this.isPresent = false; this.date = date; } /** * no argument constructor for beans */ public DateType() { isBlank = true; date = null; } /** * copy constructor * * @param src copy from here */ public DateType(DateType src) { text = src.getText(); format = src.getFormat(); type = src.getType(); isPresent = src.isPresent(); isBlank = src.isBlank(); date = src.getCalendarDate(); } /** * Constructor. * * @param text string representation * @param format using java.text.SimpleDateFormat, or null * @param type type of date, or null * @throws java.text.ParseException if error parsing text */ public DateType(String text, String format, String type) throws java.text.ParseException { text = (text == null) ? "" : text.trim(); this.text = text; this.format = format; this.type = type; // see if its blank if (text.isEmpty()) { isBlank = true; date = null; return; } // see if its the string "present" isPresent = text.equalsIgnoreCase("present"); if (isPresent) { this.date = null; return; } // see if its got a format if (format != null) { SimpleDateFormat dateFormat = new java.text.SimpleDateFormat(format); Date d = dateFormat.parse(text); date = CalendarDate.of(d); return; } // see if its a udunits string if (text.indexOf("since") > 0) { date = CalendarDate.parseUdunits(null, text); if (date == null) throw new java.text.ParseException("invalid udunit date unit =" + text, 0); return; } date = CalendarDate.parseISOformat(null, text); if (date == null) throw new java.text.ParseException("invalid ISO date unit =" + text, 0); } /** * Constructor. * * @param text string representation * @param format using java.text.SimpleDateFormat, or null * @param type type of date, or null * @param cal2 ucar.nc2.time.Calendar of date, or null * @throws java.text.ParseException if error parsing text */ public DateType(String text, String format, String type, ucar.nc2.time.Calendar cal2) throws java.text.ParseException { if (cal2 == null) cal2 = ucar.nc2.time.Calendar.getDefault(); text = (text == null) ? "" : text.trim(); this.text = text; this.format = format; this.type = type; // see if its blank if (text.isEmpty()) { isBlank = true; date = null; return; } // see if its the string "present" isPresent = text.equalsIgnoreCase("present"); if (isPresent) { date = null; return; } // see if its got a format if (format != null) { SimpleDateFormat dateFormat = new java.text.SimpleDateFormat(format); java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(dateFormat.parse(text)); date = CalendarDate.of(cal2, c.getTimeInMillis()); return; } // see if its a udunits string String calName = (cal2 == null) ? null : cal2.name(); if (text.indexOf("since") > 0) { date = CalendarDate.parseUdunits(calName, text); if (date == null) throw new java.text.ParseException("invalid udunit date unit =" + text, 0); return; } date = CalendarDate.parseISOformat(calName, text); if (date == null) throw new java.text.ParseException("invalid ISO date unit =" + text, 0); } /** * Get this as a Date. * Does not handle non-standard Calendars. * * @deprecated use getCalendarDate() * @return Date */ public Date getDate() { return isPresent() ? new Date() : date.toDate(); } /** * Get this as a CalendarDate * * @return CalendarDate */ public CalendarDate getCalendarDate() { return isPresent() ? CalendarDate.present() : date; } /** * Does this represent the present time. * * @return true if present time. */ public boolean isPresent() { return isPresent; } /** * Was blank text passed to the constructor. * * @return true if blank text passed to the constructor. */ public boolean isBlank() { return isBlank; } /** * Get a text representation. * * @return text representation */ public String getText() { if (isPresent) text = "present"; if (text == null) text = toDateTimeString(); return text; } /** * Get the SimpleDateFormat format for parsing the text. * * @return SimpleDateFormat format, or null */ public String getFormat() { return format; } /** * Get the type of Date. * * @return type of Date, or null */ public String getType() { return type; } /** * Set the type of Date. * * @param type type of Date */ public DateType setType(String type) { this.type = type; return this; } /** * Is this date before the given date. if isPresent, always false. * * @param d test against this date * @return true if this date before the given date */ public boolean before(Date d) { if (isPresent()) return false; return date.isBefore(CalendarDate.of(d)); } /** * Is this date before the given date. if d.isPresent, always true, else if this.isPresent, false. * * @param d test against this date * @return true if this date before the given date */ public boolean before(DateType d) { if (d.isPresent()) return true; if (isPresent()) return false; return date.isBefore(d.getCalendarDate()); } /** * Is this date after the given date. if isPresent, always true. * * @param d test against this date * @return true if this date after the given date */ public boolean after(Date d) { if (isPresent()) return true; return date.isAfter(CalendarDate.of(d)); } /** * Same as DateFormatter.toDateOnlyString() * * @return formatted date */ public String toDateString() { if (isPresent()) return CalendarDateFormatter.toDateStringPresent(); else return CalendarDateFormatter.toDateString(date); } /** * Same as CalendarDateFormatter.toDateTimeStringISO * * @return formatted date */ public String toDateTimeString() { if (isPresent()) return CalendarDateFormatter.toDateTimeStringISO(new Date()); else return CalendarDateFormatter.toDateTimeStringISO(date); } /** * Get ISO formatted string * * @return ISO formatted date */ public String toDateTimeStringISO() { return toDateTimeString(); } /** * String representation * * @return getText() */ public String toString() { return getText(); } public int hashCode() { if (isBlank()) return 0; if (isPresent()) return 1; return getDate().hashCode(); } public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof DateType)) return false; DateType oo = (DateType) o; if (isPresent() && oo.isPresent()) return true; if (isBlank() && oo.isBlank()) return true; return oo.getDate().equals(getDate()); } // private java.util.Calendar cal = null; public DateType add(TimeDuration d) { return add(d.getTimeUnit()); } public DateType add(TimeUnit d) { CalendarDate useDate = getCalendarDate(); CalendarDate result = useDate.add((int) d.getValueInSeconds(), CalendarPeriod.Field.Second); return new DateType(result); } public DateType subtract(TimeDuration d) { return subtract(d.getTimeUnit()); } public DateType subtract(TimeUnit d) { CalendarDate useDate = getCalendarDate(); CalendarDate result = useDate.add((int) -d.getValueInSeconds(), CalendarPeriod.Field.Second); return new DateType(result); } }