View Javadoc
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 }