001: package gnu.xquery.util;
002:
003: import gnu.xml.*;
004: import gnu.kawa.xml.*;
005: import gnu.math.*;
006: import gnu.mapping.WrongType;
007: import gnu.mapping.Values;
008: import java.math.BigDecimal;
009: import java.math.BigInteger;
010: import java.util.TimeZone;
011:
012: public class TimeUtils {
013: static DateTime coerceToDateTime(String fun, Object value) {
014: if (XTimeType.dateTimeType.isInstance(value))
015: return (DateTime) value;
016: if (value instanceof KNode || value instanceof UntypedAtomic)
017: return XTimeType.parseDateTime(
018: TextUtils.stringValue(value), DateTime.DATE_MASK
019: | DateTime.TIME_MASK);
020: throw new WrongType(fun, 1, value, "xs:dateTime");
021: }
022:
023: static DateTime coerceToDate(String fun, Object value) {
024: if (XTimeType.dateType.isInstance(value))
025: return (DateTime) value;
026: if (value instanceof KNode || value instanceof UntypedAtomic)
027: return XTimeType.parseDateTime(
028: TextUtils.stringValue(value), DateTime.DATE_MASK);
029: throw new WrongType(fun, 1, value, "xs:date");
030: }
031:
032: static DateTime coerceToTime(String fun, Object value) {
033: if (XTimeType.timeType.isInstance(value))
034: return (DateTime) value;
035: if (value instanceof KNode || value instanceof UntypedAtomic)
036: return XTimeType.parseDateTime(
037: TextUtils.stringValue(value), DateTime.TIME_MASK);
038: throw new WrongType(fun, 1, value, "xs:time");
039: }
040:
041: static Duration coerceToDuration(String fun, Object value) {
042: if (value instanceof Duration)
043: return (Duration) value;
044: throw new WrongType(fun, 1, value, "xs:duration");
045: }
046:
047: static Object timeZoneFromXTime(DateTime time) {
048: if (time.isZoneUnspecified())
049: return Values.empty;
050: return Duration.makeMinutes(time.getZoneMinutes());
051: }
052:
053: static IntNum asInteger(int value) {
054: return IntNum.make(value);
055: }
056:
057: public static Object yearFromDateTime(Object arg) {
058: if (arg == null || arg == Values.empty)
059: return arg;
060: return asInteger(coerceToDateTime("year-from-dateTime", arg)
061: .getYear());
062: }
063:
064: public static Object monthFromDateTime(Object arg) {
065: if (arg == null || arg == Values.empty)
066: return arg;
067: return asInteger(coerceToDateTime("month-from-dateTime", arg)
068: .getMonth());
069: }
070:
071: public static Object dayFromDateTime(Object arg) {
072: if (arg == null || arg == Values.empty)
073: return arg;
074: return asInteger(coerceToDateTime("day-from-dateTime", arg)
075: .getDay());
076: }
077:
078: public static Object hoursFromDateTime(Object arg) {
079: if (arg == null || arg == Values.empty)
080: return arg;
081: return asInteger(coerceToDateTime("hours-from-dateTime", arg)
082: .getHours());
083: }
084:
085: public static Object minutesFromDateTime(Object arg) {
086: if (arg == null || arg == Values.empty)
087: return arg;
088: return asInteger(coerceToDateTime("minutes-from-dateTime", arg)
089: .getMinutes());
090: }
091:
092: static Number getSeconds(DateTime date) {
093: int seconds = date.getSecondsOnly();
094: long nanos = date.getNanoSecondsOnly();
095: if (nanos == 0)
096: return IntNum.make(seconds);
097: nanos += seconds * 1000000000L;
098: return new BigDecimal(BigInteger.valueOf(nanos), 9);
099: }
100:
101: public static Object secondsFromDateTime(Object arg) {
102: if (arg == null || arg == Values.empty)
103: return arg;
104: return getSeconds(coerceToDateTime("seconds-from-dateTime", arg));
105: }
106:
107: public static Object timezoneFromDateTime(Object arg) {
108: if (arg == null || arg == Values.empty)
109: return arg;
110: return timeZoneFromXTime(coerceToDateTime(
111: "timezone-from-datetime", arg));
112: }
113:
114: public static Object yearFromDate(Object arg) {
115: if (arg == null || arg == Values.empty)
116: return arg;
117: return asInteger(coerceToDate("year-from-date", arg).getYear());
118: }
119:
120: public static Object monthFromDate(Object arg) {
121: if (arg == null || arg == Values.empty)
122: return arg;
123: return asInteger(coerceToDate("month-from-date", arg)
124: .getMonth());
125: }
126:
127: public static Object dayFromDate(Object arg) {
128: if (arg == null || arg == Values.empty)
129: return arg;
130: return asInteger(coerceToDate("day-from-date", arg).getDay());
131: }
132:
133: public static Object timezoneFromDate(Object arg) {
134: if (arg == null || arg == Values.empty)
135: return arg;
136: return timeZoneFromXTime(coerceToDate("timezone-from-date", arg));
137: }
138:
139: public static Object hoursFromTime(Object arg) {
140: if (arg == null || arg == Values.empty)
141: return arg;
142: return asInteger(coerceToTime("hours-from-time", arg)
143: .getHours());
144: }
145:
146: public static Object minutesFromTime(Object arg) {
147: if (arg == null || arg == Values.empty)
148: return arg;
149: return asInteger(coerceToTime("minutes-from-time", arg)
150: .getMinutes());
151: }
152:
153: public static Object secondsFromTime(Object arg) {
154: if (arg == null || arg == Values.empty)
155: return arg;
156: return getSeconds(coerceToTime("seconds-from-time", arg));
157: }
158:
159: public static Object timezoneFromTime(Object arg) {
160: if (arg == null || arg == Values.empty)
161: return arg;
162: return timeZoneFromXTime(coerceToTime("timezone-from-time", arg));
163: }
164:
165: public static Object yearsFromDuration(Object arg) {
166: if (arg == null || arg == Values.empty)
167: return arg;
168: return asInteger(coerceToDuration("years-from-duration", arg)
169: .getYears());
170: }
171:
172: public static Object monthsFromDuration(Object arg) {
173: if (arg == null || arg == Values.empty)
174: return arg;
175: return asInteger(coerceToDuration("months-from-duration", arg)
176: .getMonths());
177: }
178:
179: public static Object daysFromDuration(Object arg) {
180: if (arg == null || arg == Values.empty)
181: return arg;
182: return asInteger(coerceToDuration("days-from-duration", arg)
183: .getDays());
184: }
185:
186: public static Object hoursFromDuration(Object arg) {
187: if (arg == null || arg == Values.empty)
188: return arg;
189: return asInteger(coerceToDuration("hours-from-duration", arg)
190: .getHours());
191: }
192:
193: public static Object minutesFromDuration(Object arg) {
194: if (arg == null || arg == Values.empty)
195: return arg;
196: return asInteger(coerceToDuration("minutes-from-duration", arg)
197: .getMinutes());
198: }
199:
200: public static BigDecimal secondsBigDecimalFromDuration(long s, int n) {
201: if (n == 0)
202: return BigDecimal.valueOf(s);
203: int scale = 9;
204: // A simple way to make sure s * 1000000000L doesn't overflow:
205: boolean huge = (int) s != s;
206: long ns = huge ? n : s * 1000000000L + n;
207: while (ns % 10 == 0) {
208: ns = ns / 10;
209: scale--;
210: }
211: BigDecimal dec = new BigDecimal(BigInteger.valueOf(ns), scale);
212: if (huge)
213: dec = BigDecimal.valueOf(s).add(dec);
214: return dec;
215: }
216:
217: public static Object secondsFromDuration(Object arg) {
218: if (arg == null || arg == Values.empty)
219: return arg;
220: Duration d = coerceToDuration("seconds-from-duration", arg);
221: int s = d.getSecondsOnly();
222: int n = d.getNanoSecondsOnly();
223: if (n == 0)
224: return asInteger(s);
225: else
226: return secondsBigDecimalFromDuration(s, n);
227: }
228:
229: public static Duration getImplicitTimezone() {
230: return Duration.makeMinutes(TimeZone.getDefault()
231: .getRawOffset() / 60000);
232: }
233:
234: public static Object adjustDateTimeToTimezone(Object time) {
235: return adjustDateTimeToTimezone(time, getImplicitTimezone());
236: }
237:
238: public static Object adjustDateTimeToTimezone(Object time,
239: Object zone) {
240: if (time == Values.empty || time == null)
241: return time;
242: DateTime dtime = coerceToDateTime(
243: "adjust-dateTime-to-timezone", time);
244: return adjustDateTimeToTimezoneRaw(dtime, zone);
245: }
246:
247: public static Object adjustDateToTimezone(Object time) {
248: return adjustDateToTimezone(time, getImplicitTimezone());
249: }
250:
251: public static Object adjustDateToTimezone(Object time, Object zone) {
252: if (time == Values.empty || time == null)
253: return time;
254: DateTime dtime = coerceToDate("adjust-date-to-timezone", time);
255: return adjustDateTimeToTimezoneRaw(dtime, zone);
256: }
257:
258: public static Object adjustTimeToTimezone(Object time) {
259: return adjustTimeToTimezone(time, getImplicitTimezone());
260: }
261:
262: public static Object adjustTimeToTimezone(Object time, Object zone) {
263: if (time == Values.empty || time == null)
264: return time;
265: DateTime dtime = coerceToTime("adjust-time-to-timezone", time);
266: return adjustDateTimeToTimezoneRaw(dtime, zone);
267: }
268:
269: static Object adjustDateTimeToTimezoneRaw(DateTime dtime,
270: Object zone) {
271: if (zone == Values.empty || zone == null)
272: return dtime.withZoneUnspecified();
273: Duration d = (Duration) zone;
274: if (d.getNanoSecondsOnly() != 0 || d.getSecondsOnly() != 0)
275: throw new IllegalArgumentException(
276: "timezone offset with fractional minute");
277: int delta = (int) d.getTotalMinutes();
278: if (delta < -14 * 60 || delta > 14 * 60)
279: throw new IllegalArgumentException(
280: "timezone offset out of range");
281: return dtime.adjustTimezone(delta);
282: }
283:
284: public static DateTime now() {
285: return gnu.kawa.xml.XTimeType.dateTimeType.now();
286: }
287:
288: public static Object dateTime(Object arg1, Object arg2) {
289: if (arg1 == null || arg1 == Values.empty)
290: return arg1;
291: if (arg2 == null || arg2 == Values.empty)
292: return arg2;
293: DateTime date = coerceToDate("dateTime", arg1);
294: DateTime time = coerceToTime("dateTime", arg2);
295: StringBuffer sbuf = new StringBuffer();
296: date.toStringDate(sbuf);
297: sbuf.append('T');
298: time.toStringTime(sbuf);
299: boolean hasZone1 = !date.isZoneUnspecified();
300: boolean hasZone2 = !time.isZoneUnspecified();
301: if (hasZone1 || hasZone2) {
302: int zone1 = date.getZoneMinutes();
303: int zone2 = time.getZoneMinutes();
304: if (hasZone1 && hasZone2 && zone1 != zone2)
305: throw new Error(
306: "dateTime: incompatible timezone in arguments");
307: DateTime.toStringZone(hasZone1 ? zone1 : zone2, sbuf);
308: }
309: return (DateTime) XTimeType.dateTimeType.valueOf(sbuf
310: .toString());
311: }
312:
313: /* #ifdef JAVA2 */
314: /* #ifdef JAVA5 */
315: // static final ThreadLocal<DateTime> currentDateTimeLocal =
316: // new ThreadLocal<DateTime>();
317: /* #else */
318: static final ThreadLocal currentDateTimeLocal = new ThreadLocal();
319:
320: /* #endif */
321: /* #else */
322: // static DateTime currentDateTime;
323: /* #endif */
324:
325: public static DateTime currentDateTime() {
326: /* #ifdef JAVA2 */
327: DateTime current = (DateTime) currentDateTimeLocal.get();
328: if (current == null) {
329: current = now();
330: currentDateTimeLocal.set(current);
331: }
332: /* #else */
333: // DateTime current = currentDateTime;
334: // if (current == null)
335: // {
336: // current = now();
337: // currentDateTime = current;
338: // }
339: /* #endif */
340: return current;
341: }
342:
343: public static DateTime currentDate() {
344: return currentDateTime().cast(DateTime.DATE_MASK);
345: }
346:
347: public static DateTime currentTime() {
348: return currentDateTime().cast(DateTime.TIME_MASK);
349: }
350:
351: public static Object implicitTimezone() {
352: return timeZoneFromXTime(currentDateTime());
353: }
354: }
|