Source code: com/hp/hpl/jena/datatypes/xsd/XSDDateTime.java
1 /******************************************************************
2 * File: XSDDateTime.java
3 * Created by: Dave Reynolds
4 * Created on: 17-Dec-2002
5 *
6 * (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
7 * [See end of file]
8 * $Id: XSDDateTime.java,v 1.17 2005/02/21 12:02:16 andy_seaborne Exp $
9 *****************************************************************/
10 package com.hp.hpl.jena.datatypes.xsd;
11
12 import java.util.*;
13
14
15 /**
16 * Represent an XSD date/time value. Rather than have a separate type for each
17 * legal date/time value combination this is a combination type than does runtime
18 * checks whether a given field is legal in the current circumstances.
19 *
20 * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
21 * @version $Revision: 1.17 $ on $Date: 2005/02/21 12:02:16 $
22 */
23 public class XSDDateTime extends AbstractDateTime {
24 /** Mask to indicate whether year is present */
25 public static final short YEAR_MASK = 0x1;
26
27 /** Mask to indicate whether month is present */
28 public static final short MONTH_MASK = 0x2;
29
30 /** Mask to indicate whether day is present */
31 public static final short DAY_MASK = 0x4;
32
33 /** Mask to indicate whether time is present */
34 public static final short TIME_MASK = 0x8;
35
36 /** Mask to indicate all date/time are present */
37 public static final short FULL_MASK = 0xf;
38
39 /** table mapping xs type name to mask of legal values */
40 public static final HashMap maskMap = new HashMap();
41
42 /** Set of legal fields for the particular date/time instance */
43 protected short mask;
44
45 /**
46 * Constructor - should only be used by the internals but public scope because
47 * the internals spread across multiple packages.
48 *
49 * @param value the date/time value returned by the parsing
50 * @param mask bitmask defining which components are valid in this instance
51 * (e.g. dates don't have valid time fields).
52 */
53 public XSDDateTime(Object value, int mask) {
54 super(value);
55 this.mask = (short)mask;
56 }
57
58
59 /**
60 * Constructor - create a full DateTime object from a java calendar instance.
61 *
62 * @param date java calendar instance
63 */
64 public XSDDateTime(Calendar date) {
65 super(convertCalendar(date));
66 this.mask = FULL_MASK;
67 }
68
69 /**
70 * Convert a java calendar object to a new int[] in the format used by XSDAbstractDateTime
71 */
72 private static int[] convertCalendar(Calendar date) {
73 int[] data = new int[TOTAL_SIZE];
74 int offset = date.get(Calendar.ZONE_OFFSET) + date.get(Calendar.DST_OFFSET);
75 // Thanks to Greg Shueler for DST patch
76 Calendar cal = date;
77 if (offset != 0) {
78 cal = (Calendar)date.clone();
79 cal.add(Calendar.MILLISECOND, -offset);
80 }
81 data[AbstractDateTime.CY] = cal.get(Calendar.YEAR);
82 data[AbstractDateTime.M] = cal.get(Calendar.MONTH) + 1;
83 data[AbstractDateTime.D] = cal.get(Calendar.DAY_OF_MONTH);
84 data[AbstractDateTime.h] = cal.get(Calendar.HOUR_OF_DAY);
85 data[AbstractDateTime.m] = cal.get(Calendar.MINUTE);
86 data[AbstractDateTime.s] = cal.get(Calendar.SECOND);
87 data[AbstractDateTime.ms] = cal.get(Calendar.MILLISECOND);
88 data[AbstractDateTime.utc] = 'Z';
89 return data;
90 }
91
92 /**
93 * Return the date time as a java Calendar object.
94 * If the timezone has been specified then the object is normalized to GMT.
95 * If the zone has not been specified then we use the default timezone.
96 * <p>
97 * N.B. The millisecond field will be discarded and the resulting Calendar
98 * object will have 0 in the millisecond field. This is a workaround for an
99 * apparent problem with some Linux JDK's Calendar implementations. If it
100 * causes a problem contact us to ask us to revisit this.
101 * </p>
102 *
103 * @throws IllegalDateTimeFieldException if this is not a full date + time
104 */
105 public Calendar asCalendar () throws IllegalDateTimeFieldException {
106 TimeZone tz = data[utc] == 'Z' ? TimeZone.getTimeZone("GMT") : TimeZone.getDefault();
107 Calendar calendar = new GregorianCalendar(tz);
108 calendar.set(data[CY], data[M] - 1, data[D], data[h], data[m], data[s]);
109 calendar.set(Calendar.MILLISECOND, data[ms]);
110 // was this to work around problems with some Linux JDKs
111 // calendar.set(Calendar.MILLISECOND, 0);
112 return calendar;
113 }
114
115 /**
116 * Return the number of years in the dateTime.
117 * @throws IllegalDateTimeFieldException if there is no legal year component
118 */
119 public int getYears() throws IllegalDateTimeFieldException {
120 if ((mask & YEAR_MASK) == 0) throw new IllegalDateTimeFieldException("Year not available");
121 return data[CY];
122 }
123
124 /**
125 * Return the month in the dateTime, this is in ISO8601 format so january = 1
126 * @throws IllegalDateTimeFieldException if there is no legal month component
127 */
128 public int getMonths() throws IllegalDateTimeFieldException {
129 if ((mask & MONTH_MASK) == 0) throw new IllegalDateTimeFieldException("Month not available");
130 return data[M];
131 }
132
133 /**
134 * Return the number of years in the dateTime
135 * @throws IllegalDateTimeFieldException if there is no legal day component
136 */
137 public int getDays() throws IllegalDateTimeFieldException {
138 if ((mask & DAY_MASK) == 0) throw new IllegalDateTimeFieldException("Day not available");
139 return data[D];
140 }
141
142 /**
143 * Return the number of hours in the dateTime
144 * @throws IllegalDateTimeFieldException if there is no legal time component
145 */
146 public int getHours() throws IllegalDateTimeFieldException {
147 if ((mask & TIME_MASK) == 0) throw new IllegalDateTimeFieldException("Time not available");
148 return data[h];
149 }
150
151 /**
152 * Return the number of minutes in the dateTime
153 * @throws IllegalDateTimeFieldException if there is no legal time component
154 */
155 public int getMinutes() throws IllegalDateTimeFieldException {
156 if ((mask & TIME_MASK) == 0) throw new IllegalDateTimeFieldException("Time not available");
157 return data[m];
158 }
159
160 /**
161 * Return the number of full seconds in the dateTime
162 * @throws IllegalDateTimeFieldException if there is no legal time component
163 */
164 public int getFullSeconds() throws IllegalDateTimeFieldException {
165 if ((mask & TIME_MASK) == 0) throw new IllegalDateTimeFieldException("Time not available");
166 return data[s];
167 }
168
169 /**
170 * Return the number of seconds in the dateTime, including fractional part
171 * @throws IllegalDateTimeFieldException if there is no legal time component
172 */
173 public double getSeconds() throws IllegalDateTimeFieldException {
174 if ((mask & TIME_MASK) == 0) throw new IllegalDateTimeFieldException("Time not available");
175 return data[s] + fractionalSeconds;
176 }
177
178 /**
179 * Return the time component of the dateTime - i.e. just the hours/mins/seconds,
180 * and returns the values in seconds.
181 * @throws IllegalDateTimeFieldException if there is no legal time component
182 */
183 public double getTimePart() throws IllegalDateTimeFieldException {
184 if ((mask & TIME_MASK) == 0) throw new IllegalDateTimeFieldException("Time not available");
185 return ((data[h]) * 60l + data[m]) * 60l + getSeconds();
186 }
187
188 /**
189 * Return legal serialized form.
190 */
191 public String toString() {
192 StringBuffer buff = new StringBuffer();
193 if ((mask & YEAR_MASK) != 0) {
194 buff.append(data[CY]);
195 } else {
196 buff.append("-");
197 }
198 if ((mask & (MONTH_MASK | DAY_MASK)) != 0) {
199 buff.append("-");
200 if ((mask & MONTH_MASK) != 0) {
201 if (data[M] <= 9) buff.append("0");
202 buff.append(data[M]);
203 } else {
204 buff.append("-");
205 }
206 if ((mask & DAY_MASK) != 0) {
207 if (mask != DAY_MASK) buff.append("-");
208 if (data[D] <= 9) buff.append("0");
209 buff.append(data[D]);
210 }
211 }
212 if ((mask & TIME_MASK) != 0 ) {
213 buff.append("T");
214 if(data[h]<10) buff.append("0");
215 buff.append(data[h]);
216
217 buff.append(":");
218 if(data[m]<10) buff.append("0");
219 buff.append(data[m]);
220
221 buff.append(":");
222 if(data[s]<10) buff.append("0");
223 buff.append(data[s]);
224
225 if (data[ms] != 0) {
226 buff.append(".");
227 buff.append(data[ms]);
228 }
229 buff.append("Z");
230 }
231 return buff.toString();
232 }
233
234 }
235
236 /*
237 (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
238 All rights reserved.
239
240 Redistribution and use in source and binary forms, with or without
241 modification, are permitted provided that the following conditions
242 are met:
243
244 1. Redistributions of source code must retain the above copyright
245 notice, this list of conditions and the following disclaimer.
246
247 2. Redistributions in binary form must reproduce the above copyright
248 notice, this list of conditions and the following disclaimer in the
249 documentation and/or other materials provided with the distribution.
250
251 3. The name of the author may not be used to endorse or promote products
252 derived from this software without specific prior written permission.
253
254 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
255 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
256 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
257 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
258 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
259 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
260 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
261 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
263 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
264 */