public boolean readDigitAndAdvance(RefInt i, int scale, int maxdigit) { if (!isValid()) return false; char c = source.charAt(index); if (c < '0' || c > '9') return false; int val = (int) c - (int) '0'; if (val > maxdigit) return false; i.value += (val * scale); advance(); return true; }
public boolean parseDateTime(String s, int part) { ParseContext context = new ParseContext(s); boolean bDatePart = (part & DateTimePart_Date) != 0; boolean bTimePart = (part & DateTimePart_Time) != 0; RefInt year = new RefInt(0); RefInt month = new RefInt(0); RefInt day = new RefInt(0); RefInt hour = new RefInt(0); RefInt minute = new RefInt(0); double second = 0; hasTZ = TZ_MISSING; offsetTZ = 0; if (bDatePart) { // parse date boolean bNegative = context.checkAndAdvance('-'); if ((part & DateTimePart_Year) != 0) { int digits = 0; RefInt temp = new RefInt(0); ; while (context.readDigitAndAdvance(temp, 1, 9)) { year.value = year.value * 10 + temp.value; digits += 1; temp.value = 0; if (digits >= 8) // overflow return false; } if (digits < 4) // inalid return false; if (digits > 4 && year.value < 10000) return false; if (bNegative) year.value = -year.value; } if ((part & (DateTimePart_Month | DateTimePart_Day)) != 0) { if (!context.checkAndAdvance('-')) return false; if ((part & DateTimePart_Month) != 0) { if (!context.readDigitAndAdvance(month, 10, 1)) return false; if (!context.readDigitAndAdvance(month, 1, month.value < 10 ? 9 : 2)) return false; if (month.value == 0) return false; } if ((part & DateTimePart_Day) != 0) { if (!context.checkAndAdvance('-')) return false; int maxFirstDigit = month.value != 2 ? 3 : 2; // complicate things by making them complicated. if (!context.readDigitAndAdvance(day, 10, maxFirstDigit)) return false; if (!context.readDigitAndAdvance(day, 1, 9)) return false; if (day.value == 0 || day.value > 31) return false; if ((part & DateTimePart_Month) != 0) { boolean b1 = month.value <= 7; boolean b2 = (month.value & 1) == 0; // month 1, 3, 5, 7, 8, 10, 12 if (b1 == b2 && day.value > 30) return false; // february. if (month.value == 2 && day.value > 29) return false; // leap years. if (month.value == 2 && (part & DateTimePart_Year) != 0 && (year.value % 4 != 0 || year.value % 100 == 0) && year.value % 400 != 0 && day.value > 28) return false; } } } if (bTimePart) { // a 'T' must follow if (!context.checkAndAdvance('T')) return false; } } if (bTimePart) { // check format here // hour from 0 to 2 if (!context.readDigitAndAdvance(hour, 10, 2)) return false; if (!context.readDigitAndAdvance(hour, 1, hour.value < 20 ? 9 : 4)) return false; if (!context.checkAndAdvance(':')) return false; int maxFirstDigit = hour.value == 24 ? 0 : 5; int maxSecondDigit = hour.value == 24 ? 0 : 9; if (!context.readDigitAndAdvance(minute, 10, maxFirstDigit)) return false; if (!context.readDigitAndAdvance(minute, 1, maxSecondDigit)) return false; if (!context.checkAndAdvance(':')) return false; RefInt secondInt = new RefInt(0); if (!context.readDigitAndAdvance(secondInt, 10, maxFirstDigit)) return false; if (!context.readDigitAndAdvance(secondInt, 1, maxSecondDigit)) return false; second = secondInt.value; if (context.checkAndAdvance('.')) { // fraction. do whatever seems fit. RefInt val = new RefInt(0); int digits = 0; while (context.readDigitAndAdvance(val, 1, 9)) { val.value *= 10; digits += 1; if (digits >= 8) // precision loss - ignore break; } if (digits == 0) return false; second += val.value * Math.pow(10.0, -digits - 1); // skip any further digits. while (context.readDigitAndAdvance(val, 0, 9)) ; } } // timezone if (context.checkAndAdvance('Z')) { // timezone specified, it is UTC. hasTZ = TZ_UTC; offsetTZ = 0; } else if (context.check('+') || context.check('-')) { // timezone offset, in hour:minute format boolean bNegative = context.check('-'); context.advance(); // do not check the hour part, for those who are obscure. RefInt temp = new RefInt(0); if (!context.readDigitAndAdvance(temp, 600, 9)) return false; if (!context.readDigitAndAdvance(temp, 60, 9)) return false; if (!context.checkAndAdvance(':')) return false; if (!context.readDigitAndAdvance(temp, 10, 5)) return false; if (!context.readDigitAndAdvance(temp, 1, 9)) return false; hasTZ = TZ_OFFSET; offsetTZ = bNegative ? -temp.value : temp.value; } if (context.isValid()) return false; if (year.value <= 0) year.value = 1; if (month.value == 0) month.value = 1; if (day.value == 0) day.value = 1; // if hour is 24 add a day. if (hour.value == 24) { hour.value = 0; Calendar c = Calendar.getInstance(); c.set(year.value, month.value - 1, day.value); c.add(Calendar.DATE, 1); year.value = c.get(Calendar.YEAR); month.value = c.get(Calendar.MONTH) + 1; day.value = c.get(Calendar.DAY_OF_MONTH); } setInternalValues( year.value, month.value, day.value, hour.value, minute.value, (int) second, ((second * 1000) % 1000) / 1000, hasTZ, offsetTZ); return true; }