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

com.feilong.lib.beanutils.converters.DateTimeConverter Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.3.0
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 com.feilong.lib.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.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.feilong.lib.beanutils.ConversionException;

/**
 * {@link com.feilong.lib.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{ /** The Constant log. */ private static final Logger LOGGER = LoggerFactory.getLogger(DateTimeConverter.class); //--------------------------------------------------------------- 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 (LOGGER.isDebugEnabled()){ LOGGER.debug(" Converted to String using format '" + result + "'"); } }else{ result = value.toString(); if (LOGGER.isDebugEnabled()){ LOGGER.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); } 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 (LOGGER.isWarnEnabled()){ LOGGER.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 (LOGGER.isWarnEnabled()){ LOGGER.warn(msg + " (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 + "'"); } 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 (LOGGER.isDebugEnabled()){ LOGGER.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 (LOGGER.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("]"); } LOGGER.debug(buffer.toString()); } } }