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

at.spardat.enterprise.fmt.ADateFmtMediumSmart Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
/*******************************************************************************
 * Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     s IT Solutions AT Spardat GmbH - initial API and implementation
 *******************************************************************************/

// @(#) $Id: ADateFmtMediumSmart.java 8163 2011-07-12 15:50:39Z laslovd $
package at.spardat.enterprise.fmt;

import java.util.*;

import at.spardat.enterprise.util.DateUtil;
import at.spardat.enterprise.util.NumberUtil;

/**
 * This class is a high speed implementation for parsing and formatting
 * dates, like the MEDIUM format of DateFormat. A very restricted set
 * of patterns is allowed. A pattern is a sequence of the following:
 * 
 * d1 ... represents a day component without leading zero
 * d2 ... represents a two digits day component
 * m1 ... represents a month component witout leading zero
 * m2 ... represents a two digits month component
 * y2 ... represents a two digit year component
 * y4 ... represents a four digit year component
 * 
* Other characters must be used to delimit the components, as long as they * do not start with d, m or y. A typical pattern for the austrian local * may be "d2.m2.y4". The pattern must consist of exactly one d, one m and * one y component. The components must be separated by delimiters. Therefore, * a pattern "d2m2y4" is illegal.

*/ public class ADateFmtMediumSmart extends ADateFmt implements Cloneable { // the pattern provided at construction time private String pattern_; // the position of the day component in the pattern private int dRank_ = -1; // the position of the month component in the pattern private int mRank_ = -1; // the position of the year component in the pattern private int yRank_ = -1; // used for completing incomplete year specifications protected int twoDigitYearOffset_ = -80; // keys are Strings denoting Locales, values are ADateFmtMediumSmart-objects private static final HashMap fmts_ = new HashMap(); private static final ADateFmtMediumSmart defaultFmt_ = new ADateFmtMediumSmart("d2.m2.y4", 0); // initialize the separators_ HashMap static { fmts_.put ("cs", new ADateFmtMediumSmart("d2.m1.y4", 0)); fmts_.put ("cs_CZ", new ADateFmtMediumSmart("d2.m1.y4", 0)); fmts_.put ("de", new ADateFmtMediumSmart("d2.m2.y4", 0)); fmts_.put ("de_AT", new ADateFmtMediumSmart("d2.m2.y4", 0)); fmts_.put ("en", new ADateFmtMediumSmart("d2/m2/y4", 0)); fmts_.put ("en_GB", new ADateFmtMediumSmart("d2/m2/y4", 0)); fmts_.put ("en_US", new ADateFmtMediumSmart("m2/d2/y4", 0)); fmts_.put ("hr", new ADateFmtMediumSmart("y4.m2.d2", 0)); fmts_.put ("hr_HR", new ADateFmtMediumSmart("y4.m2.d2", 0)); fmts_.put ("hu", new ADateFmtMediumSmart("y4.m2.d2.", 0)); fmts_.put ("hu_HU", new ADateFmtMediumSmart("y4.m2.d2.", 0)); fmts_.put ("sk", new ADateFmtMediumSmart("d2.m1.y4", 0)); fmts_.put ("sk_SK", new ADateFmtMediumSmart("d2.m1.y4", 0)); } /** * Returns a MEDIUM format object for a particular Locale. * * @param l the Locale * @param style may be MANDATORY * @return the non null format object. */ static ADateFmtMediumSmart getInstance (Locale l, int style) { /** * Look up the HashTable to get a template-object */ String locStr = l.toString(); ADateFmtMediumSmart result = (ADateFmtMediumSmart) fmts_.get(locStr); if (result == null) { int iUnder = locStr.lastIndexOf('_'); if (iUnder != -1) { locStr = locStr.substring(0, iUnder); result = (ADateFmtMediumSmart) fmts_.get(locStr); if (result == null) { iUnder = locStr.lastIndexOf('_'); if (iUnder != -1) { locStr = locStr.substring(0, iUnder); result = (ADateFmtMediumSmart) fmts_.get(locStr); } } } } if (result == null) result = defaultFmt_; /** * Clone the found template object */ result = (ADateFmtMediumSmart)result.clone(); /** * And set the right style */ result.style_ = style; return result; } /** * Constructs using a pattern as defined in the class header. * * @param pattern the pattern used * @param style may be MANDATORY * @exception RuntimeException on wrong patterns. */ protected ADateFmtMediumSmart (String pattern, int style) { style_ = style; setPattern (pattern); } /** * Sets the pattern as defined in the class header. * * @param pattern the pattern to set * @exception RuntimeException on wrong patterns */ public void setPattern (String pattern) { // analyse the pattern pattern_ = pattern; dRank_ = -1; mRank_ = -1; yRank_ = -1; int rank = 0; for (int i=0, len=pattern.length(); i=0; i--) if (pattern_.charAt(i) == aChar) return true; return false; } /** * @see at.spardat.enterprise.fmt.IFmt#isOneWay() */ public boolean isOneWay() { return false; } /** * @see at.spardat.enterprise.fmt.IFmt#maxLenOfExternal() */ public int maxLenOfExternal() { return pattern_.length() + 2; // adjust for 4 digit years } /** * The parse method accepts the following inputs: *

    *
  • '0' ... zero stands for today *
  • '[-+] number' ... a signed number stands for today plus/minus the provided number of days. *
  • 'number' ... a number on its own represents the day component of the current month in the * current year. *
  • 'number separators number' ... if only to components are given, they are taken to be * month and day. The current year is added. *
  • 'number separators number separators number' ... the three numbers are considered to be the * day, month and year components following the order defined in the pattern. *
* The separators between the numbers need not match the separators provided in the patterns.

* * Some rules apply to parsing the year component. If this componenent consists of at least 3 digits, * it is taken as year itself, i.e., 002 means the year 0002. If the year component consists of 2 or 1 digit(s), * it is thought of a year without century and a century using a sliding window approach is set down. * The century is fixed in a way that the resulting year lies in the interval * (currentYear+twoDigitYearOffset_, currentYear+twoDigitYearOffset_+100] * * @see at.spardat.enterprise.fmt.IFmt#parse(String) */ public String parse (String external) throws AParseException { String internal = parse2 (external); checkMandatory (internal); checkDateRange (internal); return internal; } /** * Does the stuff described in method parse, without the mandatory-check. */ private String parse2 (String external) throws AParseException { if (external == null) return ""; // check for spaces only external = external.trim(); if (external.length() == 0) return ""; // needed very often for parsing in that what follows char ch; int index = 0; int extLen = external.length(); // collects the result DateUtil.DMY result = new DateUtil.DMY(); // special case: the string consists just of a number with an optional sign char sign = 0; int number = 0; int numDigits = 0; ch = external.charAt(index); if (ch == '-') { sign = '-'; index++; } if (ch == '+') { sign = '+'; index++; } while (index < extLen) { ch = external.charAt(index); if (NumberUtil.isDigit(ch)) { number = number*10 + ch-'0'; index++; numDigits++; } else break; } // and the part after the number until the end is not numeric (which is ignored) while (index < extLen) { ch = external.charAt(index); if (NumberUtil.isDigit(ch)) break; else index++; } // ### // did we parse until the end, i.e., we really have just one component. // This is considerd to be a day component if (index == extLen && numDigits >= 1) { if (sign == '-') number *= -1; // a single component is considered to be a day component DateUtil.DMY today = DateUtil.getDMY(new GregorianCalendar()); result.d_ = today.d_; result.m_ = today.m_; result.y_ = today.y_; if (number == 0) { // a zero day component means today } else { // a non zero day component without sign is the day and possible a month and a year if (sign == 0) { if ( number > 1000000 ) { // e.g. 18052011 -> 18.05.2011, result.y_ = number % 10000; number /= 10000; } else if ( number > 10000 ) { // e.g. 180511 -> 18.05.2011 result.y_ = number % 100 + 2000; number /= 100; } if ( number > 100 ) { // e.g. 1805 -> 18.05.2011 result.m_ = number % 100; number /= 100; } result.d_ = number; } else { // a signed component means to roll the day forward or backwards GregorianCalendar cal = new GregorianCalendar(); cal.add (Calendar.DATE, number); result = DateUtil.getDMY (cal); } } } else { // the hard part: we split external up into components int [] components = new int[3]; // the numeric value of the components short [] lengths = new short[3]; int numC = 0; index = 0; // discover consecutive numeric strings while (index < extLen) { ch = external.charAt(index); if (!NumberUtil.isDigit(ch)) { index++; continue; } // here is a sequence of digits while (index < extLen) { ch = external.charAt(index); if (!NumberUtil.isDigit(ch)) break; if (numC >= 3) generalDateError(); components[numC] = components[numC] * 10 + ch - '0'; lengths[numC]++; index++; } numC++; } // next, have a look at the components if (numC <= 1) generalDateError(); else if (numC == 2) { // two components are taken as day and month DateUtil.DMY today = DateUtil.getDMY(new GregorianCalendar()); result.y_ = today.y_; if (dRank_ < mRank_) { result.d_ = components[0]; result.m_ = components[1]; } else { result.d_ = components[1]; result.m_ = components[0]; } } else { // three components result.d_ = components[dRank_]; result.m_ = components[mRank_]; result.y_ = components[yRank_]; // correct one or two digit years if (lengths[yRank_] <= 2) { // the year we have is just the year within a decade. DateUtil.DMY today = DateUtil.getDMY(new GregorianCalendar()); int slidingDecadeBegin = today.y_ + twoDigitYearOffset_; int slidingDecadeEnd = slidingDecadeBegin + 100; if (result.y_ + slidingDecadeBegin/100*100 <= slidingDecadeBegin) result.y_ = result.y_ + slidingDecadeEnd/100*100; else result.y_ = result.y_ + slidingDecadeBegin/100*100; } } } // check if result is valid if (!DateUtil.isValid(result)) throw new FmtParseException ("ADateRange"); return DateUtil.DMY2Internal (result); } // convenience method to throw a FmtParseException private void generalDateError () { throw new FmtParseException ("ADateNotValid", format ("20031130")); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy