/** * Parses time zone: 'Z' or {+,-} followed by hh:mm * * @param data * @param sign * @exception RuntimeException */ protected void getTimeZone(String buffer, DateTimeData data, int sign, int end) throws RuntimeException { data.utc = buffer.charAt(sign); if (buffer.charAt(sign) == 'Z') { if (end > (++sign)) { throw new RuntimeException("Error in parsing time zone"); } return; } if (sign <= (end - 6)) { int negate = buffer.charAt(sign) == '-' ? -1 : 1; // parse hr int stop = ++sign + 2; data.timezoneHr = negate * parseInt(buffer, sign, stop); if (buffer.charAt(stop++) != ':') { throw new RuntimeException("Error in parsing time zone"); } // parse min data.timezoneMin = negate * parseInt(buffer, stop, stop + 2); if (stop + 2 != end) { throw new RuntimeException("Error in parsing time zone"); } if (data.timezoneHr != 0 || data.timezoneMin != 0) data.normalized = false; } else { throw new RuntimeException("Error in parsing time zone"); } if (DEBUG) { System.out.println("time[hh]=" + data.timezoneHr + " time[mm]=" + data.timezoneMin); } }
/** * Parses time hh:mm:ss.sss and time zone if any * * @param start * @param end * @param data * @exception RuntimeException */ protected void getTime(String buffer, int start, int end, DateTimeData data) throws RuntimeException { int stop = start + 2; // get hours (hh) data.hour = parseInt(buffer, start, stop); // get minutes (mm) if (buffer.charAt(stop++) != ':') { throw new RuntimeException("Error in parsing time zone"); } start = stop; stop = stop + 2; data.minute = parseInt(buffer, start, stop); // get seconds (ss) if (buffer.charAt(stop++) != ':') { throw new RuntimeException("Error in parsing time zone"); } // find UTC sign if any int sign = findUTCSign(buffer, start, end); // get seconds (ms) start = stop; stop = sign < 0 ? end : sign; data.second = parseSecond(buffer, start, stop); // parse UTC time zone (hh:mm) if (sign > 0) { getTimeZone(buffer, data, sign, end); } }
/** * Parses date CCYY-MM * * @param buffer * @param start start position * @param end end position * @param date * @exception RuntimeException */ protected int getYearMonth(String buffer, int start, int end, DateTimeData date) throws RuntimeException { if (buffer.charAt(0) == '-') { // REVISIT: date starts with preceding '-' sign // do we have to do anything with it? // start++; } int i = indexOf(buffer, start, end, '-'); if (i == -1) throw new RuntimeException("Year separator is missing or misplaced"); int length = i - start; if (length < 4) { throw new RuntimeException("Year must have 'CCYY' format"); } else if (length > 4 && buffer.charAt(start) == '0') { throw new RuntimeException( "Leading zeros are required if the year value would otherwise have fewer than four digits; otherwise they are forbidden"); } date.year = parseIntYear(buffer, i); if (buffer.charAt(i) != '-') { throw new RuntimeException("CCYY must be followed by '-' sign"); } start = ++i; i = start + 2; date.month = parseInt(buffer, start, i); return i; // fStart points right after the MONTH }
/** * Validates given date/time object accoring to W3C PR Schema [D.1 ISO 8601 Conventions] * * @param data */ protected void validateDateTime(DateTimeData data) { // REVISIT: should we throw an exception for not valid dates // or reporting an error message should be sufficient? /** XML Schema 1.1 - RQ-123: Allow year 0000 in date related types. */ if (!Constants.SCHEMA_1_1_SUPPORT && data.year == 0) { throw new RuntimeException("The year \"0000\" is an illegal year value"); } if (data.month < 1 || data.month > 12) { throw new RuntimeException("The month must have values 1 to 12"); } // validate days if (data.day > maxDayInMonthFor(data.year, data.month) || data.day < 1) { throw new RuntimeException("The day must have values 1 to 31"); } // validate hours if (data.hour > 23 || data.hour < 0) { if (data.hour == 24 && data.minute == 0 && data.second == 0) { data.hour = 0; if (++data.day > maxDayInMonthFor(data.year, data.month)) { data.day = 1; if (++data.month > 12) { data.month = 1; if (Constants.SCHEMA_1_1_SUPPORT) { ++data.year; } else if (++data.year == 0) { data.year = 1; } } } } else { throw new RuntimeException("Hour must have values 0-23, unless 24:00:00"); } } // validate if (data.minute > 59 || data.minute < 0) { throw new RuntimeException("Minute must have values 0-59"); } // validate if (data.second >= 60 || data.second < 0) { throw new RuntimeException("Second must have values 0-59"); } // validate if (data.timezoneHr > 14 || data.timezoneHr < -14) { throw new RuntimeException("Time zone should have range -14:00 to +14:00"); } else { if ((data.timezoneHr == 14 || data.timezoneHr == -14) && data.timezoneMin != 0) throw new RuntimeException("Time zone should have range -14:00 to +14:00"); else if (data.timezoneMin > 59 || data.timezoneMin < -59) throw new RuntimeException("Minute must have values 0-59"); } }
/* (non-Javadoc) * @see org.apache.xerces.xs.datatypes.XSDateTime#normalize() */ public XSDateTime normalize() { if (!normalized) { DateTimeData dt = (DateTimeData) this.clone(); dt.normalized = true; return dt; } return this; }
private void cloneDate(DateTimeData finalValue, DateTimeData tempDate) { tempDate.year = finalValue.year; tempDate.month = finalValue.month; tempDate.day = finalValue.day; tempDate.hour = finalValue.hour; tempDate.minute = finalValue.minute; tempDate.second = finalValue.second; tempDate.utc = finalValue.utc; tempDate.timezoneHr = finalValue.timezoneHr; tempDate.timezoneMin = finalValue.timezoneMin; }
/** * Resets object representation of date/time * * @param data date/time object */ protected void resetDateObj(DateTimeData data) { data.year = 0; data.month = 0; data.day = 0; data.hour = 0; data.minute = 0; data.second = 0; data.utc = 0; data.timezoneHr = 0; data.timezoneMin = 0; }
// distinguishes between identity and equality for date/time values // ie: two values representing the same "moment in time" but with different // remembered timezones are now equal but not identical. public boolean isIdentical(Object value1, Object value2) { if (!(value1 instanceof DateTimeData) || !(value2 instanceof DateTimeData)) { return false; } DateTimeData v1 = (DateTimeData) value1; DateTimeData v2 = (DateTimeData) value2; // original timezones must be the same in addition to date/time values // being 'equal' if ((v1.timezoneHr == v2.timezoneHr) && (v1.timezoneMin == v2.timezoneMin)) { return v1.equals(v2); } return false; } // isIdentical()
/** * If timezone present - normalize dateTime [E Adding durations to dateTimes] * * @param date CCYY-MM-DDThh:mm:ss+03 */ protected void normalize(DateTimeData date) { // REVISIT: we have common code in addDuration() for durations // should consider reorganizing it. // // add minutes (from time zone) int negate = -1; if (DEBUG) { System.out.println("==>date.minute" + date.minute); System.out.println("==>date.timezoneMin" + date.timezoneMin); } int temp = date.minute + negate * date.timezoneMin; int carry = fQuotient(temp, 60); date.minute = mod(temp, 60, carry); if (DEBUG) { System.out.println("==>carry: " + carry); } // add hours temp = date.hour + negate * date.timezoneHr + carry; carry = fQuotient(temp, 24); date.hour = mod(temp, 24, carry); if (DEBUG) { System.out.println("==>date.hour" + date.hour); System.out.println("==>carry: " + carry); } date.day = date.day + carry; while (true) { temp = maxDayInMonthFor(date.year, date.month); if (date.day < 1) { date.day = date.day + maxDayInMonthFor(date.year, date.month - 1); carry = -1; } else if (date.day > temp) { date.day = date.day - temp; carry = 1; } else { break; } temp = date.month + carry; date.month = modulo(temp, 1, 13); date.year = date.year + fQuotient(temp, 1, 13); if (date.year == 0 && !Constants.SCHEMA_1_1_SUPPORT) { date.year = (date.timezoneHr < 0 || date.timezoneMin < 0) ? 1 : -1; } } date.utc = 'Z'; }
/** * Parses date CCYY-MM-DD * * @param buffer * @param start start position * @param end end position * @param date * @exception RuntimeException */ protected int getDate(String buffer, int start, int end, DateTimeData date) throws RuntimeException { start = getYearMonth(buffer, start, end, date); if (buffer.charAt(start++) != '-') { throw new RuntimeException("CCYY-MM must be followed by '-' sign"); } int stop = start + 2; date.day = parseInt(buffer, start, stop); return stop; }
/** * Parses, validates and computes normalized version of gYearMonth object * * @param str The lexical representation of gYearMonth object CCYY-MM with possible time zone Z or * (-),(+)hh:mm * @return normalized date representation * @exception SchemaDateTimeException Invalid lexical representation */ protected DateTimeData parse(String str) throws SchemaDateTimeException { DateTimeData date = new DateTimeData(str, this); int len = str.length(); // get date int end = getYearMonth(str, 0, len, date); date.day = DAY; parseTimeZone(str, end, len, date); // validate and normalize validateDateTime(date); // save unnormalized values saveUnnormalized(date); if (date.utc != 0 && date.utc != 'Z') { normalize(date); } date.position = 0; return date; }
/** @param date */ protected void saveUnnormalized(DateTimeData date) { date.unNormYear = date.year; date.unNormMonth = date.month; date.unNormDay = date.day; date.unNormHour = date.hour; date.unNormMinute = date.minute; date.unNormSecond = date.second; }
public Object clone() { DateTimeData dt = new DateTimeData( this.year, this.month, this.day, this.hour, this.minute, this.second, this.utc, this.originalValue, this.normalized, this.type); dt.canonical = this.canonical; dt.position = position; dt.timezoneHr = this.timezoneHr; dt.timezoneMin = this.timezoneMin; dt.unNormYear = this.unNormYear; dt.unNormMonth = this.unNormMonth; dt.unNormDay = this.unNormDay; dt.unNormHour = this.unNormHour; dt.unNormMinute = this.unNormMinute; dt.unNormSecond = this.unNormSecond; return dt; }
/** * Compare algorithm described in dateDime (3.2.7). Duration datatype overwrites this method * * @param date1 normalized date representation of the first value * @param date2 normalized date representation of the second value * @param strict * @return less, greater, less_equal, greater_equal, equal */ protected short compareDates(DateTimeData date1, DateTimeData date2, boolean strict) { if (date1.utc == date2.utc) { return compareOrder(date1, date2); } short c1, c2; DateTimeData tempDate = new DateTimeData(null, this); if (date1.utc == 'Z') { // compare date1<=date1<=(date2 with time zone -14) // cloneDate(date2, tempDate); // clones date1 value to global temporary storage: fTempDate tempDate.timezoneHr = 14; tempDate.timezoneMin = 0; tempDate.utc = '+'; normalize(tempDate); c1 = compareOrder(date1, tempDate); if (c1 == LESS_THAN) return c1; // compare date1>=(date2 with time zone +14) // cloneDate(date2, tempDate); // clones date1 value to global temporary storage: tempDate tempDate.timezoneHr = -14; tempDate.timezoneMin = 0; tempDate.utc = '-'; normalize(tempDate); c2 = compareOrder(date1, tempDate); if (c2 == GREATER_THAN) return c2; return INDETERMINATE; } else if (date2.utc == 'Z') { // compare (date1 with time zone -14)<=date2 // cloneDate(date1, tempDate); // clones date1 value to global temporary storage: tempDate tempDate.timezoneHr = -14; tempDate.timezoneMin = 0; tempDate.utc = '-'; if (DEBUG) { System.out.println("tempDate=" + dateToString(tempDate)); } normalize(tempDate); c1 = compareOrder(tempDate, date2); if (DEBUG) { System.out.println("date=" + dateToString(date2)); System.out.println("tempDate=" + dateToString(tempDate)); } if (c1 == LESS_THAN) return c1; // compare (date1 with time zone +14)<=date2 // cloneDate(date1, tempDate); // clones date1 value to global temporary storage: tempDate tempDate.timezoneHr = 14; tempDate.timezoneMin = 0; tempDate.utc = '+'; normalize(tempDate); c2 = compareOrder(tempDate, date2); if (DEBUG) { System.out.println("tempDate=" + dateToString(tempDate)); } if (c2 == GREATER_THAN) return c2; return INDETERMINATE; } return INDETERMINATE; }
/** * Parses, validates and computes normalized version of duration object * * @param str The lexical representation of duration object PnYn MnDTnH nMnS * @param durationType * @return normalized date representation * @exception SchemaDateTimeException Invalid lexical representation */ protected DateTimeData parse(String str, int durationType) throws SchemaDateTimeException { int len = str.length(); DateTimeData date = new DateTimeData(str, this); int start = 0; char c = str.charAt(start++); if (c != 'P' && c != '-') { throw new SchemaDateTimeException(); } else { date.utc = (c == '-') ? '-' : 0; if (c == '-' && str.charAt(start++) != 'P') { throw new SchemaDateTimeException(); } } int negate = 1; // negative duration if (date.utc == '-') { negate = -1; } // at least one number and designator must be seen after P boolean designator = false; int endDate = indexOf(str, start, len, 'T'); if (endDate == -1) { endDate = len; } else if (durationType == YEARMONTHDURATION_TYPE) { throw new SchemaDateTimeException(); } // find 'Y' int end = indexOf(str, start, endDate, 'Y'); if (end != -1) { if (durationType == DAYTIMEDURATION_TYPE) { throw new SchemaDateTimeException(); } // scan year date.year = negate * parseInt(str, start, end); start = end + 1; designator = true; } end = indexOf(str, start, endDate, 'M'); if (end != -1) { if (durationType == DAYTIMEDURATION_TYPE) { throw new SchemaDateTimeException(); } // scan month date.month = negate * parseInt(str, start, end); start = end + 1; designator = true; } end = indexOf(str, start, endDate, 'D'); if (end != -1) { if (durationType == YEARMONTHDURATION_TYPE) { throw new SchemaDateTimeException(); } // scan day date.day = negate * parseInt(str, start, end); start = end + 1; designator = true; } if (len == endDate && start != len) { throw new SchemaDateTimeException(); } if (len != endDate) { // scan hours, minutes, seconds // REVISIT: can any item include a decimal fraction or only seconds? // end = indexOf(str, ++start, len, 'H'); if (end != -1) { // scan hours date.hour = negate * parseInt(str, start, end); start = end + 1; designator = true; } end = indexOf(str, start, len, 'M'); if (end != -1) { // scan min date.minute = negate * parseInt(str, start, end); start = end + 1; designator = true; } end = indexOf(str, start, len, 'S'); if (end != -1) { // scan seconds date.second = negate * parseSecond(str, start, end); start = end + 1; designator = true; } // no additional data shouls appear after last item // P1Y1M1DT is illigal value as well if (start != len || str.charAt(--start) == 'T') { throw new SchemaDateTimeException(); } } if (!designator) { throw new SchemaDateTimeException(); } return date; }
private DateTimeData addDuration(DateTimeData date, DateTimeData addto, DateTimeData duration) { // REVISIT: some code could be shared between normalize() and this method, // however is it worth moving it? The structures are different... // resetDateObj(duration); // add months (may be modified additionaly below) int temp = addto.month + date.month; duration.month = modulo(temp, 1, 13); int carry = fQuotient(temp, 1, 13); // add years (may be modified additionaly below) duration.year = addto.year + date.year + carry; // add seconds double dtemp = addto.second + date.second; carry = (int) Math.floor(dtemp / 60); duration.second = dtemp - carry * 60; // add minutes temp = addto.minute + date.minute + carry; carry = fQuotient(temp, 60); duration.minute = mod(temp, 60, carry); // add hours temp = addto.hour + date.hour + carry; carry = fQuotient(temp, 24); duration.hour = mod(temp, 24, carry); duration.day = addto.day + date.day + carry; while (true) { temp = maxDayInMonthFor(duration.year, duration.month); if (duration.day < 1) { // original duration was negative duration.day = duration.day + maxDayInMonthFor(duration.year, duration.month - 1); carry = -1; } else if (duration.day > temp) { duration.day = duration.day - temp; carry = 1; } else { break; } temp = duration.month + carry; duration.month = modulo(temp, 1, 13); duration.year = duration.year + fQuotient(temp, 1, 13); } duration.utc = 'Z'; return duration; }