/* * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.geotools.xml.impl; import java.text.FieldPosition; import java.text.Format; import java.text.ParsePosition; import java.util.Calendar; import java.util.TimeZone; /** <p>An instance of {@link java.text.Format}, which may be used * to parse and format <code>xs:dateTime</code> values.</p> * * @author <a href="mailto:joe@ispsoft.de">Jochen Wiedmann</a> * * * @source $URL$ */ public class XsDateTimeFormat extends Format { final boolean parseDate; final boolean parseTime; XsDateTimeFormat(boolean pParseDate, boolean pParseTime) { parseDate = pParseDate; parseTime = pParseTime; } /** Creates a new instance. */ public XsDateTimeFormat() { this(true, true); } private int parseInt(String pString, int pOffset, StringBuffer pDigits) { int length = pString.length(); pDigits.setLength(0); while (pOffset < length) { char c = pString.charAt(pOffset); if (Character.isDigit(c)) { pDigits.append(c); ++pOffset; } else { break; } } return pOffset; } public Object parseObject(String pString, ParsePosition pParsePosition) { if (pString == null) { throw new NullPointerException("The String argument must not be null."); } if (pParsePosition == null) { throw new NullPointerException("The ParsePosition argument must not be null."); } int offset = pParsePosition.getIndex(); int length = pString.length(); boolean isMinus = false; StringBuffer digits = new StringBuffer(); int year, month, mday; if (parseDate) { // Sign if (offset < length) { char c = pString.charAt(offset); if (c == '+') { ++offset; } else if (c == '-') { ++offset; isMinus = true; } } offset = parseInt(pString, offset, digits); if (digits.length() < 4) { pParsePosition.setErrorIndex(offset); return null; } year = Integer.parseInt(digits.toString()); if (offset < length && pString.charAt(offset) == '-') { ++offset; } else { pParsePosition.setErrorIndex(offset); return null; } offset = parseInt(pString, offset, digits); if (digits.length() != 2) { pParsePosition.setErrorIndex(offset); return null; } month = Integer.parseInt(digits.toString()); if (offset < length && pString.charAt(offset) == '-') { ++offset; } else { pParsePosition.setErrorIndex(offset); return null; } offset = parseInt(pString, offset, digits); if (digits.length() != 2) { pParsePosition.setErrorIndex(offset); return null; } mday = Integer.parseInt(digits.toString()); if (parseTime) { if (offset < length && pString.charAt(offset) == 'T') { ++offset; } else { pParsePosition.setErrorIndex(offset); return null; } } } else { year = month = mday = 0; } int hour, minute, second, millis; if (parseTime) { offset = parseInt(pString, offset, digits); if (digits.length() != 2) { pParsePosition.setErrorIndex(offset); return null; } hour = Integer.parseInt(digits.toString()); if (offset < length && pString.charAt(offset) == ':') { ++offset; } else { pParsePosition.setErrorIndex(offset); return null; } offset = parseInt(pString, offset, digits); if (digits.length() != 2) { pParsePosition.setErrorIndex(offset); return null; } minute = Integer.parseInt(digits.toString()); if (offset < length && pString.charAt(offset) == ':') { ++offset; } else { pParsePosition.setErrorIndex(offset); return null; } offset = parseInt(pString, offset, digits); if (digits.length() != 2) { pParsePosition.setErrorIndex(offset); return null; } second = Integer.parseInt(digits.toString()); if (offset < length && pString.charAt(offset) == '.') { ++offset; offset = parseInt(pString, offset, digits); if (digits.length() > 0) { millis = Integer.parseInt(digits.toString()); if (millis > 999) { pParsePosition.setErrorIndex(offset); return null; } for (int i = digits.length(); i < 3; i++) { millis *= 10; } } else { millis = 0; } } else { millis = 0; } } else { hour = minute = second = millis = 0; } digits.setLength(0); digits.append("GMT"); if (offset < length) { char c = pString.charAt(offset); if (c == 'Z') { // Ignore UTC, it is the default ++offset; } else if (c == '+' || c == '-') { digits.append(c); ++offset; for (int i = 0; i < 5; i++) { if (offset >= length) { pParsePosition.setErrorIndex(offset); return null; } c = pString.charAt(offset); if ((i != 2 && Character.isDigit(c)) || (i == 2 && c == ':')) { digits.append(c); } else { pParsePosition.setErrorIndex(offset); return null; } ++offset; } } } Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(digits.toString())); cal.set(isMinus ? -year : year, parseDate ? month-1 : month, mday, hour, minute, second); cal.set(Calendar.MILLISECOND, millis); pParsePosition.setIndex(offset); return cal; } private void append(StringBuffer pBuffer, int pNum, int pMinLen) { String s = Integer.toString(pNum); for (int i = s.length(); i < pMinLen; i++) { pBuffer.append('0'); } pBuffer.append(s); } public StringBuffer format(Object pCalendar, StringBuffer pBuffer, FieldPosition pPos) { if (pCalendar == null) { throw new NullPointerException("The Calendar argument must not be null."); } if (pBuffer == null) { throw new NullPointerException("The StringBuffer argument must not be null."); } if (pPos == null) { throw new NullPointerException("The FieldPosition argument must not be null."); } Calendar cal = (Calendar) pCalendar; if (parseDate) { int year = cal.get(Calendar.YEAR); if (year < 0) { pBuffer.append('-'); year = -year; } append(pBuffer, year, 4); pBuffer.append('-'); append(pBuffer, cal.get(Calendar.MONTH)+1, 2); pBuffer.append('-'); append(pBuffer, cal.get(Calendar.DAY_OF_MONTH), 2); if (parseTime) { pBuffer.append('T'); } } if (parseTime) { append(pBuffer, cal.get(Calendar.HOUR_OF_DAY), 2); pBuffer.append(':'); append(pBuffer, cal.get(Calendar.MINUTE), 2); pBuffer.append(':'); append(pBuffer, cal.get(Calendar.SECOND), 2); int millis = cal.get(Calendar.MILLISECOND); if (millis > 0) { pBuffer.append('.'); append(pBuffer, millis, 3); } } TimeZone tz = cal.getTimeZone(); // JDK 1.4: int offset = tz.getOffset(cal.getTimeInMillis()); int offset = cal.get(Calendar.ZONE_OFFSET); if (tz.inDaylightTime(cal.getTime())) { offset += cal.get(Calendar.DST_OFFSET); } if (offset == 0) { pBuffer.append('Z'); } else { if (offset < 0) { pBuffer.append('-'); offset = -offset; } else { pBuffer.append('+'); } int minutes = offset / (60*1000); int hours = minutes / 60; minutes -= hours * 60; append(pBuffer, hours, 2); pBuffer.append(':'); append(pBuffer, minutes, 2); } return pBuffer; } }