/* * GeoTools - The Open Source Java GIS Toolkit http://geotools.org * (C) 2004-2011, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; version 2.1 of the License. * * This library 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 Lesser General Public License for more details. */ package org.geotools.filter.expression; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.TimeZone; import org.geotools.factory.Hints; import org.geotools.filter.capability.FunctionNameImpl; import org.opengis.filter.capability.FunctionName; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.ExpressionVisitor; import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Literal; /** * {@link Function} to format a time given as a {@link Date} using a {@link SimpleDateFormat} pattern in a time zone supported by {@link TimeZone}. * * <p> * * Parameters: * <ol> * <li>pattern: formatting pattern supported by {@link SimpleDateFormat}, for example "yyyy-MM-dd". * <li>date: the {@link Date} for the time to be formatted or its string representation, for example "1948-01-01T00:00:00Z". A * {@link RuntimeException} with be thrown if the date is malformed (and not null). * <li>timezone: the name of a time zone supported by {@link TimeZone}, for example "UTC" or "Canada/Mountain". Note that unrecognised timezones will * silently be converted to UTC. * </ol> * * <p> * * This function returns null if any parameter is null. * * @author Ben Caradoc-Davies (CSIRO Earth Science and Resource Engineering) */ public class FormatDateTimezoneFunction implements Function { public static final FunctionName NAME = new FunctionNameImpl("FormatDateTimezone", "pattern", "date", "timezone"); private final Literal fallback; private final List<Expression> parameters; public FormatDateTimezoneFunction() { this(new ArrayList<Expression>(), null); } public FormatDateTimezoneFunction(List<Expression> parameters, Literal fallback) { this.parameters = parameters; this.fallback = fallback; } public Object accept(ExpressionVisitor visitor, Object extraData) { return visitor.visit(this, extraData); } public Object evaluate(Object object) { return evaluate(object, Hints.class); } @SuppressWarnings("unchecked") public <T> T evaluate(Object object, Class<T> context) { if (parameters.size() != 3) { throw new RuntimeException(getName() + ": wrong number of parameters (" + parameters.size() + " not 3)"); } // return null if any parameter is null for (Expression p : parameters) { if (p.evaluate(object) == null) { return null; } } String pattern = parameters.get(0).evaluate(object, String.class); Date date = parameters.get(1).evaluate(object, Date.class); if (date == null) { // malformed date that was not null throw new RuntimeException(getName() + ": could not parse date: " + (String) parameters.get(1).evaluate(object, String.class)); } // if timezone is not understood it is silently set to UTC TimeZone timezone = TimeZone.getTimeZone(parameters.get(2).evaluate(object, String.class)); // broken patterns corrupt output but do not cause exceptions DateFormat dateFormat = new SimpleDateFormat(pattern); dateFormat.setTimeZone(timezone); return (T) dateFormat.format(date); } public Literal getFallbackValue() { return fallback; } public FunctionName getFunctionName() { return NAME; } public String getName() { return NAME.getName(); } public List<Expression> getParameters() { return Collections.unmodifiableList(parameters); } }