| DateFormatter.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 or later
5 * as published by the Free Software Foundation. This program is distributed
6 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * © CrossWire Bible Society, 2007 - 2016
18 *
19 */
20 package org.crosswire.common.icu;
21
22 import java.lang.reflect.InvocationTargetException;
23 import java.text.DateFormat;
24 import java.text.SimpleDateFormat;
25 import java.util.Date;
26
27 import org.crosswire.common.util.ClassUtil;
28 import org.crosswire.common.util.ReflectionUtil;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33 * DateFormat provides a wrapper of some of DateFormat and SimpleDateFormat
34 * using ICU4J if present, otherwise from core Java. Note, only those methods in
35 * DateFormat that are actually used are here.
36 *
37 * @author DM Smith
38 * @see gnu.lgpl.License The GNU Lesser General Public License for details.<br>
39 * The copyright to this program is held by its authors.
40 */
41 public final class DateFormatter {
42 // Note these values are the same for Java and ICU4J
43 /**
44 * Constant for full style pattern.
45 */
46 public static final int FULL = 0;
47 /**
48 * Constant for long style pattern.
49 */
50 public static final int LONG = 1;
51 /**
52 * Constant for medium style pattern.
53 */
54 public static final int MEDIUM = 2;
55 /**
56 * Constant for short style pattern.
57 */
58 public static final int SHORT = 3;
59 /**
60 * Constant for default style pattern. Its value is MEDIUM.
61 */
62 public static final int DEFAULT = MEDIUM;
63 private static final Logger LOGGER = LoggerFactory.getLogger(DateFormatter.class);
64 private static final String DEFAULT_SIMPLE_DATE_FORMAT_CLASS = "com.ibm.icu.text.SimpleDateFormat";
65 private static final String DEFAULT_DATE_FORMAT_CLASS = "com.ibm.icu.text.DateFormat";
66
67 /**
68 * The actual formatter.
69 */
70 private Object formatter;
71 /**
72 * The class of the formatter
73 */
74 private Class<?> formatterClass;
75 private static Class<?> defaultSimpleDateFormat;
76 private static Class<?> defaultDateFormat;
77
78 static {
79 try {
80 defaultSimpleDateFormat = ClassUtil.forName(DEFAULT_SIMPLE_DATE_FORMAT_CLASS);
81 } catch (ClassNotFoundException ex) {
82 LOGGER.info("Error loading simple date format class [{}]", DEFAULT_SIMPLE_DATE_FORMAT_CLASS);
83 }
84
85 try {
86 defaultDateFormat = ClassUtil.forName(DEFAULT_DATE_FORMAT_CLASS);
87 } catch (ClassNotFoundException ex) {
88 LOGGER.info("Error loading date format class [{}]", DEFAULT_SIMPLE_DATE_FORMAT_CLASS);
89 }
90 }
91
92 /**
93 * Prevent instantiation.
94 */
95 private DateFormatter() {
96 }
97
98 /**
99 * Construct a DateFormatter with the given date format.
100 *
101 * @param format the date format
102 * @return a DateFormatter of the given format
103 * @see java.text.DateFormat#getDateInstance(int)
104 */
105 public static DateFormatter getDateInstance(int format) {
106 DateFormatter fmt = new DateFormatter();
107 boolean oops = false;
108 try {
109 fmt.formatterClass = defaultDateFormat;
110 // To call a method taking a type of int, the type has to match but
111 // the object has to be wrapped
112 Class<?>[] instanceTypes = {
113 int.class
114 };
115 Object[] instanceParams = {
116 Integer.valueOf(format)
117 };
118 fmt.formatter = ReflectionUtil.invoke(fmt.formatterClass, fmt.formatterClass, "getDateInstance", instanceParams, instanceTypes);
119 } catch (NoSuchMethodException e) {
120 oops = true;
121 } catch (IllegalAccessException e) {
122 oops = true;
123 } catch (InvocationTargetException e) {
124 oops = true;
125 } catch (NullPointerException e) {
126 oops = true;
127 }
128
129 if (oops) {
130 fmt.formatterClass = DateFormat.class;
131 fmt.formatter = DateFormat.getDateInstance(format);
132 }
133
134 return fmt;
135 }
136
137 /**
138 * Construct a DateFormatter with the default date format.
139 *
140 * @return a DateFormatter of the default format
141 * @see java.text.DateFormat#getDateInstance()
142 */
143 public static DateFormatter getDateInstance() {
144 return getDateInstance(DEFAULT);
145 }
146
147 /**
148 * Construct a simple DateFormatter with the given date format.
149 *
150 * @param format the date format
151 * @return a DateFormatter with the given date format
152 * @see java.text.DateFormat#getDateInstance(int)
153 */
154 public static DateFormatter getSimpleDateInstance(String format) {
155 DateFormatter fmt = new DateFormatter();
156 boolean oops = false;
157 try {
158 fmt.formatterClass = defaultSimpleDateFormat;
159 fmt.formatter = ReflectionUtil.construct(fmt.formatterClass, format);
160 } catch (NoSuchMethodException e) {
161 oops = true;
162 } catch (IllegalAccessException e) {
163 oops = true;
164 } catch (InvocationTargetException e) {
165 oops = true;
166 } catch (NullPointerException e) {
167 oops = true;
168 } catch (InstantiationException e) {
169 oops = true;
170 }
171
172 if (oops) {
173 fmt.formatterClass = SimpleDateFormat.class;
174 fmt.formatter = new SimpleDateFormat(format);
175 }
176
177 return fmt;
178 }
179
180 /**
181 * Set whether this DataFormatter should be lenient in parsing dates.
182 *
183 * @param lenient whether to be lenient or not
184 * @see java.text.DateFormat#setLenient(boolean)
185 */
186 public void setLenient(boolean lenient) {
187 try {
188 Class<?>[] lenientTypes = {
189 boolean.class
190 };
191 Object[] lenientParams = {
192 Boolean.valueOf(lenient)
193 };
194 ReflectionUtil.invoke(formatterClass, formatter, "setLenient", lenientParams, lenientTypes);
195 } catch (NoSuchMethodException e) {
196 assert false : e;
197 } catch (IllegalAccessException e) {
198 assert false : e;
199 } catch (InvocationTargetException e) {
200 assert false : e;
201 }
202 }
203
204 /**
205 * Formats a Date into a date/time string.
206 *
207 * @param date the time value to be formatted into a time string.
208 * @return the formatted time string.
209 * @see java.text.DateFormat#format(java.util.Date)
210 */
211 public String format(Date date) {
212 try {
213 return (String) ReflectionUtil.invoke(formatterClass, formatter, "format", date);
214 } catch (NoSuchMethodException e) {
215 assert false : e;
216 } catch (IllegalAccessException e) {
217 assert false : e;
218 } catch (InvocationTargetException e) {
219 assert false : e;
220 }
221 return "";
222 }
223
224 /**
225 * Convert text to a date.
226 *
227 * @param text the input to parse as a date
228 * @return the resultant date
229 * @see java.text.DateFormat#parse(java.lang.String)
230 */
231 public Date parse(String text) {
232 try {
233 return (Date) ReflectionUtil.invoke(formatterClass, formatter, "parse", text);
234 } catch (NoSuchMethodException e) {
235 assert false : e;
236 } catch (IllegalAccessException e) {
237 assert false : e;
238 } catch (InvocationTargetException e) {
239 assert false : e;
240 }
241 return new Date();
242 }
243 }
244