EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.util]

COVERAGE SUMMARY FOR SOURCE FILE [DateTimeUtils.java]

nameclass, %method, %block, %line, %
DateTimeUtils.java100% (2/2)93%  (40/43)92%  (1610/1757)93%  (299.8/324)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DateTimeUtils100% (1/1)93%  (38/41)92%  (1605/1752)92%  (297.8/322)
DateTimeUtils (): void 0%   (0/1)0%   (0/3)0%   (0/2)
getTimeLocalWithoutDst (Date): long 0%   (0/1)0%   (0/10)0%   (0/1)
getTimeUTCWithoutDst (long): long 0%   (0/1)0%   (0/9)0%   (0/1)
parseDateTime (String, String, String, String): Date 100% (1/1)48%  (15/31)50%  (3/6)
getMillis (TimeZone, int, int, int, int, int, int, int): long 100% (1/1)51%  (50/99)50%  (8/16)
getDateFormat (String, String, String): SimpleDateFormat 100% (1/1)53%  (27/51)78%  (7/9)
convertToLocal (Date, Calendar): long 100% (1/1)74%  (25/34)87%  (7.8/9)
formatDateTime (Date, String, String, String): String 100% (1/1)75%  (15/20)75%  (3/4)
convertDate (Date, Calendar): ValueDate 100% (1/1)80%  (16/20)83%  (5/6)
convertTime (Time, Calendar): ValueTime 100% (1/1)80%  (16/20)83%  (5/6)
convertTimestamp (Timestamp, Calendar): ValueTimestamp 100% (1/1)88%  (28/32)88%  (7/8)
parseTimeNanos (String, int, int, boolean): long 100% (1/1)94%  (150/160)92%  (24/26)
<static initializer> 100% (1/1)100% (115/115)100% (3/3)
absoluteDayFromDateValue (long): long 100% (1/1)100% (78/78)100% (12/12)
convertDate (Value, Calendar): Date 100% (1/1)100% (42/42)100% (10/10)
convertDateValueToDate (long): Date 100% (1/1)100% (18/18)100% (2/2)
convertDateValueToTimestamp (long, long): Timestamp 100% (1/1)100% (71/71)100% (12/12)
convertNanoToTime (long): Time 100% (1/1)100% (55/55)100% (9/9)
convertTime (Calendar, Calendar): void 100% (1/1)100% (49/49)100% (9/9)
convertTime (Value, Calendar): Time 100% (1/1)100% (83/83)100% (18/18)
convertTimestamp (Value, Calendar): Timestamp 100% (1/1)100% (99/99)100% (21/21)
dateValue (long, int, int): long 100% (1/1)100% (12/12)100% (1/1)
dateValueFromAbsoluteDay (long): long 100% (1/1)100% (129/129)100% (25/25)
dateValueFromCalendar (Calendar): long 100% (1/1)100% (26/26)100% (4/4)
dateValueFromDate (long): long 100% (1/1)100% (12/12)100% (4/4)
dayFromDateValue (long): int 100% (1/1)100% (5/5)100% (1/1)
getDatePart (Date, int): int 100% (1/1)100% (26/26)100% (8/8)
getIsoDayOfWeek (Date): int 100% (1/1)100% (18/18)100% (4/4)
getIsoWeek (Date): int 100% (1/1)100% (16/16)100% (5/5)
getIsoYear (Date): int 100% (1/1)100% (39/39)100% (12/12)
getTimeTry (boolean, TimeZone, int, int, int, int, int, int, int): long 100% (1/1)100% (28/28)100% (7/7)
getYear (Calendar): int 100% (1/1)100% (14/14)100% (4/4)
isValidDate (int, int, int): boolean 100% (1/1)100% (96/96)100% (13/13)
monthFromDateValue (long): int 100% (1/1)100% (7/7)100% (1/1)
nanosFromCalendar (Calendar): long 100% (1/1)100% (36/36)100% (5/5)
nanosFromDate (long): long 100% (1/1)100% (12/12)100% (4/4)
normalizeTimestamp (long, long): ValueTimestamp 100% (1/1)100% (40/40)100% (7/7)
parseDateValue (String, int, int): long 100% (1/1)100% (81/81)100% (12/12)
resetCalendar (): void 100% (1/1)100% (3/3)100% (2/2)
setCalendarFields (Calendar, int, int, int, int, int, int, int): void 100% (1/1)100% (48/48)100% (12/12)
yearFromDateValue (long): int 100% (1/1)100% (5/5)100% (1/1)
     
