/* * Copyright (c) 2004, Rob Gordon. */ package org.oddjob.values.types; import java.io.Serializable; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import org.oddjob.arooa.ArooaValue; import org.oddjob.arooa.convert.ConversionProvider; import org.oddjob.arooa.convert.ConversionRegistry; import org.oddjob.arooa.convert.Convertlet; import org.oddjob.arooa.convert.ConvertletException; import org.oddjob.arooa.types.ValueType; import org.oddjob.arooa.utils.DateHelper; import org.oddjob.util.Clock; import org.oddjob.util.DateProvider; import org.oddjob.util.DateShortcuts; import org.oddjob.util.DefaultClock; /** * @oddjob.description Define a Date. * <p> * Oddjob's inbuilt conversion allows a date to be specified as text in * any of these formats:</p> * <dl> * <dt>yyyy-MM-dd</dt><dd>Just the date.</dd> * <dt>yyyy-MM-dd HH:mm</dt><dd>The date, hours and minutes.</dd> * <dt>yyyy-MM-dd HH:mm:ss</dt><dd>The date, hours, minutes and seconds.</dd> * <dt>yyyy-MM-dd HH:mm:ss.SSS</dt><dd>The date, hours, minutes, seconds * and milliseconds.</dd> * </dl> * <p>Because of this a date property of a job can be specified perfectly * easily as a {@link ValueType} or a property. However there are two situations * when this is inadequate:</p> * <ul> * <li>The text format of the date is not in one of the formats above.</li> * <li>The date must be specified in a different time zone.</li> * </ul> * <p>In either or both of these cases the date type can be used.</p> * <p> * This date type can also be used to specify a java Calendar property which * Oddjob's inbuilt conversion will currently not do from text. * <p> * Since v1.3 The date can also be specified using one of these shortcuts: * <dl> * <dt>NOW</dt><dd>The date and time now.</dd> * <dt>TODAY</dt><dd>The date as of midnight.</dd> * <dt>YESTERDAY</dt><dd>The date yesterday at midnight.</dd> * <dt>TOMORROW</dt><dd>The date tomorrow at midnight.</dd> * </dl> * * @oddjob.example A simple example of specifying a date. * * {@oddjob.xml.resource org/oddjob/values/types/SimpleDateExample.xml} * * @oddjob.example Specifying a date in a different format. * * {@oddjob.xml.resource org/oddjob/values/types/DateFormatExample.xml} * * @oddjob.example Adjusting a date by Time Zone. * * {@oddjob.xml.resource org/oddjob/values/types/DateWithTimeZoneExample.xml#sequential} * * @oddjob.example Date shortcuts. * * {@oddjob.xml.resource org/oddjob/values/types/DateShortcutsExample.xml} * * @author Rob Gordon. */ public class DateType implements ArooaValue, Serializable { private static final long serialVersionUID = 20070312; public static class Conversions implements ConversionProvider { public void registerWith(ConversionRegistry registry) { registry.register(DateType.class, Date.class, new Convertlet<DateType, Date>() { public Date convert(DateType from) throws ConvertletException { try { return from.toDate(); } catch (ParseException e) { throw new ConvertletException(e); } } }); registry.register(DateType.class, Calendar.class, new Convertlet<DateType, Calendar>() { public Calendar convert(DateType from) throws ConvertletException { try { return from.toCalandar(); } catch (ParseException e) { throw new ConvertletException(e); } } }); } } /** * @oddjob.property * @oddjob.description A date in text, if a format is specified it is * expected to be in the format provide, otherwise it is expected * to be in the default format.. * @oddjob.required Yes. */ private String date; /** * @oddjob.property * @oddjob.description The format the date is in. * @oddjob.required No. */ private String format; /** * @oddjob.property * @oddjob.description The time zone the date is for. * @oddjob.required No. */ private String timeZone; /** * @oddjob.property * @oddjob.description The clock to use if a date shortcut is * specified. This is mainly here for tests. * @oddjob.required No, defaults to the current time clock. */ private Clock clock; public Calendar toCalandar() throws ParseException { Date date = toDate(); if (date == null) { return null; } TimeZone tz = TimeZone.getDefault(); if (timeZone != null) { tz = TimeZone.getTimeZone(timeZone); } Calendar cal =Calendar.getInstance(tz); cal.setTime(date); return cal; } /** * Convert this type to a date. * * @return A date. May be null if the date property is null. * * @throws ParseException */ public Date toDate() throws ParseException { if (date == null) { return null; } TimeZone theTimeZone = null; if (timeZone != null) { theTimeZone = TimeZone.getTimeZone(timeZone); } if (format == null) { DateProvider provider = DateShortcuts.getShortcut(date); if (provider != null) { return provider.dateFor(getClock(), theTimeZone); } else { return DateHelper.parseDateTime(date, theTimeZone); } } else { SimpleDateFormat sdf = new SimpleDateFormat(format); if (theTimeZone != null) { sdf.setTimeZone(theTimeZone); } return sdf.parse(date); } } public void setDate(String date) { this.date = date; } public String getDate() { return date; } public String getFormat() { return format; } public void setFormat(String format) { this.format = format; } public void setTimeZone(String timeZoneId) { this.timeZone = timeZoneId; } public String getTimeZone() { return timeZone; } public Clock getClock() { if (clock == null) { return new DefaultClock(); } else { return clock; } } public void setClock(Clock clock) { this.clock = clock; } public String toString() { return "DateType: " + date; } }