package au.net.causal.projo.prefs.transform;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import au.net.causal.projo.prefs.PreferencesException;
/**
* Converts dates between date and string format using one or more date formats.
* <p>
*
* When parsing and multiple date formats are specified, each one is tried in order until a parse error does not occur. This allows dates in multiple formats
* to exist in string form. When converting back from date to string form, the first date format in the list is always used.
*
* @author prunge
*/
public class DateToStringTransformer extends GenericToStringTransformer<Date>
{
private final List<? extends DateFormat> dateFormats;
/**
* Creates a <code>DateToStringTransformer</code> with a single date format.
*
* @param dateFormat the date format to use.
*
* @throws NullPointerException if <code>dateFormat</code> is null.
*/
public DateToStringTransformer(DateFormat dateFormat)
{
this(Collections.singletonList(dateFormat));
if (dateFormat == null)
throw new NullPointerException("dateFormat == null");
}
/**
* Creates a <code>DateToStringTransformer</code> with multiple date formats.
* <p>
*
* When parsing, each date format is used, from the top of the list to the bottom, until a parse error does not occur.
* <p>
*
* When converting to string, the first date format in the list is always used.
*
* @param dateFormats the date formats to use.
*
* @throws NullPointerException if <code>dateFormats</code> is null.
* @throws IllegalArgumentException if <code>dateFormats</code> is empty.
*/
public DateToStringTransformer(List<? extends DateFormat> dateFormats)
{
super(Date.class);
if (dateFormats == null)
throw new NullPointerException("dateFormats == null");
if (dateFormats.isEmpty())
throw new IllegalArgumentException("At least one date format must be specified.");
this.dateFormats = Collections.unmodifiableList(new ArrayList<>(dateFormats));
}
/**
* Creates a <code>DateToStringTransformer</code> with multiple date formats.
* <p>
*
* When parsing, each date format is used, from the top of the list to the bottom, until a parse error does not occur.
* <p>
*
* When converting to string, the first date format in the list is always used.
*
* @param dateFormats the date formats to use.
*
* @throws NullPointerException if <code>dateFormats</code> is null.
* @throws IllegalArgumentException if <code>dateFormats</code> is empty.
*/
public DateToStringTransformer(DateFormat... dateFormats)
{
this(Arrays.asList(dateFormats));
}
@Override
protected Date stringToValue(String s) throws PreferencesException
{
if (s == null)
return(null);
ParseException lastParseError = null;
for (DateFormat dateFormat : dateFormats)
{
try
{
return(dateFormat.parse(s));
}
catch (ParseException e)
{
lastParseError = e;
//Move on to next one
}
}
//If we get here, no date formats worked
//Propogate cause if only one format exists
PreferencesException ex = new PreferencesException("Error parsing date '" + s + "'.");
if (dateFormats.size() == 1)
ex.initCause(lastParseError);
throw ex;
}
@Override
protected String valueToString(Date value) throws PreferencesException
{
if (value == null)
return(null);
DateFormat dateFormat = dateFormats.get(0);
return(dateFormat.format(value));
}
}