class DateTimeUtils$1100% (1/1)100% (2/2)100% (5/5)100% (2/2)
DateTimeUtils$1 (): void 100% (1/1)100% (3/3)100% (1/1)
initialValue (): Calendar 100% (1/1)100% (2/2)100% (1/1)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 * Iso8601:
6 * Initial Developer: Robert Rathsack (firstName dot lastName at gmx dot de)
7 */
8package org.h2.util;
9 
10import java.sql.Date;
11import java.sql.Time;
12import java.sql.Timestamp;
13import java.text.SimpleDateFormat;
14import java.util.Calendar;
15import java.util.GregorianCalendar;
16import java.util.Locale;
17import java.util.TimeZone;
18 
19import org.h2.api.ErrorCode;
20import org.h2.message.DbException;
21import org.h2.value.Value;
22import org.h2.value.ValueDate;
23import org.h2.value.ValueNull;
24import org.h2.value.ValueTime;
25import org.h2.value.ValueTimestamp;
26 
27/**
28 * This utility class contains time conversion functions.
29 * <p>
30 * Date value: a bit field with bits for the year, month, and day.
31 * Absolute day: the day number (0 means 1970-01-01).
32 */
33public class DateTimeUtils {
34 
35    /**
36     * The number of milliseconds per day.
37     */
38    public static final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000L;
39 
40    private static final long NANOS_PER_DAY = MILLIS_PER_DAY * 1000000;
41 
42    private static final int SHIFT_YEAR = 9;
43    private static final int SHIFT_MONTH = 5;
44 
45    private static final int[] NORMAL_DAYS_PER_MONTH = { 0, 31, 28, 31, 30, 31,
46            30, 31, 31, 30, 31, 30, 31 };
47 
48    /**
49     * Offsets of month within a year, starting with March, April,...
50     */
51    private static final int[] DAYS_OFFSET = { 0, 31, 61, 92, 122, 153, 184,
52            214, 245, 275, 306, 337, 366 };
53 
54    private static final ThreadLocal<Calendar> CACHED_CALENDAR =
55            new ThreadLocal<Calendar>() {
56        @Override
57        protected Calendar initialValue() {
58            return Calendar.getInstance();
59        }
60    };
61 
62    private DateTimeUtils() {
63        // utility class
64    }
65 
66    /**
67     * Reset the calendar, for example after changing the default timezone.
68     */
69    public static void resetCalendar() {
70        CACHED_CALENDAR.remove();
71    }
72 
73    /**
74     * Convert the date to the specified time zone.
75     *
76     * @param value the date (might be ValueNull)
77     * @param calendar the calendar
78     * @return the date using the correct time zone
79     */
80    public static Date convertDate(Value value, Calendar calendar) {
81        if (value == ValueNull.INSTANCE) {
82            return null;
83        }
84        ValueDate d = (ValueDate) value.convertTo(Value.DATE);
85        Calendar cal = (Calendar) calendar.clone();
86        cal.clear();
87        cal.setLenient(true);
88        long dateValue = d.getDateValue();
89        setCalendarFields(cal, yearFromDateValue(dateValue),
90                monthFromDateValue(dateValue),
91                dayFromDateValue(dateValue),
92                0, 0, 0, 0);
93        long ms = cal.getTimeInMillis();
94        return new Date(ms);
95    }
96 
97    /**
98     * Convert the time to the specified time zone.
99     *
100     * @param value the time (might be ValueNull)
101     * @param calendar the calendar
102     * @return the time using the correct time zone
103     */
104    public static Time convertTime(Value value, Calendar calendar) {
105        if (value == ValueNull.INSTANCE) {
106            return null;
107        }
108        ValueTime t = (ValueTime) value.convertTo(Value.TIME);
109        Calendar cal = (Calendar) calendar.clone();
110        cal.clear();
111        cal.setLenient(true);
112        long nanos = t.getNanos();
113        long millis = nanos / 1000000;
114        nanos -= millis * 1000000;
115        long s = millis / 1000;
116        millis -= s * 1000;
117        long m = s / 60;
118        s -= m * 60;
119        long h = m / 60;
120        m -= h * 60;
121        setCalendarFields(cal, 1970, 1, 1,
122                (int) h, (int) m, (int) s, (int) millis);
123        long ms = cal.getTimeInMillis();
124        return new Time(ms);
125    }
126 
127    /**
128     * Convert the timestamp to the specified time zone.
129     *
130     * @param value the timestamp (might be ValueNull)
131     * @param calendar the calendar
132     * @return the timestamp using the correct time zone
133     */
134    public static Timestamp convertTimestamp(Value value, Calendar calendar) {
135        if (value == ValueNull.INSTANCE) {
136            return null;
137        }
138        ValueTimestamp ts = (ValueTimestamp) value.convertTo(Value.TIMESTAMP);
139        Calendar cal = (Calendar) calendar.clone();
140        cal.clear();
141        cal.setLenient(true);
142        long dateValue = ts.getDateValue();
143        long nanos = ts.getTimeNanos();
144        long millis = nanos / 1000000;
145        nanos -= millis * 1000000;
146        long s = millis / 1000;
147        millis -= s * 1000;
148        long m = s / 60;
149        s -= m * 60;
150        long h = m / 60;
151        m -= h * 60;
152        setCalendarFields(cal, yearFromDateValue(dateValue),
153                monthFromDateValue(dateValue),
154                dayFromDateValue(dateValue),
155                (int) h, (int) m, (int) s, (int) millis);
156        long ms = cal.getTimeInMillis();
157        Timestamp x = new Timestamp(ms);
158        x.setNanos((int) (nanos + millis * 1000000));
159        return x;
160    }
161 
162    /**
163     * Convert the date using the specified calendar.
164     *
165     * @param x the date
166     * @param calendar the calendar
167     * @return the date
168     */
169    public static ValueDate convertDate(Date x, Calendar calendar) {
170        if (calendar == null) {
171            throw DbException.getInvalidValueException("calendar", null);
172        }
173        Calendar cal = (Calendar) calendar.clone();
174        cal.setTimeInMillis(x.getTime());
175        long dateValue = dateValueFromCalendar(cal);
176        return ValueDate.fromDateValue(dateValue);
177    }
178 
179    /**
180     * Convert the time using the specified calendar.
181     *
182     * @param x the time
183     * @param calendar the calendar
184     * @return the time
185     */
186    public static ValueTime convertTime(Time x, Calendar calendar) {
187        if (calendar == null) {
188            throw DbException.getInvalidValueException("calendar", null);
189        }
190        Calendar cal = (Calendar) calendar.clone();
191        cal.setTimeInMillis(x.getTime());
192        long nanos = nanosFromCalendar(cal);
193        return ValueTime.fromNanos(nanos);
194    }
195 
196    /**
197     * Convert a date to the specified time zone.
198     *
199     * @param x the date to convert
200     * @param target the calendar with the target timezone
201     * @return the milliseconds in UTC
202     */
203    public static long convertToLocal(java.util.Date x, Calendar target) {
204        if (target == null) {
205            throw DbException.getInvalidValueException("calendar", null);
206        }
207        target = (Calendar) target.clone();
208        Calendar local = Calendar.getInstance();
209        synchronized (local) {
210            local.setTime(x);
211            convertTime(local, target);
212        }
213        return target.getTime().getTime();
214    }
215 
216    private static void convertTime(Calendar from, Calendar to) {
217        to.set(Calendar.ERA, from.get(Calendar.ERA));
218        to.set(Calendar.YEAR, from.get(Calendar.YEAR));
219        to.set(Calendar.MONTH, from.get(Calendar.MONTH));
220        to.set(Calendar.DAY_OF_MONTH, from.get(Calendar.DAY_OF_MONTH));
221        to.set(Calendar.HOUR_OF_DAY, from.get(Calendar.HOUR_OF_DAY));
222        to.set(Calendar.MINUTE, from.get(Calendar.MINUTE));
223        to.set(Calendar.SECOND, from.get(Calendar.SECOND));
224        to.set(Calendar.MILLISECOND, from.get(Calendar.MILLISECOND));
225    }
226 
227    /**
228     * Convert the timestamp using the specified calendar.
229     *
230     * @param x the time
231     * @param calendar the calendar
232     * @return the timestamp
233     */
234    public static ValueTimestamp convertTimestamp(Timestamp x, Calendar calendar) {
235        if (calendar == null) {
236            throw DbException.getInvalidValueException("calendar", null);
237        }
238        Calendar cal = (Calendar) calendar.clone();
239        cal.setTimeInMillis(x.getTime());
240        long dateValue = dateValueFromCalendar(cal);
241        long nanos = nanosFromCalendar(cal);
242        nanos += x.getNanos() % 1000000;
243        return ValueTimestamp.fromDateValueAndNanos(dateValue, nanos);
244    }
245 
246    /**
247     * Parse a date string. The format is: [+|-]year-month-day
248     *
249     * @param s the string to parse
250     * @param start the parse index start
251     * @param end the parse index end
252     * @return the date value
253     * @throws IllegalArgumentException if there is a problem
254     */
255    public static long parseDateValue(String s, int start, int end) {
256        if (s.charAt(start) == '+') {
257            // +year
258            start++;
259        }
260        // start at position 1 to support "-year"
261        int s1 = s.indexOf('-', start + 1);
262        int s2 = s.indexOf('-', s1 + 1);
263        if (s1 <= 0 || s2 <= s1) {
264            throw new IllegalArgumentException(s);
265        }
266        int year = Integer.parseInt(s.substring(start, s1));
267        int month = Integer.parseInt(s.substring(s1 + 1, s2));
268        int day = Integer.parseInt(s.substring(s2 + 1, end));
269        if (!isValidDate(year, month, day)) {
270            throw new IllegalArgumentException(year + "-" + month + "-" + day);
271        }
272        return dateValue(year, month, day);
273    }
274 
275    /**
276     * Parse a time string. The format is: [-]hour:minute:second[.nanos]
277     *
278     * @param s the string to parse
279     * @param start the parse index start
280     * @param end the parse index end
281     * @param timeOfDay whether the result need to be within 0 (inclusive) and 1
282     *            day (exclusive)
283     * @return the time in nanoseconds
284     * @throws IllegalArgumentException if there is a problem
285     */
286    public static long parseTimeNanos(String s, int start, int end,
287            boolean timeOfDay) {
288        int hour = 0, minute = 0, second = 0;
289        long nanos = 0;
290        int s1 = s.indexOf(':', start);
291        int s2 = s.indexOf(':', s1 + 1);
292        int s3 = s.indexOf('.', s2 + 1);
293        if (s1 <= 0 || s2 <= s1) {
294            throw new IllegalArgumentException(s);
295        }
296        boolean negative;
297        hour = Integer.parseInt(s.substring(start, s1));
298        if (hour < 0) {
299            if (timeOfDay) {
300                throw new IllegalArgumentException(s);
301            }
302            negative = true;
303            hour = -hour;
304        } else {
305            negative = false;
306        }
307        minute = Integer.parseInt(s.substring(s1 + 1, s2));
308        if (s3 < 0) {
309            second = Integer.parseInt(s.substring(s2 + 1, end));
310        } else {
311            second = Integer.parseInt(s.substring(s2 + 1, s3));
312            String n = (s.substring(s3 + 1, end) + "000000000").substring(0, 9);
313            nanos = Integer.parseInt(n);
314        }
315        if (hour >= 2000000 || minute < 0 ||
316                minute >= 60 || second < 0 || second >= 60) {
317            throw new IllegalArgumentException(s);
318        }
319        if (timeOfDay && hour >= 24) {
320            throw new IllegalArgumentException(s);
321        }
322        nanos += ((((hour * 60L) + minute) * 60) + second) * 1000000000;
323        return negative ? -nanos : nanos;
324    }
325 
326    /**
327     * Calculate the milliseconds since 1970-01-01 (UTC) for the given date and
328     * time (in the specified timezone).
329     *
330     * @param tz the timezone of the parameters,
331 *              or null for the default timezone
332     * @param year the absolute year (positive or negative)
333     * @param month the month (1-12)
334     * @param day the day (1-31)
335     * @param hour the hour (0-23)
336     * @param minute the minutes (0-59)
337     * @param second the number of seconds (0-59)
338     * @param millis the number of milliseconds
339     * @return the number of milliseconds (UTC)
340     */
341    public static long getMillis(TimeZone tz, int year, int month, int day,
342            int hour, int minute, int second, int millis) {
343        try {
344            return getTimeTry(false, tz, year, month, day, hour, minute, second, millis);
345        } catch (IllegalArgumentException e) {
346            // special case: if the time simply doesn't exist because of
347            // daylight saving time changes, use the lenient version
348            String message = e.toString();
349            if (message.indexOf("HOUR_OF_DAY") > 0) {
350                if (hour < 0 || hour > 23) {
351                    throw e;
352                }
353                return getTimeTry(true, tz, year, month, day, hour, minute,
354                        second, millis);
355            } else if (message.indexOf("DAY_OF_MONTH") > 0) {
356                int maxDay;
357                if (month == 2) {
358                    maxDay = new GregorianCalendar().isLeapYear(year) ? 29 : 28;
359                } else {
360                    maxDay = 30 + ((month + (month > 7 ? 1 : 0)) & 1);
361                }
362                if (day < 1 || day > maxDay) {
363                    throw e;
364                }
365                // DAY_OF_MONTH is thrown for years > 2037
366                // using the timezone Brasilia and others,
367                // for example for 2042-10-12 00:00:00.
368                hour += 6;
369                return getTimeTry(true, tz, year, month, day, hour, minute,
370                        second, millis);
371            } else {
372                return getTimeTry(true, tz, year, month, day, hour, minute,
373                        second, millis);
374            }
375        }
376    }
377 
378    private static long getTimeTry(boolean lenient, TimeZone tz,
379            int year, int month, int day, int hour, int minute, int second,
380            int millis) {
381        Calendar c;
382        if (tz == null) {
383            c = CACHED_CALENDAR.get();
384        } else {
385            c = Calendar.getInstance(tz);
386        }
387        c.clear();
388        c.setLenient(lenient);
389        setCalendarFields(c, year, month, day, hour, minute, second, millis);
390        return c.getTime().getTime();
391    }
392 
393    private static void setCalendarFields(Calendar cal, int year, int month,
394            int day, int hour, int minute, int second, int millis) {
395        if (year <= 0) {
396            cal.set(Calendar.ERA, GregorianCalendar.BC);
397            cal.set(Calendar.YEAR, 1 - year);
398        } else {
399            cal.set(Calendar.ERA, GregorianCalendar.AD);
400            cal.set(Calendar.YEAR, year);
401        }
402        // january is 0
403        cal.set(Calendar.MONTH, month - 1);
404        cal.set(Calendar.DAY_OF_MONTH, day);
405        cal.set(Calendar.HOUR_OF_DAY, hour);
406        cal.set(Calendar.MINUTE, minute);
407        cal.set(Calendar.SECOND, second);
408        cal.set(Calendar.MILLISECOND, millis);
409    }
410 
411    /**
412     * Get the specified field of a date, however with years normalized to
413     * positive or negative, and month starting with 1.
414     *
415     * @param d the date
416     * @param field the field type
417     * @return the value
418     */
419    public static int getDatePart(java.util.Date d, int field) {
420        Calendar c = CACHED_CALENDAR.get();
421        c.setTime(d);
422        if (field == Calendar.YEAR) {
423            return getYear(c);
424        }
425        int value = c.get(field);
426        if (field == Calendar.MONTH) {
427            return value + 1;
428        }
429        return value;
430    }
431 
432    /**
433     * Get the year (positive or negative) from a calendar.
434     *
435     * @param calendar the calendar
436     * @return the year
437     */
438    private static int getYear(Calendar calendar) {
439        int year = calendar.get(Calendar.YEAR);
440        if (calendar.get(Calendar.ERA) == GregorianCalendar.BC) {
441            year = 1 - year;
442        }
443        return year;
444    }
445 
446    /**
447     * Get the number of milliseconds since 1970-01-01 in the local timezone,
448     * but without daylight saving time into account.
449     *
450     * @param d the date
451     * @return the milliseconds
452     */
453    public static long getTimeLocalWithoutDst(java.util.Date d) {
454        return d.getTime() + CACHED_CALENDAR.get().get(Calendar.ZONE_OFFSET);
455    }
456 
457    /**
458     * Convert the number of milliseconds since 1970-01-01 in the local timezone
459     * to UTC, but without daylight saving time into account.
460     *
461     * @param millis the number of milliseconds in the local timezone
462     * @return the number of milliseconds in UTC
463     */
464    public static long getTimeUTCWithoutDst(long millis) {
465        return millis - CACHED_CALENDAR.get().get(Calendar.ZONE_OFFSET);
466    }
467 
468    /**
469     * Return the day of week according to the ISO 8601 specification. Week
470     * starts at Monday. See also http://en.wikipedia.org/wiki/ISO_8601
471     *
472     * @author Robert Rathsack
473     *
474     * @param date the date object which day of week should be calculated
475     * @return the day of the week, Monday as 1 to Sunday as 7
476     */
477    public static int getIsoDayOfWeek(java.util.Date date) {
478        Calendar cal = Calendar.getInstance();
479        cal.setTimeInMillis(date.getTime());
480        int val = cal.get(Calendar.DAY_OF_WEEK) - 1;
481        return val == 0 ? 7 : val;
482    }
483 
484    /**
485     * Returns the week of the year according to the ISO 8601 specification. The
486     * spec defines the first week of the year as the week which contains at
487     * least 4 days of the new year. The week starts at Monday. Therefore
488     * December 29th - 31th could belong to the next year and January 1st - 3th
489     * could belong to the previous year. If January 1st is on Thursday (or
490     * earlier) it belongs to the first week, otherwise to the last week of the
491     * previous year. Hence January 4th always belongs to the first week while
492     * the December 28th always belongs to the last week.
493     *
494     * @author Robert Rathsack
495     * @param date the date object which week of year should be calculated
496     * @return the week of the year
497     */
498    public static int getIsoWeek(java.util.Date date) {
499        Calendar c = Calendar.getInstance();
500        c.setTimeInMillis(date.getTime());
501        c.setFirstDayOfWeek(Calendar.MONDAY);
502        c.setMinimalDaysInFirstWeek(4);
503        return c.get(Calendar.WEEK_OF_YEAR);
504    }
505 
506    /**
507     * Returns the year according to the ISO week definition.
508     *
509     * @author Robert Rathsack
510     *
511     * @param date the date object which year should be calculated
512     * @return the year
513     */
514    public static int getIsoYear(java.util.Date date) {
515        Calendar cal = Calendar.getInstance();
516        cal.setTimeInMillis(date.getTime());
517        cal.setFirstDayOfWeek(Calendar.MONDAY);
518        cal.setMinimalDaysInFirstWeek(4);
519        int year = getYear(cal);
520        int month = cal.get(Calendar.MONTH);
521        int week = cal.get(Calendar.WEEK_OF_YEAR);
522        if (month == 0 && week > 51) {
523            year--;
524        } else if (month == 11 && week == 1) {
525            year++;
526        }
527        return year;
528    }
529 
530    /**
531     * Formats a date using a format string.
532     *
533     * @param date the date to format
534     * @param format the format string
535     * @param locale the locale
536     * @param timeZone the timezone
537     * @return the formatted date
538     */
539    public static String formatDateTime(java.util.Date date, String format,
540            String locale, String timeZone) {
541        SimpleDateFormat dateFormat = getDateFormat(format, locale, timeZone);
542        synchronized (dateFormat) {
543            return dateFormat.format(date);
544        }
545    }
546 
547    /**
548     * Parses a date using a format string.
549     *
550     * @param date the date to parse
551     * @param format the parsing format
552     * @param locale the locale
553     * @param timeZone the timeZone
554     * @return the parsed date
555     */
556    public static java.util.Date parseDateTime(String date, String format,
557            String locale, String timeZone) {
558        SimpleDateFormat dateFormat = getDateFormat(format, locale, timeZone);
559        try {
560            synchronized (dateFormat) {
561                return dateFormat.parse(date);
562            }
563        } catch (Exception e) {
564            // ParseException
565            throw DbException.get(ErrorCode.PARSE_ERROR_1, e, date);
566        }
567    }
568 
569    private static SimpleDateFormat getDateFormat(String format, String locale,
570            String timeZone) {
571        try {
572            // currently, a new instance is create for each call
573            // however, could cache the last few instances
574            SimpleDateFormat df;
575            if (locale == null) {
576                df = new SimpleDateFormat(format);
577            } else {
578                Locale l = new Locale(locale);
579                df = new SimpleDateFormat(format, l);
580            }
581            if (timeZone != null) {
582                df.setTimeZone(TimeZone.getTimeZone(timeZone));
583            }
584            return df;
585        } catch (Exception e) {
586            throw DbException.get(ErrorCode.PARSE_ERROR_1, e,
587                    format + "/" + locale + "/" + timeZone);
588        }
589    }
590 
591    /**
592     * Verify if the specified date is valid.
593     *
594     * @param year the year
595     * @param month the month (January is 1)
596     * @param day the day (1 is the first of the month)
597     * @return true if it is valid
598     */
599    public static boolean isValidDate(int year, int month, int day) {
600        if (month < 1 || month > 12 || day < 1) {
601            return false;
602        }
603        if (year > 1582) {
604            // Gregorian calendar
605            if (month != 2) {
606                return day <= NORMAL_DAYS_PER_MONTH[month];
607            }
608            // February
609            if ((year & 3) != 0) {
610                return day <= 28;
611            }
612            return day <= ((year % 100 != 0) || (year % 400 == 0) ? 29 : 28);
613        } else if (year == 1582 && month == 10) {
614            // special case: days 1582-10-05 .. 1582-10-14 don't exist
615            return day <= 31 && (day < 5 || day > 14);
616        }
617        if (month != 2 && day <= NORMAL_DAYS_PER_MONTH[month]) {
618            return true;
619        }
620        return day <= ((year & 3) != 0 ? 28 : 29);
621    }
622 
623    /**
624     * Convert a date value to a date, using the default timezone.
625     *
626     * @param dateValue the date value
627     * @return the date
628     */
629    public static Date convertDateValueToDate(long dateValue) {
630        long millis = getMillis(null,
631                yearFromDateValue(dateValue),
632                monthFromDateValue(dateValue),
633                dayFromDateValue(dateValue), 0, 0, 0, 0);
634        return new Date(millis);
635    }
636 
637    /**
638     * Convert a date value / time value to a timestamp, using the default
639     * timezone.
640     *
641     * @param dateValue the date value
642     * @param timeNanos the nanoseconds since midnight
643     * @return the timestamp
644     */
645    public static Timestamp convertDateValueToTimestamp(long dateValue,
646            long timeNanos) {
647        long millis = timeNanos / 1000000;
648        timeNanos -= millis * 1000000;
649        long s = millis / 1000;
650        millis -= s * 1000;
651        long m = s / 60;
652        s -= m * 60;
653        long h = m / 60;
654        m -= h * 60;
655        long ms = getMillis(null,
656                yearFromDateValue(dateValue),
657                monthFromDateValue(dateValue),
658                dayFromDateValue(dateValue),
659                (int) h, (int) m, (int) s, 0);
660        Timestamp ts = new Timestamp(ms);
661        ts.setNanos((int) (timeNanos + millis * 1000000));
662        return ts;
663    }
664 
665    /**
666     * Convert a time value to a time, using the default
667     * timezone.
668     *
669     * @param nanos the nanoseconds since midnight
670     * @return the time
671     */
672    public static Time convertNanoToTime(long nanos) {
673        long millis = nanos / 1000000;
674        long s = millis / 1000;
675        millis -= s * 1000;
676        long m = s / 60;
677        s -= m * 60;
678        long h = m / 60;
679        m -= h * 60;
680        long ms = getMillis(null,
681                1970, 1, 1, (int) (h % 24), (int) m, (int) s, (int) millis);
682        return new Time(ms);
683    }
684 
685    /**
686     * Get the year from a date value.
687     *
688     * @param x the date value
689     * @return the year
690     */
691    public static int yearFromDateValue(long x) {
692        return (int) (x >>> SHIFT_YEAR);
693    }
694 
695    /**
696     * Get the month from a date value.
697     *
698     * @param x the date value
699     * @return the month (1..12)
700     */
701    public static int monthFromDateValue(long x) {
702        return (int) (x >>> SHIFT_MONTH) & 15;
703    }
704 
705    /**
706     * Get the day of month from a date value.
707     *
708     * @param x the date value
709     * @return the day (1..31)
710     */
711    public static int dayFromDateValue(long x) {
712        return (int) (x & 31);
713    }
714 
715    /**
716     * Get the date value from a given date.
717     *
718     * @param year the year
719     * @param month the month (1..12)
720     * @param day the day (1..31)
721     * @return the date value
722     */
723    public static long dateValue(long year, int month, int day) {
724        return (year << SHIFT_YEAR) | (month << SHIFT_MONTH) | day;
725    }
726 
727    /**
728     * Calculate the date value (in the default timezone) from a given time in
729     * milliseconds in UTC.
730     *
731     * @param ms the milliseconds
732     * @return the date value
733     */
734    public static long dateValueFromDate(long ms) {
735        Calendar cal = CACHED_CALENDAR.get();
736        cal.clear();
737        cal.setTimeInMillis(ms);
738        return dateValueFromCalendar(cal);
739    }
740 
741    /**
742     * Calculate the date value from a given calendar.
743     *
744     * @param cal the calendar
745     * @return the date value
746     */
747    private static long dateValueFromCalendar(Calendar cal) {
748        int year, month, day;
749        year = getYear(cal);
750        month = cal.get(Calendar.MONTH) + 1;
751        day = cal.get(Calendar.DAY_OF_MONTH);
752        return ((long) year << SHIFT_YEAR) | (month << SHIFT_MONTH) | day;
753    }
754 
755    /**
756     * Calculate the nanoseconds since midnight (in the default timezone) from a
757     * given time in milliseconds in UTC.
758     *
759     * @param ms the milliseconds
760     * @return the nanoseconds
761     */
762    public static long nanosFromDate(long ms) {
763        Calendar cal = CACHED_CALENDAR.get();
764        cal.clear();
765        cal.setTimeInMillis(ms);
766        return nanosFromCalendar(cal);
767    }
768 
769    /**
770     * Calculate the nanoseconds since midnight from a given calendar.
771     *
772     * @param cal the calendar
773     * @return the nanoseconds
774     */
775    private static long nanosFromCalendar(Calendar cal) {
776        int h = cal.get(Calendar.HOUR_OF_DAY);
777        int m = cal.get(Calendar.MINUTE);
778        int s = cal.get(Calendar.SECOND);
779        int millis = cal.get(Calendar.MILLISECOND);
780        return ((((((h * 60L) + m) * 60) + s) * 1000) + millis) * 1000000;
781    }
782 
783    /**
784     * Calculate the normalized timestamp.
785     *
786     * @param absoluteDay the absolute day
787     * @param nanos the nanoseconds (may be negative or larger than one day)
788     * @return the timestamp
789     */
790    public static ValueTimestamp normalizeTimestamp(long absoluteDay, long nanos) {
791        if (nanos > NANOS_PER_DAY || nanos < 0) {
792            long d;
793            if (nanos > NANOS_PER_DAY) {
794                d = nanos / NANOS_PER_DAY;
795            } else {
796                d = (nanos - NANOS_PER_DAY + 1) / NANOS_PER_DAY;
797            }
798            nanos -= d * NANOS_PER_DAY;
799            absoluteDay += d;
800        }
801        return ValueTimestamp.fromDateValueAndNanos(
802                dateValueFromAbsoluteDay(absoluteDay), nanos);
803    }
804 
805    /**
806     * Calculate the absolute day from a date value.
807     *
808     * @param dateValue the date value
809     * @return the absolute day
810     */
811    public static long absoluteDayFromDateValue(long dateValue) {
812        long y = yearFromDateValue(dateValue);
813        int m = monthFromDateValue(dateValue);
814        int d = dayFromDateValue(dateValue);
815        if (m <= 2) {
816            y--;
817            m += 12;
818        }
819        long a = ((y * 2922L) >> 3) + DAYS_OFFSET[m - 3] + d - 719484;
820        if (y <= 1582 && ((y < 1582) || (m * 100 + d < 1005))) {
821            // Julian calendar (cutover at 1582-10-04 / 1582-10-15)
822            a += 13;
823        } else if (y < 1901 || y > 2099) {
824            // Gregorian calendar (slow mode)
825            a += (y / 400) - (y / 100) + 15;
826        }
827        return a;
828    }
829 
830    /**
831     * Calculate the date value from an absolute day.
832     *
833     * @param absoluteDay the absolute day
834     * @return the date value
835     */
836    public static long dateValueFromAbsoluteDay(long absoluteDay) {
837        long d = absoluteDay + 719468;
838        long y100 = 0, offset;
839        if (d > 578040) {
840            // Gregorian calendar
841            long y400 = d / 146097;
842            d -= y400 * 146097;
843            y100 = d / 36524;
844            d -= y100 * 36524;
845            offset = y400 * 400 + y100 * 100;
846        } else {
847            // Julian calendar
848            d += 292200000002L;
849            offset = -800000000;
850        }
851        long y4 = d / 1461;
852        d -= y4 * 1461;
853        long y = d / 365;
854        d -= y * 365;
855        if (d == 0 && (y == 4 || y100 == 4)) {
856            y--;
857            d += 365;
858        }
859        y += offset + y4 * 4;
860        // month of a day
861        int m = ((int) d * 2 + 1) * 5 / 306;
862        d -= DAYS_OFFSET[m] - 1;
863        if (m >= 10) {
864            y++;
865            m -= 12;
866        }
867        return dateValue(y, m + 3, (int) d);
868    }
869 
870}

[all classes][org.h2.util]
EMMA 2.0.5312 (C) Vladimir Roubtsov