All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.beanutils.converters.DateTimeConverter Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.beanutils.converters;

import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import org.apache.commons.beanutils.ConversionException;

/**
 * {@link org.apache.commons.beanutils.Converter} implementaion
 * that handles conversion to and from date/time objects.
 * 

* This implementation handles conversion for the following * date/time types. *

    *
  • java.util.Date
  • *
  • java.util.Calendar
  • *
  • java.sql.Date
  • *
  • java.sql.Time
  • *
  • java.sql.Timestamp
  • *
* *

String Conversions (to and from)

* This class provides a number of ways in which date/time * conversions to/from Strings can be achieved: *
    *
  • Using the SHORT date format for the default Locale, configure using:
  • *
      *
    • setUseLocaleFormat(true)
    • *
    *
  • Using the SHORT date format for a specified Locale, configure using:
  • *
      *
    • setLocale(Locale)
    • *
    *
  • Using the specified date pattern(s) for the default Locale, configure using:
  • *
      *
    • Either setPattern(String) or * setPatterns(String[])
    • *
    *
  • Using the specified date pattern(s) for a specified Locale, configure using:
  • *
      *
    • setPattern(String) or * setPatterns(String[]) and...
    • *
    • setLocale(Locale)
    • *
    *
  • If none of the above are configured the * toDate(String) method is used to convert * from String to Date and the Dates's * toString() method used to convert from * Date to String.
  • *
* *

* The Time Zone to use with the date format can be specified * using the setTimeZone() method. * * @version $Id$ * @since 1.8.0 */ public abstract class DateTimeConverter extends AbstractConverter { private String[] patterns; private String displayPatterns; private Locale locale; private TimeZone timeZone; private boolean useLocaleFormat; // ----------------------------------------------------------- Constructors /** * Construct a Date/Time Converter that throws a * ConversionException if an error occurs. */ public DateTimeConverter() { super(); } /** * Construct a Date/Time Converter that returns a default * value if an error occurs. * * @param defaultValue The default value to be returned * if the value to be converted is missing or an error * occurs converting the value. */ public DateTimeConverter(final Object defaultValue) { super(defaultValue); } // --------------------------------------------------------- Public Methods /** * Indicate whether conversion should use a format/pattern or not. * * @param useLocaleFormat true if the format * for the locale should be used, otherwise false */ public void setUseLocaleFormat(final boolean useLocaleFormat) { this.useLocaleFormat = useLocaleFormat; } /** * Return the Time Zone to use when converting dates * (or null if none specified. * * @return The Time Zone. */ public TimeZone getTimeZone() { return timeZone; } /** * Set the Time Zone to use when converting dates. * * @param timeZone The Time Zone. */ public void setTimeZone(final TimeZone timeZone) { this.timeZone = timeZone; } /** * Return the Locale for the Converter * (or null if none specified). * * @return The locale to use for conversion */ public Locale getLocale() { return locale; } /** * Set the Locale for the Converter. * * @param locale The Locale. */ public void setLocale(final Locale locale) { this.locale = locale; setUseLocaleFormat(true); } /** * Set a date format pattern to use to convert * dates to/from a java.lang.String. * * @see SimpleDateFormat * @param pattern The format pattern. */ public void setPattern(final String pattern) { setPatterns(new String[] {pattern}); } /** * Return the date format patterns used to convert * dates to/from a java.lang.String * (or null if none specified). * * @see SimpleDateFormat * @return Array of format patterns. */ public String[] getPatterns() { return patterns; } /** * Set the date format patterns to use to convert * dates to/from a java.lang.String. * * @see SimpleDateFormat * @param patterns Array of format patterns. */ public void setPatterns(final String[] patterns) { this.patterns = patterns; if (patterns != null && patterns.length > 1) { final StringBuilder buffer = new StringBuilder(); for (int i = 0; i < patterns.length; i++) { if (i > 0) { buffer.append(", "); } buffer.append(patterns[i]); } displayPatterns = buffer.toString(); } setUseLocaleFormat(true); } // ------------------------------------------------------ Protected Methods /** * Convert an input Date/Calendar object into a String. *

* N.B.If the converter has been configured to with * one or more patterns (using setPatterns()), then * the first pattern will be used to format the date into a String. * Otherwise the default DateFormat for the default locale * (and style if configured) will be used. * * @param value The input value to be converted * @return the converted String value. * @throws Throwable if an error occurs converting to a String */ @Override protected String convertToString(final Object value) throws Throwable { Date date = null; if (value instanceof Date) { date = (Date)value; } else if (value instanceof Calendar) { date = ((Calendar)value).getTime(); } else if (value instanceof Long) { date = new Date(((Long)value).longValue()); } String result = null; if (useLocaleFormat && date != null) { DateFormat format = null; if (patterns != null && patterns.length > 0) { format = getFormat(patterns[0]); } else { format = getFormat(locale, timeZone); } logFormat("Formatting", format); result = format.format(date); if (log().isDebugEnabled()) { log().debug(" Converted to String using format '" + result + "'"); } } else { result = value.toString(); if (log().isDebugEnabled()) { log().debug(" Converted to String using toString() '" + result + "'"); } } return result; } /** * Convert the input object into a Date object of the * specified type. *

* This method handles conversions between the following * types: *

    *
  • java.util.Date
  • *
  • java.util.Calendar
  • *
  • java.sql.Date
  • *
  • java.sql.Time
  • *
  • java.sql.Timestamp
  • *
* * It also handles conversion from a String to * any of the above types. *

* * For String conversion, if the converter has been configured * with one or more patterns (using setPatterns()), then * the conversion is attempted with each of the specified patterns. * Otherwise the default DateFormat for the default locale * (and style if configured) will be used. * * @param The desired target type of the conversion. * @param targetType Data type to which this value should be converted. * @param value The input value to be converted. * @return The converted value. * @throws Exception if conversion cannot be performed successfully */ @Override protected T convertToType(final Class targetType, final Object value) throws Exception { final Class sourceType = value.getClass(); // Handle java.sql.Timestamp if (value instanceof java.sql.Timestamp) { // ---------------------- JDK 1.3 Fix ---------------------- // N.B. Prior to JDK 1.4 the Timestamp's getTime() method // didn't include the milliseconds. The following code // ensures it works consistently accross JDK versions final java.sql.Timestamp timestamp = (java.sql.Timestamp)value; long timeInMillis = ((timestamp.getTime() / 1000) * 1000); timeInMillis += timestamp.getNanos() / 1000000; // ---------------------- JDK 1.3 Fix ---------------------- return toDate(targetType, timeInMillis); } // Handle Date (includes java.sql.Date & java.sql.Time) if (value instanceof Date) { final Date date = (Date)value; return toDate(targetType, date.getTime()); } // Handle Calendar if (value instanceof Calendar) { final Calendar calendar = (Calendar)value; return toDate(targetType, calendar.getTime().getTime()); } // Handle Long if (value instanceof Long) { final Long longObj = (Long)value; return toDate(targetType, longObj.longValue()); } // Convert all other types to String & handle final String stringValue = value.toString().trim(); if (stringValue.length() == 0) { return handleMissing(targetType); } // Parse the Date/Time if (useLocaleFormat) { Calendar calendar = null; if (patterns != null && patterns.length > 0) { calendar = parse(sourceType, targetType, stringValue); } else { final DateFormat format = getFormat(locale, timeZone); calendar = parse(sourceType, targetType, stringValue, format); } if (Calendar.class.isAssignableFrom(targetType)) { return targetType.cast(calendar); } else { return toDate(targetType, calendar.getTime().getTime()); } } // Default String conversion return toDate(targetType, stringValue); } /** * Convert a long value to the specified Date type for this * Converter. *

* * This method handles conversion to the following types: *

    *
  • java.util.Date
  • *
  • java.util.Calendar
  • *
  • java.sql.Date
  • *
  • java.sql.Time
  • *
  • java.sql.Timestamp
  • *
* * @param The target type * @param type The Date type to convert to * @param value The long value to convert. * @return The converted date value. */ private T toDate(final Class type, final long value) { // java.util.Date if (type.equals(Date.class)) { return type.cast(new Date(value)); } // java.sql.Date if (type.equals(java.sql.Date.class)) { return type.cast(new java.sql.Date(value)); } // java.sql.Time if (type.equals(java.sql.Time.class)) { return type.cast(new java.sql.Time(value)); } // java.sql.Timestamp if (type.equals(java.sql.Timestamp.class)) { return type.cast(new java.sql.Timestamp(value)); } // java.util.Calendar if (type.equals(Calendar.class)) { Calendar calendar = null; if (locale == null && timeZone == null) { calendar = Calendar.getInstance(); } else if (locale == null) { calendar = Calendar.getInstance(timeZone); } else if (timeZone == null) { calendar = Calendar.getInstance(locale); } else { calendar = Calendar.getInstance(timeZone, locale); } calendar.setTime(new Date(value)); calendar.setLenient(false); return type.cast(calendar); } final String msg = toString(getClass()) + " cannot handle conversion to '" + toString(type) + "'"; if (log().isWarnEnabled()) { log().warn(" " + msg); } throw new ConversionException(msg); } /** * Default String to Date conversion. *

* This method handles conversion from a String to the following types: *

    *
  • java.sql.Date
  • *
  • java.sql.Time
  • *
  • java.sql.Timestamp
  • *
*

* N.B. No default String conversion * mechanism is provided for java.util.Date * and java.util.Calendar type. * * @param The target type * @param type The date type to convert to * @param value The String value to convert. * @return The converted Number value. */ private T toDate(final Class type, final String value) { // java.sql.Date if (type.equals(java.sql.Date.class)) { try { return type.cast(java.sql.Date.valueOf(value)); } catch (final IllegalArgumentException e) { throw new ConversionException( "String must be in JDBC format [yyyy-MM-dd] to create a java.sql.Date"); } } // java.sql.Time if (type.equals(java.sql.Time.class)) { try { return type.cast(java.sql.Time.valueOf(value)); } catch (final IllegalArgumentException e) { throw new ConversionException( "String must be in JDBC format [HH:mm:ss] to create a java.sql.Time"); } } // java.sql.Timestamp if (type.equals(java.sql.Timestamp.class)) { try { return type.cast(java.sql.Timestamp.valueOf(value)); } catch (final IllegalArgumentException e) { throw new ConversionException( "String must be in JDBC format [yyyy-MM-dd HH:mm:ss.fffffffff] " + "to create a java.sql.Timestamp"); } } final String msg = toString(getClass()) + " does not support default String to '" + toString(type) + "' conversion."; if (log().isWarnEnabled()) { log().warn(" " + msg); log().warn(" (N.B. Re-configure Converter or use alternative implementation)"); } throw new ConversionException(msg); } /** * Return a DateFormat for the Locale. * @param locale The Locale to create the Format with (may be null) * @param timeZone The Time Zone create the Format with (may be null) * * @return A Date Format. */ protected DateFormat getFormat(final Locale locale, final TimeZone timeZone) { DateFormat format = null; if (locale == null) { format = DateFormat.getDateInstance(DateFormat.SHORT); } else { format = DateFormat.getDateInstance(DateFormat.SHORT, locale); } if (timeZone != null) { format.setTimeZone(timeZone); } return format; } /** * Create a date format for the specified pattern. * * @param pattern The date pattern * @return The DateFormat */ private DateFormat getFormat(final String pattern) { final DateFormat format = new SimpleDateFormat(pattern); if (timeZone != null) { format.setTimeZone(timeZone); } return format; } /** * Parse a String date value using the set of patterns. * * @param sourceType The type of the value being converted * @param targetType The type to convert the value to. * @param value The String date value. * * @return The converted Date object. * @throws Exception if an error occurs parsing the date. */ private Calendar parse(final Class sourceType, final Class targetType, final String value) throws Exception { Exception firstEx = null; for (String pattern : patterns) { try { final DateFormat format = getFormat(pattern); final Calendar calendar = parse(sourceType, targetType, value, format); return calendar; } catch (final Exception ex) { if (firstEx == null) { firstEx = ex; } } } if (patterns.length > 1) { throw new ConversionException("Error converting '" + toString(sourceType) + "' to '" + toString(targetType) + "' using patterns '" + displayPatterns + "'"); } else { throw firstEx; } } /** * Parse a String into a Calendar object * using the specified DateFormat. * * @param sourceType The type of the value being converted * @param targetType The type to convert the value to * @param value The String date value. * @param format The DateFormat to parse the String value. * * @return The converted Calendar object. * @throws ConversionException if the String cannot be converted. */ private Calendar parse(final Class sourceType, final Class targetType, final String value, final DateFormat format) { logFormat("Parsing", format); format.setLenient(false); final ParsePosition pos = new ParsePosition(0); final Date parsedDate = format.parse(value, pos); // ignore the result (use the Calendar) if (pos.getErrorIndex() >= 0 || pos.getIndex() != value.length() || parsedDate == null) { String msg = "Error converting '" + toString(sourceType) + "' to '" + toString(targetType) + "'"; if (format instanceof SimpleDateFormat) { msg += " using pattern '" + ((SimpleDateFormat)format).toPattern() + "'"; } if (log().isDebugEnabled()) { log().debug(" " + msg); } throw new ConversionException(msg); } final Calendar calendar = format.getCalendar(); return calendar; } /** * Provide a String representation of this date/time converter. * * @return A String representation of this date/time converter */ @Override public String toString() { final StringBuilder buffer = new StringBuilder(); buffer.append(toString(getClass())); buffer.append("[UseDefault="); buffer.append(isUseDefault()); buffer.append(", UseLocaleFormat="); buffer.append(useLocaleFormat); if (displayPatterns != null) { buffer.append(", Patterns={"); buffer.append(displayPatterns); buffer.append('}'); } if (locale != null) { buffer.append(", Locale="); buffer.append(locale); } if (timeZone != null) { buffer.append(", TimeZone="); buffer.append(timeZone); } buffer.append(']'); return buffer.toString(); } /** * Log the DateFormat creation. * @param action The action the format is being used for * @param format The Date format */ private void logFormat(final String action, final DateFormat format) { if (log().isDebugEnabled()) { final StringBuilder buffer = new StringBuilder(45); buffer.append(" "); buffer.append(action); buffer.append(" with Format"); if (format instanceof SimpleDateFormat) { buffer.append("["); buffer.append(((SimpleDateFormat)format).toPattern()); buffer.append("]"); } buffer.append(" for "); if (locale == null) { buffer.append("default locale"); } else { buffer.append("locale["); buffer.append(locale); buffer.append("]"); } if (timeZone != null) { buffer.append(", TimeZone["); buffer.append(timeZone); buffer.append("]"); } log().debug(buffer.toString()); } } }