/* * DCDate.java * * Version: $Revision$ * * Date: $Date$ * * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts * Institute of Technology. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the Hewlett-Packard Company nor the name of the * Massachusetts Institute of Technology nor the names of their * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ package org.dspace.content; import java.text.DateFormatSymbols; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; import org.apache.log4j.Logger; // FIXME: No tests // FIXME: Not very robust - assumes dates will always be valid /** * Dublin Core date utility class *

* Dates in the DSpace database are held in the ISO 8601 format. They are always * stored in UTC, converting to and from the current time zone. *

* YYYY-MM-DDThh:mm:ss *

* There are four levels of granularity, depending on how much date information * is available. *

* Examples: 1994-05-03T15:30:24,1995-10-04, * 2001-10,1975 * * @author Robert Tansley * @version $Revision$ */ public class DCDate { /** Logger */ private static Logger cat = Logger.getLogger(DCDate.class); /** The year, or -1 if none */ private int year; /** The month, or -1 if none */ private int month; /** The day, or -1 if none */ private int day; /** Hours, -1 if none */ private int hours; /** Minutes, -1 if none */ private int minutes; /** seconds, -1 if none */ private int seconds; /** * Calendar object for timezone conversion. Only used if the date has a time * component. */ private GregorianCalendar localGC; /** * DateFormatSymbols for locale monthsname */ private static DateFormatSymbols dfs = null; /** * note the session locale */ private static Locale langMonth = null; /** * Construct a clean date */ public DCDate() { // Set all fields to unknown year = month = day = hours = minutes = seconds = -1; localGC = null; } /** * Construct a date from a Dublin Core value * * @param fromDC * the date string, in ISO 8601 (no timezone, always use UTC/GMT) */ public DCDate(String fromDC) { // Set all fields to unknown year = month = day = hours = minutes = seconds = -1; localGC = null; // An empty date is OK if ((fromDC == null) || fromDC.equals("")) { return; } try { switch (fromDC.length()) { case 20: // Full date and time hours = Integer.parseInt(fromDC.substring(11, 13)); minutes = Integer.parseInt(fromDC.substring(14, 16)); seconds = Integer.parseInt(fromDC.substring(17, 19)); case 10: // Just full date day = Integer.parseInt(fromDC.substring(8, 10)); case 7: // Just year and month month = Integer.parseInt(fromDC.substring(5, 7)); case 4: // Just the year year = Integer.parseInt(fromDC.substring(0, 4)); } } catch (NumberFormatException e) { // Mangled date cat.warn("Mangled date: " + fromDC + " Exception: " + e); year = month = day = hours = minutes = seconds = -1; } } /** * Construct a date object from a Java Date object. * * @param date * the Java Date object. */ public DCDate(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); // Set all fields setDateLocal(calendar.get(Calendar.YEAR), // Uses 1 to 12 implementation below instead of Java's // 0 to 11 convention calendar.get(Calendar.MONTH) + 1, calendar .get(Calendar.DAY_OF_MONTH), calendar .get(Calendar.HOUR_OF_DAY), calendar .get(Calendar.MINUTE), calendar.get(Calendar.SECOND)); } /** * Get a date representing the current instant in time. * * @return a DSpaceDate object representing the current instant. */ public static DCDate getCurrent() { return (new DCDate(new Date())); } /** * Get the date as a string to put back in the Dublin Core * * @return The date as a string. */ public String toString() { StringBuffer sb = new StringBuffer(); if (year > 0) { sb.append(year); } if (month > 0) { sb.append('-').append(fleshOut(month)); } if (day > 0) { sb.append('-').append(fleshOut(day)); } if (hours >= 0) { sb.append("T").append(fleshOut(hours)).append(':').append( fleshOut(minutes)).append(':').append(fleshOut(seconds)) .append("Z"); } return (sb.toString()); } /** * Get the date as a Java Date object * * @return a Date object */ public Date toDate() { GregorianCalendar utcGC = new GregorianCalendar(TimeZone .getTimeZone("UTC")); utcGC.set(year, month - 1, day, hours, minutes, seconds); return utcGC.getTime(); } /** * Set the date. The date passed in is assumed to be in the current time * zone, and is adjusting to fit the current time zone. Unknown values * should be given as -1. * * @param yyyy * the year * @param mm * the month * @param dd * the day * @param hh * the hours * @param mn * the minutes * @param ss * the seconds */ public void setDateLocal(int yyyy, int mm, int dd, int hh, int mn, int ss) { year = month = day = hours = minutes = seconds = -1; if (yyyy > 0) { year = yyyy; } else { return; } if (mm > 0) { month = mm; } else { return; } if (dd > 0) { day = dd; } else { return; } if (hh == -1) { return; } // We have a time, so we need to do a timezone adjustment localGC = new GregorianCalendar(year, month - 1, day, hh, mn, ss); // Adjust to UTC GregorianCalendar utcGC = new GregorianCalendar(TimeZone .getTimeZone("UTC")); utcGC.setTime(localGC.getTime()); year = utcGC.get(Calendar.YEAR); // Notation month = utcGC.get(Calendar.MONTH) + 1; day = utcGC.get(Calendar.DAY_OF_MONTH); hours = utcGC.get(Calendar.HOUR_OF_DAY); minutes = utcGC.get(Calendar.MINUTE); seconds = utcGC.get(Calendar.SECOND); } /** * Get the date as an array of ints, adjusted for the current timezone * * @return the date an an array: ( year, month, day, hour, minute, seconds) - * unset fields are given a value of -1. */ private int[] getDateLocal() { // Handle simple date cases first - no timezone adjustment if (hours == -1) { return new int[] { year, month, day, -1, -1, -1 }; } // We have a full time, adjust to current timezone if (localGC == null) { GregorianCalendar utcGC = new GregorianCalendar(TimeZone .getTimeZone("UTC")); utcGC.set(year, month - 1, day, hours, minutes, seconds); localGC = new GregorianCalendar(); localGC.setTime(utcGC.getTime()); } return new int[] { localGC.get(Calendar.YEAR), localGC.get(Calendar.MONTH) + 1, localGC.get(Calendar.DAY_OF_MONTH), localGC.get(Calendar.HOUR_OF_DAY), localGC.get(Calendar.MINUTE), localGC.get(Calendar.SECOND) }; } /** * Get the year, adjusting for current time zone. * * @return the year */ public int getYear() { return (getDateLocal())[0]; } /** * Get the month, adjusting for current time zone. * * @return the month */ public int getMonth() { return (getDateLocal())[1]; } /** * Get the day, adjusting for current time zone. * * @return the day */ public int getDay() { return (getDateLocal())[2]; } /** * Get the hour, adjusting for current time zone. * * @return the hour */ public int getHour() { return (getDateLocal())[3]; } /** * Get the minute, adjusting for current time zone. * * @return the minute */ public int getMinute() { return (getDateLocal())[4]; } /** * Get the second, adjusting for current time zone. * * @return the second */ public int getSecond() { return (getDateLocal())[5]; } /** * Get the date as an array of ints in GMT * * @return the date an an array: ( year, month, day, hour, minute, seconds) - * unset fields are given a value of -1. */ private int[] getDateGMT() { return new int[] { year, month, day, hours, minutes, seconds }; } /** * Get the year in GMT. * * @return the year */ public int getYearGMT() { return (getDateGMT())[0]; } /** * Get the month in GMT. * * @return the month */ public int getMonthGMT() { return (getDateGMT())[1]; } /** * Get the day in GMT. * * @return the day */ public int getDayGMT() { return (getDateGMT())[2]; } /** * Get the hour in GMT. * * @return the hour */ public int getHourGMT() { return (getDateGMT())[3]; } /** * Get the minute in GMT. * * @return the minute */ public int getMinuteGMT() { return (getDateGMT())[4]; } /** * Get the second in GMT. * * @return the second */ public int getSecondGMT() { return (getDateGMT())[5]; } /** * Flesh out a number to two digits * * @param n * the number * @return the number as a two-digit string */ private String fleshOut(int n) { if (n < 10) { return "0" + n; } else { return String.valueOf(n); } } /** * Get a month's name for a month between 1 and 12. Any invalid month value * (e.g. 0 or -1) will return a value of "Unspecified". * * @param m * the month number * * @return the month name. */ public static String getMonthName(int m, Locale locale) { if ((m > 0) && (m < 13)) { if (dfs == null || !langMonth.equals(locale)) { dfs = new DateFormatSymbols(locale); langMonth = locale; } return dfs.getMonths()[m-1]; } else { return "Unspecified"; } } }