src/net/fortuna/ical4j/model/CalendarDateFormatFactory.java

Tue, 10 Feb 2015 18:12:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 18:12:00 +0100
changeset 0
fb9019fb1bf7
permissions
-rw-r--r--

Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.

michael@0 1 /**
michael@0 2 * Copyright (c) 2012, Ben Fortuna
michael@0 3 * All rights reserved.
michael@0 4 *
michael@0 5 * Redistribution and use in source and binary forms, with or without
michael@0 6 * modification, are permitted provided that the following conditions
michael@0 7 * are met:
michael@0 8 *
michael@0 9 * o Redistributions of source code must retain the above copyright
michael@0 10 * notice, this list of conditions and the following disclaimer.
michael@0 11 *
michael@0 12 * o Redistributions in binary form must reproduce the above copyright
michael@0 13 * notice, this list of conditions and the following disclaimer in the
michael@0 14 * documentation and/or other materials provided with the distribution.
michael@0 15 *
michael@0 16 * o Neither the name of Ben Fortuna nor the names of any other contributors
michael@0 17 * may be used to endorse or promote products derived from this software
michael@0 18 * without specific prior written permission.
michael@0 19 *
michael@0 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
michael@0 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
michael@0 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
michael@0 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
michael@0 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
michael@0 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
michael@0 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
michael@0 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 31 */
michael@0 32 package net.fortuna.ical4j.model;
michael@0 33
michael@0 34 import java.text.FieldPosition;
michael@0 35 import java.text.NumberFormat;
michael@0 36 import java.text.ParsePosition;
michael@0 37 import java.text.SimpleDateFormat;
michael@0 38 import java.util.Date;
michael@0 39 import java.util.GregorianCalendar;
michael@0 40 import java.util.TimeZone;
michael@0 41
michael@0 42 import org.apache.commons.logging.Log;
michael@0 43 import org.apache.commons.logging.LogFactory;
michael@0 44
michael@0 45 /**
michael@0 46 * $Id$ [06-Apr-2004]
michael@0 47 *
michael@0 48 * Creates DateFormat objects optimized for common iCalendar date patterns.
michael@0 49 *
michael@0 50 * @author Dave Nault dnault@laszlosystems.com
michael@0 51 * @see #getInstance(String)
michael@0 52 */
michael@0 53 public final class CalendarDateFormatFactory {
michael@0 54 private static final Log LOG = LogFactory.getLog(CalendarDateFormatFactory.class);
michael@0 55
michael@0 56 private static final String DATETIME_PATTERN = "yyyyMMdd'T'HHmmss";
michael@0 57 private static final String DATETIME_UTC_PATTERN = "yyyyMMdd'T'HHmmss'Z'";
michael@0 58 private static final String DATE_PATTERN = "yyyyMMdd";
michael@0 59 private static final String TIME_PATTERN = "HHmmss";
michael@0 60 private static final String TIME_UTC_PATTERN = "HHmmss'Z'";
michael@0 61
michael@0 62 /**
michael@0 63 * Constructor made private to enforce static nature.
michael@0 64 */
michael@0 65 private CalendarDateFormatFactory() {
michael@0 66 }
michael@0 67
michael@0 68 /**
michael@0 69 * Returns DateFormat objects optimized for common iCalendar date patterns. The DateFormats are *not* thread safe.
michael@0 70 * Attempts to get or set the Calendar or NumberFormat of an optimized DateFormat will result in an
michael@0 71 * UnsupportedOperation exception being thrown.
michael@0 72 *
michael@0 73 * @param pattern
michael@0 74 * a SimpleDateFormat-compatible pattern
michael@0 75 * @return an optimized DateFormat instance if possible, otherwise a normal SimpleDateFormat instance
michael@0 76 */
michael@0 77 public static java.text.DateFormat getInstance(String pattern) {
michael@0 78 java.text.DateFormat instance = null;
michael@0 79
michael@0 80 // if (true) {
michael@0 81 // return new SimpleDateFormat(pattern);
michael@0 82 // }
michael@0 83
michael@0 84 if (pattern.equals(DATETIME_PATTERN) || pattern.equals(DATETIME_UTC_PATTERN)) {
michael@0 85 instance = new DateTimeFormat(pattern);
michael@0 86 }
michael@0 87 else if (pattern.equals(DATE_PATTERN)) {
michael@0 88 instance = new DateFormat(pattern);
michael@0 89 }
michael@0 90 else if (pattern.equals(TIME_PATTERN) || pattern.equals(TIME_UTC_PATTERN)) {
michael@0 91 instance = new TimeFormat(pattern);
michael@0 92 }
michael@0 93 else {
michael@0 94 if (LOG.isDebugEnabled()) {
michael@0 95 LOG.debug("unexpected date format pattern: " + pattern);
michael@0 96 }
michael@0 97
michael@0 98 instance = new SimpleDateFormat(pattern);
michael@0 99 }
michael@0 100 return instance;
michael@0 101 }
michael@0 102
michael@0 103 private abstract static class CalendarDateFormat extends java.text.DateFormat {
michael@0 104 /**
michael@0 105 *
michael@0 106 */
michael@0 107 private static final long serialVersionUID = -4191402739860280205L;
michael@0 108
michael@0 109 private static final java.util.TimeZone DEFAULT_TIME_ZONE = TimeZone.getDefault();
michael@0 110
michael@0 111 private final String pattern;
michael@0 112
michael@0 113 private boolean lenient = true;
michael@0 114
michael@0 115 private java.util.TimeZone timeZone = DEFAULT_TIME_ZONE;
michael@0 116
michael@0 117 public CalendarDateFormat(String pattern) {
michael@0 118 this.pattern = pattern;
michael@0 119 }
michael@0 120
michael@0 121 public java.util.TimeZone getTimeZone() {
michael@0 122 return this.timeZone;
michael@0 123 }
michael@0 124
michael@0 125 public void setTimeZone(java.util.TimeZone tz) {
michael@0 126 this.timeZone = tz;
michael@0 127 }
michael@0 128
michael@0 129 public void setLenient(boolean lenient) {
michael@0 130 this.lenient = lenient;
michael@0 131 }
michael@0 132
michael@0 133 public boolean isLenient() {
michael@0 134 return lenient;
michael@0 135 }
michael@0 136
michael@0 137 public java.util.Calendar getCalendar() {
michael@0 138 throw new UnsupportedOperationException();
michael@0 139 }
michael@0 140
michael@0 141 public void setCalendar(java.util.Calendar c) {
michael@0 142 throw new UnsupportedOperationException();
michael@0 143 }
michael@0 144
michael@0 145 public NumberFormat getNumberFormat() {
michael@0 146 throw new UnsupportedOperationException();
michael@0 147 }
michael@0 148
michael@0 149 public void setNumberFormat(NumberFormat n) {
michael@0 150 throw new UnsupportedOperationException();
michael@0 151 }
michael@0 152
michael@0 153 public Object clone() {
michael@0 154 // don't call super.clone()
michael@0 155 final CalendarDateFormat f = (CalendarDateFormat) CalendarDateFormatFactory.getInstance(pattern);
michael@0 156 f.setTimeZone(getTimeZone());
michael@0 157 f.setLenient(isLenient());
michael@0 158 return f;
michael@0 159 }
michael@0 160
michael@0 161 public boolean equals(Object o) {
michael@0 162 if (this == o) {
michael@0 163 return true;
michael@0 164 }
michael@0 165 if (o == null || getClass() != o.getClass()) {
michael@0 166 return false;
michael@0 167 }
michael@0 168 if (!super.equals(o)) {
michael@0 169 return false;
michael@0 170 }
michael@0 171
michael@0 172 final CalendarDateFormat that = (CalendarDateFormat) o;
michael@0 173
michael@0 174 if (lenient != that.lenient) {
michael@0 175 return false;
michael@0 176 }
michael@0 177 if (!pattern.equals(that.pattern)) {
michael@0 178 return false;
michael@0 179 }
michael@0 180 if (!timeZone.equals(that.timeZone)) {
michael@0 181 return false;
michael@0 182 }
michael@0 183
michael@0 184 return true;
michael@0 185 }
michael@0 186
michael@0 187 public int hashCode() {
michael@0 188 int result = super.hashCode();
michael@0 189 result = 31 * result + pattern.hashCode();
michael@0 190 result = 31 * result + (lenient ? 1 : 0);
michael@0 191 result = 31 * result + timeZone.hashCode();
michael@0 192 return result;
michael@0 193 }
michael@0 194 }
michael@0 195
michael@0 196 /**
michael@0 197 * A custom date-time formatter.
michael@0 198 * Parses and formats these patterns:
michael@0 199 *
michael@0 200 * <pre>
michael@0 201 * yyyyMMdd'T'HHmmss
michael@0 202 * yyyyMMdd'T'HHmmss'Z'
michael@0 203 * </pre>
michael@0 204 */
michael@0 205 private static class DateTimeFormat extends CalendarDateFormat {
michael@0 206
michael@0 207 /**
michael@0 208 *
michael@0 209 */
michael@0 210 private static final long serialVersionUID = 3005824302269636122L;
michael@0 211
michael@0 212 final boolean patternEndsWithZ;
michael@0 213
michael@0 214 public DateTimeFormat(String pattern) {
michael@0 215 super(pattern);
michael@0 216 patternEndsWithZ = pattern.endsWith("'Z'");
michael@0 217 }
michael@0 218
michael@0 219 public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
michael@0 220 final java.util.Calendar cal = new GregorianCalendar(getTimeZone());
michael@0 221 cal.setTimeInMillis(date.getTime());
michael@0 222
michael@0 223 appendPadded(toAppendTo, cal.get(GregorianCalendar.YEAR), 4);
michael@0 224 appendPadded(toAppendTo, cal.get(GregorianCalendar.MONTH) + 1, 2);
michael@0 225 appendPadded(toAppendTo, cal.get(GregorianCalendar.DAY_OF_MONTH), 2);
michael@0 226 toAppendTo.append("T");
michael@0 227
michael@0 228 appendPadded(toAppendTo, cal.get(GregorianCalendar.HOUR_OF_DAY), 2);
michael@0 229 appendPadded(toAppendTo, cal.get(GregorianCalendar.MINUTE), 2);
michael@0 230 appendPadded(toAppendTo, cal.get(GregorianCalendar.SECOND), 2);
michael@0 231
michael@0 232 if (patternEndsWithZ) {
michael@0 233 toAppendTo.append("Z");
michael@0 234 }
michael@0 235
michael@0 236 return toAppendTo;
michael@0 237 }
michael@0 238
michael@0 239 public Date parse(String source, ParsePosition pos) {
michael@0 240 // if lenient ignore superfluous input..
michael@0 241 if (patternEndsWithZ) {
michael@0 242 if (source.length() > DATETIME_UTC_PATTERN.length() && !isLenient()) {
michael@0 243 pos.setErrorIndex(DATETIME_UTC_PATTERN.length());
michael@0 244 return null;
michael@0 245 }
michael@0 246 } else if (source.length() > DATETIME_PATTERN.length() && !isLenient()) {
michael@0 247 pos.setErrorIndex(DATETIME_PATTERN.length());
michael@0 248 return null;
michael@0 249 }
michael@0 250
michael@0 251 try {
michael@0 252 if (source.charAt(8) != 'T') {
michael@0 253 pos.setErrorIndex(8);
michael@0 254 return null;
michael@0 255 }
michael@0 256 if (patternEndsWithZ && source.charAt(15) != 'Z') {
michael@0 257 pos.setErrorIndex(15);
michael@0 258 return null;
michael@0 259 }
michael@0 260
michael@0 261 final int year = Integer.parseInt(source.substring(0, 4));
michael@0 262 final int month = Integer.parseInt(source.substring(4, 6)) - 1;
michael@0 263 final int day = Integer.parseInt(source.substring(6, 8));
michael@0 264 final int hour = Integer.parseInt(source.substring(9, 11));
michael@0 265 final int minute = Integer.parseInt(source.substring(11, 13));
michael@0 266 final int second = Integer.parseInt(source.substring(13, 15));
michael@0 267
michael@0 268 final Date d = makeCalendar(isLenient(), getTimeZone(),
michael@0 269 year, month, day, hour, minute, second).getTime();
michael@0 270 pos.setIndex(15);
michael@0 271 return d;
michael@0 272 } catch (Exception e) {
michael@0 273 return null;
michael@0 274 }
michael@0 275 }
michael@0 276 }
michael@0 277
michael@0 278 /**
michael@0 279 * Custom date formatter.
michael@0 280 * Parses and formats this pattern:
michael@0 281 *
michael@0 282 * <pre>
michael@0 283 * yyyyMMdd
michael@0 284 * </pre>
michael@0 285 */
michael@0 286 private static class DateFormat extends CalendarDateFormat {
michael@0 287
michael@0 288 /**
michael@0 289 *
michael@0 290 */
michael@0 291 private static final long serialVersionUID = -7626077667268431779L;
michael@0 292
michael@0 293 public DateFormat(String pattern) {
michael@0 294 super(pattern);
michael@0 295 }
michael@0 296
michael@0 297 public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
michael@0 298 final java.util.Calendar cal = java.util.Calendar.getInstance(getTimeZone());
michael@0 299 cal.setTimeInMillis(date.getTime());
michael@0 300
michael@0 301 appendPadded(toAppendTo, cal.get(GregorianCalendar.YEAR), 4);
michael@0 302 appendPadded(toAppendTo, cal.get(GregorianCalendar.MONTH) + 1, 2);
michael@0 303 appendPadded(toAppendTo, cal.get(GregorianCalendar.DAY_OF_MONTH), 2);
michael@0 304
michael@0 305 return toAppendTo;
michael@0 306 }
michael@0 307
michael@0 308 public Date parse(String source, ParsePosition pos) {
michael@0 309 // if lenient ignore superfluous input..
michael@0 310 if (source.length() > DATE_PATTERN.length() && !isLenient()) {
michael@0 311 pos.setErrorIndex(DATE_PATTERN.length());
michael@0 312 return null;
michael@0 313 }
michael@0 314
michael@0 315 try {
michael@0 316 final int year = Integer.parseInt(source.substring(0, 4));
michael@0 317 final int month = Integer.parseInt(source.substring(4, 6)) - 1;
michael@0 318 final int day = Integer.parseInt(source.substring(6, 8));
michael@0 319
michael@0 320 final Date d = makeCalendar(isLenient(), getTimeZone(), year, month, day).getTime();
michael@0 321 pos.setIndex(8);
michael@0 322 return d;
michael@0 323 } catch (Exception e) {
michael@0 324 return null;
michael@0 325 }
michael@0 326 }
michael@0 327 }
michael@0 328
michael@0 329 /**
michael@0 330 * Custom time formatter.
michael@0 331 * Parses and formats these patterns:
michael@0 332 *
michael@0 333 * <pre>
michael@0 334 * HHmmss
michael@0 335 * HHmmss'Z'
michael@0 336 * </pre>
michael@0 337 */
michael@0 338 private static class TimeFormat extends CalendarDateFormat {
michael@0 339
michael@0 340 /**
michael@0 341 *
michael@0 342 */
michael@0 343 private static final long serialVersionUID = -1367114409994225425L;
michael@0 344
michael@0 345 final boolean patternEndsWithZ;
michael@0 346
michael@0 347 public TimeFormat(String pattern) {
michael@0 348 super(pattern);
michael@0 349 patternEndsWithZ = pattern.endsWith("'Z'");
michael@0 350 }
michael@0 351
michael@0 352 public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
michael@0 353 final java.util.Calendar cal = new GregorianCalendar(getTimeZone());
michael@0 354 cal.setTimeInMillis(date.getTime());
michael@0 355
michael@0 356 appendPadded(toAppendTo, cal.get(GregorianCalendar.HOUR_OF_DAY), 2);
michael@0 357 appendPadded(toAppendTo, cal.get(GregorianCalendar.MINUTE), 2);
michael@0 358 appendPadded(toAppendTo, cal.get(GregorianCalendar.SECOND), 2);
michael@0 359
michael@0 360 if (patternEndsWithZ) {
michael@0 361 toAppendTo.append("Z");
michael@0 362 }
michael@0 363
michael@0 364 return toAppendTo;
michael@0 365 }
michael@0 366
michael@0 367 public Date parse(String source, ParsePosition pos) {
michael@0 368 // if lenient ignore superfluous input..
michael@0 369 if (patternEndsWithZ) {
michael@0 370 if (source.length() > TIME_UTC_PATTERN.length() && !isLenient()) {
michael@0 371 pos.setErrorIndex(TIME_UTC_PATTERN.length());
michael@0 372 return null;
michael@0 373 }
michael@0 374 } else if (source.length() > TIME_PATTERN.length() && !isLenient()) {
michael@0 375 pos.setErrorIndex(TIME_PATTERN.length());
michael@0 376 return null;
michael@0 377 }
michael@0 378
michael@0 379 try {
michael@0 380 if (patternEndsWithZ && source.charAt(6) != 'Z') {
michael@0 381 pos.setErrorIndex(6);
michael@0 382 return null;
michael@0 383 }
michael@0 384
michael@0 385 final int hour = Integer.parseInt(source.substring(0, 2));
michael@0 386 final int minute = Integer.parseInt(source.substring(2, 4));
michael@0 387 final int second = Integer.parseInt(source.substring(4, 6));
michael@0 388
michael@0 389 final Date d = makeCalendar(isLenient(), getTimeZone(), 1970, 0, 1, hour, minute, second).getTime();
michael@0 390 pos.setIndex(6);
michael@0 391 return d;
michael@0 392 } catch (Exception e) {
michael@0 393 return null;
michael@0 394 }
michael@0 395 }
michael@0 396 }
michael@0 397
michael@0 398 private static java.util.Calendar makeCalendar(boolean lenient, java.util.TimeZone timeZone, int year,
michael@0 399 int zeroBasedMonth, int day, int hour, int minutes, int seconds) {
michael@0 400 final java.util.Calendar cal = new GregorianCalendar(timeZone);
michael@0 401 cal.setLenient(lenient);
michael@0 402 cal.set(year, zeroBasedMonth, day, hour, minutes, seconds);
michael@0 403 cal.set(java.util.Calendar.MILLISECOND, 0);
michael@0 404 return cal;
michael@0 405 }
michael@0 406
michael@0 407 private static java.util.Calendar makeCalendar(boolean lenient, TimeZone timeZone, int year, int month, int day) {
michael@0 408 return makeCalendar(lenient, timeZone, year, month, day, 0, 0, 0);
michael@0 409 }
michael@0 410
michael@0 411 private static void appendPadded(StringBuffer toAppendTo, int value, int fieldWidth) {
michael@0 412 final String s = Integer.toString(value);
michael@0 413 final int max = fieldWidth - s.length();
michael@0 414 for (int i = 0; i < max; i++) {
michael@0 415 toAppendTo.append("0");
michael@0 416 }
michael@0 417 toAppendTo.append(s);
michael@0 418 }
michael@0 419
michael@0 420 }

mercurial