001: /******************************************************************
002: * File: XSDDateTime.java
003: * Created by: Dave Reynolds
004: * Created on: 17-Dec-2002
005: *
006: * (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: XSDDateTime.java,v 1.25 2008/01/02 12:10:49 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.datatypes.xsd;
010:
011: import java.util.*;
012:
013: import com.hp.hpl.jena.datatypes.xsd.impl.XSDAbstractDateTimeType;
014:
015: /**
016: * Represent an XSD date/time value. Rather than have a separate type for each
017: * legal date/time value combination this is a combination type than does runtime
018: * checks whether a given field is legal in the current circumstances.
019: *
020: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
021: * @version $Revision: 1.25 $ on $Date: 2008/01/02 12:10:49 $
022: */
023: public class XSDDateTime extends AbstractDateTime {
024: /** Mask to indicate whether year is present */
025: public static final short YEAR_MASK = 0x1;
026:
027: /** Mask to indicate whether month is present */
028: public static final short MONTH_MASK = 0x2;
029:
030: /** Mask to indicate whether day is present */
031: public static final short DAY_MASK = 0x4;
032:
033: /** Mask to indicate whether time is present */
034: public static final short TIME_MASK = 0x8;
035:
036: /** Mask to indicate all date/time are present */
037: public static final short FULL_MASK = 0xf;
038:
039: /** table mapping xs type name to mask of legal values */
040: public static final HashMap maskMap = new HashMap();
041:
042: /** Set of legal fields for the particular date/time instance */
043: protected short mask;
044:
045: /**
046: * Constructor - should only be used by the internals but public scope because
047: * the internals spread across multiple packages.
048: *
049: * @param value the date/time value returned by the parsing
050: * @param mask bitmask defining which components are valid in this instance
051: * (e.g. dates don't have valid time fields).
052: */
053: public XSDDateTime(Object value, int mask) {
054: super (value);
055: this .mask = (short) mask;
056: }
057:
058: /**
059: * Constructor - create a full DateTime object from a java calendar instance.
060: *
061: * @param date java calendar instance
062: */
063: public XSDDateTime(Calendar date) {
064: super (convertCalendar(date));
065: this .mask = FULL_MASK;
066: }
067:
068: /**
069: * Return the most specific xsd type which can represent
070: * this date/time
071: */
072: public XSDDatatype getNarrowedDatatype() {
073: switch (mask) {
074: case TIME_MASK:
075: return XSDDatatype.XSDtime;
076: case MONTH_MASK:
077: return XSDDatatype.XSDgMonth;
078: case DAY_MASK:
079: return XSDDatatype.XSDgDay;
080: case YEAR_MASK:
081: return XSDDatatype.XSDgYear;
082: case MONTH_MASK | DAY_MASK:
083: return XSDDatatype.XSDgMonthDay;
084: case MONTH_MASK | YEAR_MASK:
085: return XSDDatatype.XSDgYearMonth;
086: case MONTH_MASK | YEAR_MASK | DAY_MASK:
087: return XSDDatatype.XSDdate;
088: default:
089: return XSDDatatype.XSDdateTime;
090: }
091: }
092:
093: /**
094: * Set the mask for this date/time to be that appropriate
095: * for the given XSD subtype. If the type is a subtype of XSDdateTime the
096: * mask will be narrowed appropriately, other types will be silently ignored.
097: */
098: public void narrowType(XSDDatatype dt) {
099: if (dt.equals(XSDDatatype.XSDtime)) {
100: mask = TIME_MASK;
101: } else if (dt.equals(XSDDatatype.XSDgMonth)) {
102: mask = MONTH_MASK;
103: } else if (dt.equals(XSDDatatype.XSDgDay)) {
104: mask = DAY_MASK;
105: } else if (dt.equals(XSDDatatype.XSDgYear)) {
106: mask = YEAR_MASK;
107: } else if (dt.equals(XSDDatatype.XSDgMonthDay)) {
108: mask = MONTH_MASK | DAY_MASK;
109: } else if (dt.equals(XSDDatatype.XSDgYearMonth)) {
110: mask = YEAR_MASK | MONTH_MASK;
111: } else if (dt.equals(XSDDatatype.XSDdate)) {
112: mask = MONTH_MASK | YEAR_MASK | DAY_MASK;
113: }
114: }
115:
116: /**
117: * Convert a java calendar object to a new int[] in the format used by XSDAbstractDateTime
118: */
119: private static int[] convertCalendar(Calendar date) {
120: int[] data = new int[TOTAL_SIZE];
121: int offset = date.get(Calendar.ZONE_OFFSET)
122: + date.get(Calendar.DST_OFFSET);
123: // Thanks to Greg Shueler for DST patch
124: Calendar cal = date;
125: if (offset != 0) {
126: cal = (Calendar) date.clone();
127: cal.add(Calendar.MILLISECOND, -offset);
128: }
129: data[AbstractDateTime.CY] = cal.get(Calendar.YEAR);
130: data[AbstractDateTime.M] = cal.get(Calendar.MONTH) + 1;
131: data[AbstractDateTime.D] = cal.get(Calendar.DAY_OF_MONTH);
132: data[AbstractDateTime.h] = cal.get(Calendar.HOUR_OF_DAY);
133: data[AbstractDateTime.m] = cal.get(Calendar.MINUTE);
134: data[AbstractDateTime.s] = cal.get(Calendar.SECOND);
135: data[AbstractDateTime.ms] = cal.get(Calendar.MILLISECOND);
136: data[AbstractDateTime.msscale] = 3;
137: data[AbstractDateTime.utc] = 'Z';
138: return data;
139: }
140:
141: /**
142: * Return the date time as a java Calendar object.
143: * If the timezone has been specified then the object is normalized to GMT.
144: * If the zone has not been specified then we use the default timezone.
145: *
146: * @throws IllegalDateTimeFieldException if this is not a full date + time
147: */
148: public Calendar asCalendar() throws IllegalDateTimeFieldException {
149: TimeZone tz = data[utc] == 'Z' ? TimeZone.getTimeZone("GMT")
150: : TimeZone.getDefault();
151: Calendar calendar = new GregorianCalendar(tz);
152: calendar.set(data[CY], data[M] - 1, data[D], data[h], data[m],
153: data[s]);
154: calendar.set(Calendar.MILLISECOND, (int) Math
155: .round(1000.0 * fractionalSeconds));
156: // was this to work around problems with some Linux JDKs
157: // calendar.set(Calendar.MILLISECOND, 0);
158: return calendar;
159: }
160:
161: /**
162: * Return the number of years in the dateTime.
163: * @throws IllegalDateTimeFieldException if there is no legal year component
164: */
165: public int getYears() throws IllegalDateTimeFieldException {
166: if ((mask & YEAR_MASK) == 0)
167: throw new IllegalDateTimeFieldException(
168: "Year not available");
169: return data[CY];
170: }
171:
172: /**
173: * Return the month in the dateTime, this is in ISO8601 format so january = 1
174: * @throws IllegalDateTimeFieldException if there is no legal month component
175: */
176: public int getMonths() throws IllegalDateTimeFieldException {
177: if ((mask & MONTH_MASK) == 0)
178: throw new IllegalDateTimeFieldException(
179: "Month not available");
180: return data[M];
181: }
182:
183: /**
184: * Return the number of years in the dateTime
185: * @throws IllegalDateTimeFieldException if there is no legal day component
186: */
187: public int getDays() throws IllegalDateTimeFieldException {
188: if ((mask & DAY_MASK) == 0)
189: throw new IllegalDateTimeFieldException("Day not available");
190: return data[D];
191: }
192:
193: /**
194: * Return the number of hours in the dateTime
195: * @throws IllegalDateTimeFieldException if there is no legal time component
196: */
197: public int getHours() throws IllegalDateTimeFieldException {
198: if ((mask & TIME_MASK) == 0)
199: throw new IllegalDateTimeFieldException(
200: "Time not available");
201: return data[h];
202: }
203:
204: /**
205: * Return the number of minutes in the dateTime
206: * @throws IllegalDateTimeFieldException if there is no legal time component
207: */
208: public int getMinutes() throws IllegalDateTimeFieldException {
209: if ((mask & TIME_MASK) == 0)
210: throw new IllegalDateTimeFieldException(
211: "Time not available");
212: return data[m];
213: }
214:
215: /**
216: * Return the number of full seconds in the dateTime
217: * @throws IllegalDateTimeFieldException if there is no legal time component
218: */
219: public int getFullSeconds() throws IllegalDateTimeFieldException {
220: if ((mask & TIME_MASK) == 0)
221: throw new IllegalDateTimeFieldException(
222: "Time not available");
223: return data[s];
224: }
225:
226: /**
227: * Return the number of seconds in the dateTime, including fractional part
228: * @throws IllegalDateTimeFieldException if there is no legal time component
229: */
230: public double getSeconds() throws IllegalDateTimeFieldException {
231: if ((mask & TIME_MASK) == 0)
232: throw new IllegalDateTimeFieldException(
233: "Time not available");
234: return data[s] + fractionalSeconds;
235: }
236:
237: /**
238: * Return the time component of the dateTime - i.e. just the hours/mins/seconds,
239: * and returns the values in seconds.
240: * @throws IllegalDateTimeFieldException if there is no legal time component
241: */
242: public double getTimePart() throws IllegalDateTimeFieldException {
243: if ((mask & TIME_MASK) == 0)
244: throw new IllegalDateTimeFieldException(
245: "Time not available");
246: return ((data[h]) * 60l + data[m]) * 60l + getSeconds();
247: }
248:
249: /**
250: * Return legal serialized form.
251: */
252: public String toString() {
253: StringBuffer buff = new StringBuffer();
254: if ((mask & YEAR_MASK) != 0) {
255: buff.append(data[CY]);
256: } else {
257: buff.append("-");
258: }
259: if ((mask & (MONTH_MASK | DAY_MASK)) != 0) {
260: buff.append("-");
261: if ((mask & MONTH_MASK) != 0) {
262: if (data[M] <= 9)
263: buff.append("0");
264: buff.append(data[M]);
265: } else {
266: buff.append("-");
267: }
268: if ((mask & DAY_MASK) != 0) {
269: if (mask != DAY_MASK)
270: buff.append("-");
271: if (data[D] <= 9)
272: buff.append("0");
273: buff.append(data[D]);
274: }
275: }
276: if ((mask & TIME_MASK) != 0) {
277: buff.append("T");
278: buff.append(timeLexicalForm());
279: }
280:
281: if (data[utc] != 0)
282: buff.append("Z");
283:
284: return buff.toString();
285: }
286:
287: /**
288: * Return the lexical form of the time component.
289: */
290: public String timeLexicalForm() {
291: StringBuffer buff = new StringBuffer();
292: if (data[h] < 10)
293: buff.append("0");
294: buff.append(data[h]);
295:
296: buff.append(":");
297: if (data[m] < 10)
298: buff.append("0");
299: buff.append(data[m]);
300:
301: buff.append(":");
302: if (data[s] < 10)
303: buff.append("0");
304: buff.append(data[s]);
305:
306: if (data[ms] != 0) {
307: buff.append(".");
308: XSDAbstractDateTimeType.appendFractionalTime(buff,
309: data[ms], data[msscale]);
310: }
311: return buff.toString();
312: }
313:
314: }
315:
316: /*
317: (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
318: All rights reserved.
319:
320: Redistribution and use in source and binary forms, with or without
321: modification, are permitted provided that the following conditions
322: are met:
323:
324: 1. Redistributions of source code must retain the above copyright
325: notice, this list of conditions and the following disclaimer.
326:
327: 2. Redistributions in binary form must reproduce the above copyright
328: notice, this list of conditions and the following disclaimer in the
329: documentation and/or other materials provided with the distribution.
330:
331: 3. The name of the author may not be used to endorse or promote products
332: derived from this software without specific prior written permission.
333:
334: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
335: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
336: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
337: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
338: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
339: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
340: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
341: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
343: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
344: */
|