/* * Copyright 2006 Edward Kuns * * 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. * * $Id: $ */ package org.exolab.castor.types; import java.text.ParseException; import java.util.Calendar; import java.util.GregorianCalendar; /** * Describe an XML schema DateTime. * <p>The format is defined by W3C XML Schema Recommendation and ISO8601 * i.e <tt>(-)CCYY-MM-DD'T'HH:MM:SS(.SSSSS)(Z|(+|-)hh:mm)</tt> * @author <a href="mailto:edward.kuns@aspect.com">Edward Kuns</a> * @version $Revision: 0000 $ */ public class DateTime extends DateTimeBase { /** SerialVersionUID. */ private static final long serialVersionUID = 6278590966410879734L; /** Complaint string. */ private static final String BAD_DATE = "Bad DateTime format: "; /** * Default constructor. */ public DateTime() { // Nothing for the default } /** * Constructs a XML Schema DateTime instance given all the values of the * different date and time (but not time zone) fields. * <p> * By default a DateTime is not UTC, and is local. To set a timezone, you * need to separately call {@link #setZone(short, short)}. * * @param values * an array of shorts that represent the different fields of * Time. * @see #setValues */ public DateTime(short[] values) { setValues(values); } /** * Creates a new XML Schema DateTime instance from a long that represents a * Date. No time zone information is set. * <p> * By default a DateTime is not UTC, and is local. To set a timezone, you * need to separately call {@link #setZone(short, short)}. * * @param dateAsLong * java.util.Date represented as a long. */ public DateTime(long dateAsLong) { this(new java.util.Date(dateAsLong)); } /** * Creates a new XML Schema DateTime instance from a java.util.Date. No time * zone information is set. * <p> * By default a DateTime is not UTC, and is local. To set a timezone, you * need to separately call {@link #setZone(short, short)}. * * @param dateRef * a java.util.Date to convert. */ public DateTime(java.util.Date dateRef) { GregorianCalendar tempCalendar = new GregorianCalendar(); tempCalendar.setTime(dateRef); setCentury((short) (tempCalendar.get(Calendar.YEAR) / 100)); setYear((short) (tempCalendar.get(Calendar.YEAR) % 100)); // In GregorianCalendar, 0 <= Month <= 11; January == 0 setMonth((short) (tempCalendar.get(Calendar.MONTH) + 1)); setDay((short) tempCalendar.get(Calendar.DAY_OF_MONTH)); setHour((short) tempCalendar.get(Calendar.HOUR_OF_DAY)); setMinute((short) tempCalendar.get(Calendar.MINUTE)); setSecond((short) tempCalendar.get(Calendar.SECOND), (short) tempCalendar.get(Calendar.MILLISECOND)); } /** * Constructs a DateTime from a String. The String is expected to be in W3C * Schema DateTime format. * * @param date * the string representing the date * @throws java.text.ParseException * if we are passed an illegal value */ public DateTime(String date) throws java.text.ParseException { parseDateTimeInternal(date, this); } /** * Sets all the fields to the values provided in an Array. The Array must * be at least eight entries long. Extra entries are ignored. The order of * entries in the array is as follows: * <ul> * <li>century</li> * <li>year</li> * <li>month</li> * <li>day</li> * <li>hour</li> * <li>minute</li> * <li>second</li> * <li>millisecond</li> * </ul> * If a Time Zone is to be specified, it has to be set separately by using * {@link DateTimeBase#setZone(short, short) setZone}. A time zone * previously set will not be cleared. * * @param values * An array of shorts containing the values for the DateTime */ public void setValues(short[] values) { if (values.length != 8) { throw new IllegalArgumentException("DateTime#setValues: Array length " + values.length + " != 8"); } this.setCentury(values[0]); this.setYear(values[1]); this.setMonth(values[2]); this.setDay(values[3]); this.setHour(values[4]); this.setMinute(values[5]); this.setSecond(values[6], values[7]); } /** * Returns an array of shorts with all the fields that describe this * DateTime type. The order of entries in the array is as follows: * <ul> * <li>century</li> * <li>year</li> * <li>month</li> * <li>day</li> * <li>hour</li> * <li>minute</li> * <li>second</li> * <li>millisecond</li> * </ul> * Note:the time zone is not included. * * @return an array of short with all the fields that describe this Date * type. */ public short[] getValues() { short[] result = new short[8]; result[0] = this.getCentury(); result[1] = this.getYear(); result[2] = this.getMonth(); result[3] = this.getDay(); result[4] = this.getHour(); result[5] = this.getMinute(); result[6] = this.getSeconds(); result[7] = this.getMilli(); return result; } //getValues /** * Converts this DateTime into a local java.util.Date. * @return a local java.util.Date representing this DateTime. */ public java.util.Date toDate() { Calendar calendar = new GregorianCalendar(getCentury()*100+getYear(), getMonth()-1, getDay(), getHour(), getMinute(), getSeconds()); calendar.set(Calendar.MILLISECOND, getMilli()); setDateFormatTimeZone(calendar); return calendar.getTime(); } //toDate() /** * Converts this DateTime into a long value representing a java.util.Date. * @return This DateTime instance as a long value representing a java.util.Date. */ public long toLong() { return toDate().getTime(); } /** * Converts this DateTime to a string. The format is defined by W3C XML * Schema recommendation and ISO8601: (+|-)CCYY-MM-DDTHH:MM:SS.SSS(+/-)HH:SS * * @return a string representing this Date */ public String toString() { StringBuffer result = new StringBuffer(); appendDateString(result); result.append('T'); appendTimeString(result); appendTimeZoneString(result); return result.toString(); } //toString /** * Parses a String into a new DateTime instance. * * @param str * the string to parse * @return a new DateTime instance with the value of the parsed string. * @throws ParseException * If the string to parse does not follow the right format */ public static DateTime parse(String str) throws ParseException { return parseDateTime(str); } /** * Parses a String into a new DateTime instance. * * @param str * the string to parse * @return a new DateTime instance with the value of the parsed string. * @throws ParseException * If the string to parse does not follow the right format */ public static DateTime parseDateTime(String str) throws ParseException { return parseDateTimeInternal(str, new DateTime()); } /** * Parses a String into the provided DateTime instance (or a new DateTime * instance if the one provided is null) and assigns that value to the * DateTime instance given. * * @param str * the string to parse * @param result * the DateTime instance to assign to the parsed value of the * String. If null is passed, a new DateTime instance is created * to be returned. * @return the DateTime instance with the value of the parsed string. * @throws ParseException * If the string to parse does not follow the right format */ private static DateTime parseDateTimeInternal(String str, DateTime result) throws ParseException { if (str == null) { throw new IllegalArgumentException("The string to be parsed must not be null."); } if (result == null) { result = new DateTime(); } char[] chars = str.toCharArray(); if (chars.length < 19) { throw new ParseException(BAD_DATE + str + "\nDateTime is not long enough", 0); } int idx = 0; idx = parseYear(str, result, chars, idx, BAD_DATE); idx = parseMonth(str, result, chars, idx, BAD_DATE); idx = parseDay(str, result, chars, idx, BAD_DATE); if (chars[idx] != 'T') { throw new ParseException(BAD_DATE + str + "\n 'T' " + DateTimeBase.WRONGLY_PLACED, idx); } idx++; idx = parseTime(str, result, chars, idx, BAD_DATE); parseTimeZone(str, result, chars, idx, BAD_DATE); return result; } //parse }