in src/main/java/org/apache/xmlbeans/GDate.java [74:313]
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 (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) {
if (ExceptionUtil.isFatal(e)) {
ExceptionUtil.rethrow(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");
}
}