All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xmlbeans.GDate Maven / Gradle / Ivy

/*   Copyright 2004 The Apache Software Foundation
 *
 *   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.
 */

package org.apache.xmlbeans;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

/**
 * Represents an XML Schema-compatible Gregorian date.
 * 

* There are many date types in XML Schema, and this type * represents the natural union of all those types. A GDate * can hold any subset of date fields (Year, Month, Day, Time, * Timezone, or some combination). Wherever the specification * provides guidance, the guidelines in the * XML Schema 1.0 specification * (plus published errata) are followed. *

* Instances may separately have values or no values for * the year, month, day-of-month, and time-of-day. Not all * operations are meaningful on all combinations. */ public final class GDate implements GDateSpecification, java.io.Serializable { private static final long serialVersionUID = 1L; // XMLSchema spec requires support only for years 1 to 9999, but XMLBeans covers more up to the following limitations // to avoid losing precision when transforming to a java.util.Date static final int MAX_YEAR = 292277265; // is Long.MAX_VALUE ms in years - 1 (for the 11month, 31days, 23h, 59m, 59sec case). static final int MIN_YEAR = -292275295; // is Long.MIN_VALUE ms in years + 1970 + 1 // for fast equality comparison, hashing, and serialization private transient String _canonicalString; private transient String _string; private int _bits; private int _CY; private int _M; private int _D; private int _h; private int _m; private int _s; private BigDecimal _fs; private int _tzsign; private int _tzh; private int _tzm; /* package */ static final BigDecimal _zero = BigDecimal.valueOf(0); /* package */ static final BigDecimal _one = BigDecimal.valueOf(1); /** * Constructs a GDate based on a lexical representation. */ public GDate(CharSequence string) { // first trim XML whitespace int len = string.length(); int start = 0; while (len > 0 && isSpace(string.charAt(len - 1))) len -= 1; while (start < len && isSpace(string.charAt(start))) start += 1; // pick optional timezone off the end if (len - start >= 1 && string.charAt(len - 1) == 'Z') { _bits |= HAS_TIMEZONE; len -= 1; } else if (len - start >= 6) timezone: { int tzsign; int tzhour; int tzminute; if (string.charAt(len - 3) != ':') break timezone; switch (string.charAt(len - 6)) { case '-': tzsign = -1; break; case '+': tzsign = 1; break; default: break timezone; } tzhour = twoDigit(string, len - 5); tzminute = twoDigit(string, len - 2); if (tzhour > 14) throw new IllegalArgumentException("time zone hour must be two digits between -14 and +14"); if (tzminute > 59) throw new IllegalArgumentException("time zone minute must be two digits between 00 and 59"); _bits |= HAS_TIMEZONE; _tzsign = tzsign; _tzh = tzhour; _tzm = tzminute; len -= 6; } // pick date fields off the beginning if it doesn't look like a time if (start < len && (start + 2 >= len || string.charAt(start + 2) != ':')) scandate: { // parse year sign boolean negyear = false; if (start < len && string.charAt(start) == '-') { negyear = true; start += 1; } // scan year digits int value = 0; int digits = -start; char ch; boolean startsWithZero = start < len && digitVal(string.charAt(start))==0; for (;;) { ch = start < len ? string.charAt(start) : '\0'; if (!isDigit(ch)) break; if ( startsWithZero && start+digits>=4 ) throw new IllegalArgumentException("year value starting with zero must be 4 or less digits: " + string); value = value * 10 + digitVal(ch); start += 1; } digits += start; if (digits > 9) throw new IllegalArgumentException("year too long (up to 9 digits)"); else if (digits >= 4) { _bits |= HAS_YEAR; _CY = negyear ? -value : value; if (_CY == 0) throw new IllegalArgumentException("year must not be zero"); } else if (digits > 0) throw new IllegalArgumentException("year must be four digits (may pad with zeroes, e.g., 0560)"); if ( _CY > MAX_YEAR ) throw new IllegalArgumentException("year value not supported: too big, must be less than " + MAX_YEAR); if ( _CY < MIN_YEAR ) throw new IllegalArgumentException("year values not supported: too small, must be bigger than " + MIN_YEAR); // hyphen introduces a month if (ch != '-') { if (negyear && !hasYear()) throw new IllegalArgumentException(); // a single minus else break scandate; } start += 1; // two-digit month if (len - start >= 2) { value = twoDigit(string, start); if (value >= 1 && value <= 12) { _bits |= HAS_MONTH; _M = value; start += 2; } } // hyphen introduces a day ch = start < len ? string.charAt(start) : '\0'; if (ch != '-') { if (!hasMonth()) throw new IllegalArgumentException(); // minus after a year else break scandate; } start += 1; // two-digit day if (len - start >= 2) { value = twoDigit(string, start); if (value >= 1 && value <= 31) { _bits |= HAS_DAY; _D = value; start += 2; } } if (!hasDay()) { // error in the original schema spec permits an extra '-' here if (hasMonth() && !hasYear()) { ch = start < len ? string.charAt(start) : '\0'; if (ch == '-') { start += 1; break scandate; } } throw new IllegalArgumentException(); // minus after a month } } // time if (start < len) { if (hasYear() || hasMonth() || hasDay()) { if (string.charAt(start) != 'T') throw new IllegalArgumentException("date and time must be separated by 'T'"); start += 1; } if (len < start + 8 || string.charAt(start + 2) != ':' || string.charAt(start + 5) != ':') throw new IllegalArgumentException(); int h = twoDigit(string, start); if (h > 24) throw new IllegalArgumentException("hour must be between 00 and 23"); int m = twoDigit(string, start + 3); if (m >= 60) throw new IllegalArgumentException("minute must be between 00 and 59"); int s = twoDigit(string, start + 6); if (s >= 60) throw new IllegalArgumentException("second must be between 00 and 59"); start += 8; BigDecimal fs = _zero; if (start < len) { if (string.charAt(start) != '.') throw new IllegalArgumentException(); if (start + 1 < len) { for (int i = start + 1; i < len; i++) { if (!isDigit(string.charAt(i))) throw new IllegalArgumentException(); } try { fs = new BigDecimal(string.subSequence(start, len).toString()); } catch (Throwable e) { throw new IllegalArgumentException(); } } } _bits |= HAS_TIME; _h = h; _m = m; _s = s; _fs = fs; } if ( hasTime() && _h == 24 ) { if ( _m != 0 || _s != 0 || _fs.compareTo(_zero) != 0 ) throw new IllegalArgumentException("if hour is 24, minutes, seconds and fraction must be 0"); else { // normalize to next day if it has date or at least has day if ( hasDate() ) { GDateBuilder gdb = new GDateBuilder(_CY, _M, _D, _h, _m, _s, _fs, _tzsign, _tzh, _tzm); gdb.normalize24h(); _D = gdb.getDay(); _M = gdb.getMonth(); _CY = gdb.getYear(); _h = 0; } else if ( hasDay() ) // if no date only days increment { _D++; _h = 0; } } } if (!isValid()) throw new IllegalArgumentException("invalid date"); } /** * Constructs a GDate with the specified year, month, day, * hours, minutes, seconds, and optional fractional seconds, in * an unspecified timezone. *

* Note that by not specifying the timezone the GDate * becomes partially unordered with respect to times that * do have a specified timezone. */ public GDate( int year, int month, int day, int hour, int minute, int second, BigDecimal fraction) { _bits = HAS_YEAR | HAS_MONTH | HAS_DAY | HAS_TIME; _CY = year; _M = month; _D = day; _h = hour; _m = minute; _s = second; _fs = fraction == null ? _zero : fraction; if (!isValid()) throw new IllegalArgumentException(); } /** * Constructs an absolute GDate with the specified year, * month, day, hours, minutes, seconds, and optional fractional * seconds, and in the timezone specified. *

* If you wish to have a time or date that isn't in a specified timezone, * then use the constructor that does not include the timezone arguments. */ public GDate( int year, int month, int day, int hour, int minute, int second, BigDecimal fraction, int tzSign, int tzHour, int tzMinute) { _bits = HAS_TIMEZONE | HAS_YEAR | HAS_MONTH | HAS_DAY | HAS_TIME; _CY = year; _M = month; _D = day; _h = hour; _m = minute; _s = second; _fs = fraction == null ? _zero : fraction; _tzsign = tzSign; _tzh = tzHour; _tzm = tzMinute; if (!isValid()) throw new IllegalArgumentException(); } /** * Constructs a GDate based on a java.util.Date. *

* The current offset of the default timezone is used as the timezone. *

* For example, if eastern daylight time is in effect at the given * date, the timezone on the east coast of the united states * translates to GMT-05:00 (EST) + 1:00 (DT offset) == GMT-04:00. */ public GDate(Date date) { // requires some date math, so ctor lives on GDateBuilder this(new GDateBuilder(date)); } /** * Constructs a GDate based on a java.util.Calendar. *

* If the calendar does not have some fields set, the same absence * of information is reflected in the GDate. Note that * java.util.GregorianCalendar fills in all fields as soon as any * are fetched, so constructing a GDate with the same calendar object * twice may result in a different GDate because of a changed calendar. * Note that org.apache.xmlbeans.XmlCalendar is stable if you re-get a set field, * so it does not have the same problem. */ public GDate(Calendar calendar) { // we must scrape the "isSet" information out before accessing anything boolean isSetYear = calendar.isSet(Calendar.YEAR); boolean isSetEra = calendar.isSet(Calendar.ERA); boolean isSetMonth = calendar.isSet(Calendar.MONTH); boolean isSetDay = calendar.isSet(Calendar.DAY_OF_MONTH); boolean isSetHourOfDay = calendar.isSet(Calendar.HOUR_OF_DAY); boolean isSetHour = calendar.isSet(Calendar.HOUR); boolean isSetAmPm = calendar.isSet(Calendar.AM_PM); boolean isSetMinute = calendar.isSet(Calendar.MINUTE); boolean isSetSecond = calendar.isSet(Calendar.SECOND); boolean isSetMillis = calendar.isSet(Calendar.MILLISECOND); boolean isSetZone = calendar.isSet(Calendar.ZONE_OFFSET); boolean isSetDst = calendar.isSet(Calendar.DST_OFFSET); if (isSetYear) { int y = calendar.get(Calendar.YEAR); if (isSetEra && calendar instanceof GregorianCalendar) if (calendar.get(Calendar.ERA) == GregorianCalendar.BC) y = -y; //1 - y; _bits |= HAS_YEAR; _CY = y; } if (isSetMonth) { _bits |= HAS_MONTH; _M = calendar.get(Calendar.MONTH) + 1; // !!note } if (isSetDay) { _bits |= HAS_DAY; _D = calendar.get(Calendar.DAY_OF_MONTH); } boolean gotTime = false; int h = 0; int m = 0; int s = 0; BigDecimal fs = _zero; if (isSetHourOfDay) { h = calendar.get(Calendar.HOUR_OF_DAY); gotTime = true; } else if (isSetHour && isSetAmPm) { h = calendar.get(Calendar.HOUR) + calendar.get(Calendar.AM_PM) * 12; gotTime = true; } if (isSetMinute) { m = calendar.get(Calendar.MINUTE); gotTime = true; } if (isSetSecond) { s = calendar.get(Calendar.SECOND); gotTime = true; } if (isSetMillis) { fs = BigDecimal.valueOf(calendar.get(Calendar.MILLISECOND), 3); gotTime = true; } if (gotTime) { _bits |= HAS_TIME; _h = h; _m = m; _s = s; _fs = fs; } if (isSetZone) { int zoneOffsetInMilliseconds = calendar.get(Calendar.ZONE_OFFSET); if (isSetDst) zoneOffsetInMilliseconds += calendar.get(Calendar.DST_OFFSET); _bits |= HAS_TIMEZONE; if (zoneOffsetInMilliseconds == 0) { _tzsign = 0; _tzh = 0; _tzm = 0; TimeZone zone = calendar.getTimeZone(); String id = zone.getID(); if (id != null && id.length() > 3) switch (id.charAt(3)) { case '+': _tzsign = 1; break; // GMT+00:00 case '-': _tzsign = -1; break; // GMT-00:00 } } else { _tzsign = (zoneOffsetInMilliseconds < 0 ? -1 : +1); zoneOffsetInMilliseconds = zoneOffsetInMilliseconds * _tzsign; _tzh = zoneOffsetInMilliseconds / 3600000; _tzm = (zoneOffsetInMilliseconds - _tzh * 3600000) / 60000; } } } /** * Constructs a GDate based on another GDateSpecification. */ public GDate(GDateSpecification gdate) { if (gdate.hasTimeZone()) { _bits |= HAS_TIMEZONE; _tzsign = gdate.getTimeZoneSign(); _tzh = gdate.getTimeZoneHour(); _tzm = gdate.getTimeZoneMinute(); } if (gdate.hasTime()) { _bits |= HAS_TIME; _h = gdate.getHour(); _m = gdate.getMinute(); _s = gdate.getSecond(); _fs = gdate.getFraction(); } if (gdate.hasDay()) { _bits |= HAS_DAY; _D = gdate.getDay(); } if (gdate.hasMonth()) { _bits |= HAS_MONTH; _M = gdate.getMonth(); } if (gdate.hasYear()) { _bits |= HAS_YEAR; _CY = gdate.getYear(); } } /* package */ static final boolean isDigit(char ch) { return ((char)(ch - '0') <= '9' - '0'); // char is unsigned } /* package */ static final boolean isSpace(char ch) { switch (ch) { case ' ': case '\t': case '\r': case '\n': return true; default: return false; } } /* package */ static final int digitVal(char ch) { return (ch - '0'); } private static final int twoDigit(CharSequence str, int index) { char ch1 = str.charAt(index); char ch2 = str.charAt(index + 1); if (!isDigit(ch1) || !isDigit(ch2)) return 100; // not two digits return digitVal(ch1) * 10 + digitVal(ch2); } /** * Returns true: all GDate instances are immutable. */ public final boolean isImmutable() { return true; } /** * Returns a combination of flags indicating the information * contained by this GDate. The five flags are * HAS_TIMEZONE, HAS_YEAR, HAS_MONTH, HAS_DAY, and HAS_TIME. */ public int getFlags() { return _bits; } /** * True if this date/time specification specifies a timezone. */ public final boolean hasTimeZone() { return ((_bits & HAS_TIMEZONE) != 0); } /** * True if this date/time specification specifies a year. */ public final boolean hasYear() { return ((_bits & HAS_YEAR) != 0); } /** * True if this date/time specification specifies a month-of-year. */ public final boolean hasMonth() { return ((_bits & HAS_MONTH) != 0); } /** * True if this date/time specification specifies a day-of-month. */ public final boolean hasDay() { return ((_bits & HAS_DAY) != 0); } /** * True if this date/time specification specifies a time-of-day. */ public final boolean hasTime() { return ((_bits & HAS_TIME) != 0); } /** * True if this date/time specification specifies a full date (year, month, day) */ public final boolean hasDate() { return ((_bits & (HAS_DAY | HAS_MONTH | HAS_YEAR)) == (HAS_DAY | HAS_MONTH | HAS_YEAR)); } /** * Gets the year. Should be a four-digit year specification. */ public final int getYear() { return _CY; } /** * Gets the month-of-year. January is 1. */ public final int getMonth() { return _M; } /** * Gets the day-of-month. The first day of each month is 1. */ public final int getDay() { return _D; } /** * Gets the hour-of-day. Midnight is 0, and 11PM is 23. */ public final int getHour() { return _h; } /** * Gets the minute-of-hour. Range from 0 to 59. */ public final int getMinute() { return _m; } /** * Gets the second-of-minute. Range from 0 to 59. */ public final int getSecond() { return _s; } /** * Gets the fraction-of-second. Range from 0 (inclusive) to 1 (exclusive). */ public final BigDecimal getFraction() { return _fs; } /** * Gets the time zone sign. For time zones east of GMT, * this is positive; for time zones west, this is negative. */ public final int getTimeZoneSign() { return _tzsign; } /** * Gets the time zone hour. * * This is always positive: for the sign, look at * getTimeZoneSign(). */ public final int getTimeZoneHour() { return _tzh; } /** * Gets the time zone minutes. * * This is always positive: for the sign, look at * getTimeZoneSign(). */ public final int getTimeZoneMinute() { return _tzm; } /** * Gets the rounded millisecond value. Range from 0 to 999 */ public int getMillisecond() { if (_fs == null) return 0; return _fs.setScale(3, BigDecimal.ROUND_DOWN).unscaledValue().intValue(); } /** * The canonical string representation. Specific moments or * times-of-day in a specified timezone are normalized to * UTC time to produce a canonical string form for them. * Other recurring time specifications keep their timezone * information. */ public String canonicalString() { ensureCanonicalString(); return _canonicalString; } /** * True if this GDate corresponds to a valid gregorian date value * in XML schema. */ public boolean isValid() { return GDateBuilder.isValidGDate(this); } /** * Returns the Julian date corresponding to this Gregorian date. * The Julian date (JD) is a continuous count of days from * 1 January 4713 BC. */ public int getJulianDate() { return GDateBuilder.julianDateForGDate(this); } /** * Retrieves the value of the current time as an {@link XmlCalendar}. *

* {@link XmlCalendar} is a subclass of {@link java.util.GregorianCalendar} * which is slightly customized to match XML schema date rules. *

* The returned {@link XmlCalendar} has only those time and date fields * set that are reflected in the GDate object. Because of the way the * {@link java.util.Calendar} contract works, any information in the isSet() vanishes * as soon as you view any unset field using get() methods. * This means that if it is important to understand which date fields * are set, you must call isSet() first before get(). */ public XmlCalendar getCalendar() { return new XmlCalendar(this); } /** * Retrieves the value of the current time as a java.util.Date * instance. */ public Date getDate() { return GDateBuilder.dateForGDate(this); } /** * Comparison to another GDate. *

    *
  • Returns -1 if this < date. (less-than) *
  • Returns 0 if this == date. (equal) *
  • Returns 1 if this > date. (greater-than) *
  • Returns 2 if this <> date. (incomparable) *
* Two instances are incomparable if they have different amounts * of information. */ public int compareToGDate(GDateSpecification datespec) { return GDateBuilder.compareGDate(this, datespec); } /** * Returns the builtin type code for the shape of the information * contained in this instance, or 0 if the * instance doesn't contain information corresponding to a * Schema type. *

* Value will be equal to * {@link SchemaType#BTC_NOT_BUILTIN}, * {@link SchemaType#BTC_G_YEAR}, * {@link SchemaType#BTC_G_YEAR_MONTH}, * {@link SchemaType#BTC_G_MONTH}, * {@link SchemaType#BTC_G_MONTH_DAY}, * {@link SchemaType#BTC_G_DAY}, * {@link SchemaType#BTC_DATE}, * {@link SchemaType#BTC_DATE_TIME}, or * {@link SchemaType#BTC_TIME}. */ public int getBuiltinTypeCode() { return GDateBuilder.btcForFlags(_bits); } /** * Adds a duration to this GDate, and returns a new GDate. */ public GDate add(GDurationSpecification duration) { GDateBuilder builder = new GDateBuilder(this); builder.addGDuration(duration); return builder.toGDate(); } /** * Adds a duration to this GDate, and returns a new GDate. */ public GDate subtract(GDurationSpecification duration) { GDateBuilder builder = new GDateBuilder(this); builder.subtractGDuration(duration); return builder.toGDate(); } /** * GDate is an immutable class, and equality is computed based * on its canonical value. */ public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof GDate)) return false; ensureCanonicalString(); return _canonicalString.equals(((GDate)obj).canonicalString()); } /** * Returns a hash code for this GDate. */ public int hashCode() { ensureCanonicalString(); return _canonicalString.hashCode(); } /** * The canonical string representation. Specific moments or * times-of-day in a specified timezone are normalized to * UTC time to produce a canonical string form for them. * Other recurring time specifications keep their timezone * information. */ private void ensureCanonicalString() { if (_canonicalString != null) return; boolean needNormalize = (hasTimeZone() && getTimeZoneSign() != 0 && hasTime() && ((hasDay() == hasMonth() && hasDay() == hasYear()))); if (!needNormalize && getFraction() != null && getFraction().scale() > 0) { BigInteger bi = getFraction().unscaledValue(); needNormalize = (bi.mod(GDateBuilder.TEN).signum() == 0); } if (!needNormalize) _canonicalString = toString(); else { GDateBuilder gdb = new GDateBuilder(this); gdb.normalize(); _canonicalString = gdb.toString(); } } /** * The natural string representation. This represents the information * that is available, including timezone. For types that correspond * to defined schema types (schemaBuiltinTypeCode() > 0), * this provides the natural lexical representation. *

* When both time and timezone are specified, this string is not * the canonical representation unless the timezone is UTC (Z) * (since the same moment in time can be expressed in different * timezones). To get a canonical string, use the canonicalString() * method. */ public String toString() { if (_string == null) _string = formatGDate(this); return _string; } private final static char[] _tensDigit = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', }; private final static char[] _onesDigit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', }; private static final int _padTwoAppend(char[] b, int i, int n) { assert(n >= 0 && n < 100); b[i] = _tensDigit[n]; b[i + 1] = _onesDigit[n]; return i + 2; } private static final int _padFourAppend(char[] b, int i, int n) { if (n < 0) { b[i++] = '-'; n = -n; } if (n >= 10000) { String s = Integer.toString(n); s.getChars(0, s.length(), b, i); return i + s.length(); } int q = n / 100; int r = n - q * 100; b[i] = _tensDigit[q]; b[i + 1] = _onesDigit[q]; b[i + 2] = _tensDigit[r]; b[i + 3] = _onesDigit[r]; return i + 4; } private static final TimeZone GMTZONE = TimeZone.getTimeZone("GMT"); private static final TimeZone[] MINUSZONE = { TimeZone.getTimeZone("GMT-00:00"), TimeZone.getTimeZone("GMT-01:00"), TimeZone.getTimeZone("GMT-02:00"), TimeZone.getTimeZone("GMT-03:00"), TimeZone.getTimeZone("GMT-04:00"), TimeZone.getTimeZone("GMT-05:00"), TimeZone.getTimeZone("GMT-06:00"), TimeZone.getTimeZone("GMT-07:00"), TimeZone.getTimeZone("GMT-08:00"), TimeZone.getTimeZone("GMT-09:00"), TimeZone.getTimeZone("GMT-10:00"), TimeZone.getTimeZone("GMT-11:00"), TimeZone.getTimeZone("GMT-12:00"), TimeZone.getTimeZone("GMT-13:00"), TimeZone.getTimeZone("GMT-14:00"), }; private static final TimeZone[] PLUSZONE = { TimeZone.getTimeZone("GMT+00:00"), TimeZone.getTimeZone("GMT+01:00"), TimeZone.getTimeZone("GMT+02:00"), TimeZone.getTimeZone("GMT+03:00"), TimeZone.getTimeZone("GMT+04:00"), TimeZone.getTimeZone("GMT+05:00"), TimeZone.getTimeZone("GMT+06:00"), TimeZone.getTimeZone("GMT+07:00"), TimeZone.getTimeZone("GMT+08:00"), TimeZone.getTimeZone("GMT+09:00"), TimeZone.getTimeZone("GMT+10:00"), TimeZone.getTimeZone("GMT+11:00"), TimeZone.getTimeZone("GMT+12:00"), TimeZone.getTimeZone("GMT+13:00"), TimeZone.getTimeZone("GMT+14:00"), }; /* package */ static final TimeZone timeZoneForGDate(GDateSpecification date) { // use a cached timezone if integral; otherwise make a new one. if (!date.hasTimeZone()) return TimeZone.getDefault(); if (date.getTimeZoneSign() == 0) return GMTZONE; if (date.getTimeZoneMinute() == 0 && date.getTimeZoneHour() <= 14 && date.getTimeZoneHour() >= 0) return date.getTimeZoneSign() < 0 ? MINUSZONE[date.getTimeZoneHour()] : PLUSZONE[date.getTimeZoneHour()]; char[] zb = new char[9]; zb[0] = 'G'; zb[1] = 'M'; zb[2] = 'T'; zb[3] = (date.getTimeZoneSign() < 0) ? '-' : '+'; GDate._padTwoAppend(zb, 4, date.getTimeZoneHour()); zb[6] = ':'; GDate._padTwoAppend(zb, 7, date.getTimeZoneMinute()); return TimeZone.getTimeZone(new String(zb)); } /* package */ static String formatGDate(GDateSpecification spec) { // We've used a char[] rather than a StringBuffer for a 4x speedup // -YY(10)YY-MM-DDTHH:MM:SS.FFFFFF+ZH:ZM // 1 + 10 + 3+ 3+ 3+ 3+ 3+1 + s + 3+ 3 = 33 + s BigDecimal fs = spec.getFraction(); char[] message = new char[33 + (fs == null ? 0 : fs.scale())]; int i = 0; if (spec.hasYear() || spec.hasMonth() || spec.hasDay()) { dmy: { if (spec.hasYear()) i = _padFourAppend(message, 0, spec.getYear()); else message[i++] = '-'; if (!(spec.hasMonth() || spec.hasDay())) break dmy; message[i++] = '-'; if (spec.hasMonth()) i = _padTwoAppend(message, i, spec.getMonth()); if (!spec.hasDay()) break dmy; message[i++] = '-'; i = _padTwoAppend(message, i, spec.getDay()); break dmy; } if (spec.hasTime()) message[i++] = 'T'; } if (spec.hasTime()) { i = _padTwoAppend(message, i, spec.getHour()); message[i++] = ':'; i = _padTwoAppend(message, i, spec.getMinute()); message[i++] = ':'; i = _padTwoAppend(message, i, spec.getSecond()); if (fs != _zero) // (optimization ~3%) { String frac = fs.toString(); int point = frac.indexOf('.'); if (point >= 0) { frac.getChars(point, frac.length(), message, i); i += frac.length() - point; } } } if (spec.hasTimeZone()) { if (spec.getTimeZoneSign() == 0) { message[i++] = 'Z'; } else { message[i++] = spec.getTimeZoneSign() > 0 ? '+' : '-'; i = _padTwoAppend(message, i, spec.getTimeZoneHour()); message[i++] = ':'; i = _padTwoAppend(message, i, spec.getTimeZoneMinute()); } } // it would be nice to use (0, i, message) ctor instead return new String(message, 0, i); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy