1 /* 2 * Copyright 2007 Kasper B. Graversen 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.supercsv.cellprocessor; 17 18 import java.text.ParseException; 19 import java.text.SimpleDateFormat; 20 import java.util.Date; 21 import java.util.Locale; 22 23 import org.supercsv.cellprocessor.ift.DateCellProcessor; 24 import org.supercsv.cellprocessor.ift.StringCellProcessor; 25 import org.supercsv.exception.SuperCsvCellProcessorException; 26 import org.supercsv.util.CsvContext; 27 28 /** 29 * Converts a String to a Date using the {@link SimpleDateFormat} class. If you want to convert from a Date to a String, 30 * use the {@link FmtDate} processor. 31 * <p> 32 * Some example date formats you can use are:<br> 33 * <code>"dd/MM/yyyy"</code> (parses a date formatted as "25/12/2011")<br> 34 * <code>"dd-MMM-yy"</code> (parses a date formatted as "25-Dec-11")<br> 35 * <code>"yyyy.MM.dd.HH.mm.ss"</code> (parses a date formatted as "2011.12.25.08.36.33"<br> 36 * <code>"E, dd MMM yyyy HH:mm:ss Z"</code> (parses a date formatted as "Tue, 25 Dec 2011 08:36:33 -0500")<br> 37 * <p> 38 * This processor caters for lenient or non-lenient date interpretations (the default is false for constructors without 39 * a 'lenient' parameter). See {@link SimpleDateFormat#setLenient(boolean)} for more information. 40 * <p> 41 * If you don't wish to use the default Locale when parsing Dates (your data is formatted for a different Locale), then 42 * use the constructor that accepts a Locale. 43 * 44 * @author Kasper B. Graversen 45 * @author James Bassett 46 */ 47 public class ParseDate extends CellProcessorAdaptor implements StringCellProcessor { 48 49 private final String dateFormat; 50 51 private final boolean lenient; 52 53 private final Locale locale; 54 55 /** 56 * Constructs a new <tt>ParseDate</tt> processor which converts a String to a Date using the supplied date format. 57 * This constructor uses non-lenient Date interpretation. 58 * 59 * @param dateFormat 60 * the date format to use 61 * @throws NullPointerException 62 * if dateFormat is null 63 */ 64 public ParseDate(final String dateFormat) { 65 this(dateFormat, false); 66 } 67 68 /** 69 * Constructs a new <tt>ParseDate</tt> processor which converts a String to a Date using the supplied date format. 70 * 71 * @param dateFormat 72 * the date format to use 73 * @param lenient 74 * whether date interpretation is lenient 75 * @throws NullPointerException 76 * if dateFormat is null 77 */ 78 public ParseDate(final String dateFormat, final boolean lenient) { 79 super(); 80 checkPreconditions(dateFormat); 81 this.dateFormat = dateFormat; 82 this.lenient = lenient; 83 this.locale = null; 84 } 85 86 /** 87 * Constructs a new <tt>ParseDate</tt> processor which converts a String to a Date using the supplied date format 88 * and Locale. 89 * 90 * @param dateFormat 91 * the date format to use 92 * @param lenient 93 * whether date interpretation is lenient 94 * @param locale 95 * the Locale used to parse the date 96 * @throws NullPointerException 97 * if dateFormat or locale is null 98 */ 99 public ParseDate(final String dateFormat, final boolean lenient, final Locale locale) { 100 super(); 101 checkPreconditions(dateFormat, locale); 102 this.dateFormat = dateFormat; 103 this.lenient = lenient; 104 this.locale = locale; 105 } 106 107 /** 108 * Constructs a new <tt>ParseDate</tt> processor which converts a String to a Date using the supplied date format, 109 * then calls the next processor in the chain. This constructor uses non-lenient Date interpretation. 110 * 111 * @param dateFormat 112 * the date format to use 113 * @param next 114 * the next processor in the chain 115 * @throws NullPointerException 116 * if dateFormat or next is null 117 */ 118 public ParseDate(final String dateFormat, final DateCellProcessor next) { 119 this(dateFormat, false, next); 120 } 121 122 /** 123 * Constructs a new <tt>ParseDate</tt> processor which converts a String to a Date using the supplied date format, 124 * then calls the next processor in the chain. 125 * 126 * @param dateFormat 127 * the date format to use 128 * @param lenient 129 * whether date interpretation is lenient 130 * @param next 131 * the next processor in the chain 132 * @throws NullPointerException 133 * if dateFormat or next is null 134 */ 135 public ParseDate(final String dateFormat, final boolean lenient, final DateCellProcessor next) { 136 super(next); 137 checkPreconditions(dateFormat); 138 this.dateFormat = dateFormat; 139 this.lenient = lenient; 140 this.locale = null; 141 } 142 143 /** 144 * Constructs a new <tt>ParseDate</tt> processor which converts a String to a Date using the supplied date format 145 * and Locale, then calls the next processor in the chain. 146 * 147 * @param dateFormat 148 * the date format to use 149 * @param lenient 150 * whether date interpretation is lenient 151 * @param locale 152 * the Locale used to parse the date 153 * @param next 154 * the next processor in the chain 155 * @throws NullPointerException 156 * if dateFormat, locale, or next is null 157 */ 158 public ParseDate(final String dateFormat, final boolean lenient, final Locale locale, final DateCellProcessor next) { 159 super(next); 160 checkPreconditions(dateFormat, locale); 161 this.dateFormat = dateFormat; 162 this.lenient = lenient; 163 this.locale = locale; 164 } 165 166 /** 167 * Checks the preconditions for creating a new ParseDate processor with a date format. 168 * 169 * @param dateFormat 170 * the date format to use 171 * @throws NullPointerException 172 * if dateFormat is null 173 */ 174 private static void checkPreconditions(final String dateFormat) { 175 if( dateFormat == null ) { 176 throw new NullPointerException("dateFormat should not be null"); 177 } 178 } 179 180 /** 181 * Checks the preconditions for creating a new ParseDate processor with date format and locale. 182 * 183 * @param dateFormat 184 * the date format to use 185 * @param locale 186 * the Locale used to parse the date 187 * @throws NullPointerException 188 * if dateFormat or locale is null 189 */ 190 private static void checkPreconditions(final String dateFormat, final Locale locale) { 191 if( dateFormat == null ) { 192 throw new NullPointerException("dateFormat should not be null"); 193 } else if( locale == null ) { 194 throw new NullPointerException("locale should not be null"); 195 } 196 } 197 198 /** 199 * {@inheritDoc} 200 * 201 * @throws SuperCsvCellProcessorException 202 * if value is null, isn't a String, or can't be parsed to a Date 203 */ 204 public Object execute(final Object value, final CsvContext context) { 205 validateInputNotNull(value, context); 206 207 if( !(value instanceof String) ) { 208 throw new SuperCsvCellProcessorException(String.class, value, context, this); 209 } 210 211 try { 212 final SimpleDateFormat formatter; 213 if( locale == null ) { 214 formatter = new SimpleDateFormat(dateFormat); 215 } else { 216 formatter = new SimpleDateFormat(dateFormat, locale); 217 } 218 formatter.setLenient(lenient); 219 final Date result = formatter.parse((String) value); 220 return next.execute(result, context); 221 } 222 catch(final ParseException e) { 223 throw new SuperCsvCellProcessorException(String.format("'%s' could not be parsed as a Date", value), 224 context, this, e); 225 } 226 } 227 }