#include "../../config/pathan_config.h" /** Copyright (c) 2001, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include "ATDateOrDerivedImpl.hpp" #include #include #include #include #include #include #include #include "../../exceptions/XPath2TypeCastException.hpp" #include #include #include #include #include #include #include #include #include #include // for INT_MIN and INT_MAX #include // for atoi #include #include "../../utils/DateUtils.hpp" #include "../../utils/Date.hpp" ATDateOrDerivedImpl:: ATDateOrDerivedImpl(const XMLCh* typeURI, const XMLCh* typeName, const XMLCh* value, XPath2MemoryManager* memMgr, const DynamicContext* context): ATDateOrDerived(memMgr), _typeName(typeName), _typeURI(typeURI) { setDate(value, context); } // private constructor for internal use() ATDateOrDerivedImpl::ATDateOrDerivedImpl(const XMLCh* typeURI, const XMLCh* typeName, const ATDecimalOrDerived* YY, const ATDecimalOrDerived* MM, const ATDecimalOrDerived* DD, const Timezone* timezone, bool hasTimezone, XPath2MemoryManager* memMgr) : ATDateOrDerived(memMgr), _YY(YY), _MM(MM), _DD(DD), _timezone(timezone), _hasTimezone(hasTimezone), _typeName(typeName), _typeURI(typeURI) { } /* Get the name of the primitive type (basic type) of this type * (ie "decimal" for xs:decimal) */ const XMLCh* ATDateOrDerivedImpl::getPrimitiveTypeName() const { return this->getPrimitiveName(); } const XMLCh* ATDateOrDerivedImpl::getPrimitiveName() { return XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DATE; } /* Get the name of this type (ie "integer" for xs:integer) */ const XMLCh* ATDateOrDerivedImpl::getTypeName() const { return _typeName; } /* Get the namespace URI for this type */ const XMLCh* ATDateOrDerivedImpl::getTypeURI() const { return _typeURI; } AnyAtomicType::AtomicObjectType ATDateOrDerivedImpl::getTypeIndex() { return AnyAtomicType::DATE; } /* If possible, cast this type to the target type */ const AnyAtomicType* ATDateOrDerivedImpl::castAsInternal(const XMLCh* targetURI, const XMLCh* targetType, const DynamicContext* context) const { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); const XMLCh doubleZero[] = { XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0, XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0, XERCES_CPP_NAMESPACE_QUALIFIER chNull }; const DatatypeFactory* target = context->getDatatypeFactory(targetURI, targetType); AnyAtomicType::AtomicObjectType targetIndex = target->getPrimitiveTypeIndex(); switch (targetIndex) { case DATE_TIME: { if(this->_YY->asMAPM() > 9999) { buf.set(this->_YY->asString(context)); } else { buf.set(this->_YY->asString(4, context)); //pad to 4 digits } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(this->_MM->asString(2, context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(this->_DD->asString(2, context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buf.append(doubleZero); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chColon); buf.append(doubleZero); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chColon); buf.append(doubleZero); // Add timezone if exists if (this->_hasTimezone) { buf.append(this->_timezone->asString(context)); } return DatatypeFactory::STR2AT::createDateTimeOrDerived(context->getMemoryManager(), targetURI, targetType, buf.getRawBuffer(), context); } case G_DAY: { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(this->_DD->asString(2, context)); if (this->_hasTimezone) { buf.append(this->_timezone->asString(context)); } return DatatypeFactory::STR2AT::createGDayOrDerived(context->getMemoryManager(), targetURI, targetType, buf.getRawBuffer(), context); } case G_MONTH_DAY: { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(this->_MM->asString(2, context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(this->_DD->asString(2, context)); if (this->_hasTimezone) { buf.append(this->_timezone->asString(context)); } return DatatypeFactory::STR2AT::createGMonthDayOrDerived(context->getMemoryManager(), targetURI, targetType, buf.getRawBuffer(), context); } case G_MONTH: { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(this->_MM->asString(2, context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); if (this->_hasTimezone) { buf.append(this->_timezone->asString(context)); } return DatatypeFactory::STR2AT::createGMonthOrDerived(context->getMemoryManager(), targetURI, targetType, buf.getRawBuffer(), context); } case G_YEAR_MONTH: { if(this->_YY->asMAPM() > 9999) { buf.set(this->_YY->asString(context)); } else { buf.set(this->_YY->asString(4, context)); //pad to 4 digits } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(this->_MM->asString(2, context)); if (this->_hasTimezone) { buf.append(this->_timezone->asString(context)); } return DatatypeFactory::STR2AT::createGYearMonthOrDerived(context->getMemoryManager(), targetURI, targetType, buf.getRawBuffer(), context); } case G_YEAR: { if(this->_YY->asMAPM() > 9999) { buf.set(this->_YY->asString(context)); } else { buf.set(this->_YY->asString(4, context)); //pad to 4 digits } if (this->_hasTimezone) { buf.append(this->_timezone->asString(context)); } return DatatypeFactory::STR2AT::createGYearOrDerived(context->getMemoryManager(), targetURI, targetType, buf.getRawBuffer(), context); } case ANY_SIMPLE_TYPE: case UNTYPED_ATOMIC: //anySimpleType and untypedAtomic follow the same casting rules as string. case STRING: { return DatatypeFactory::STR2AT::createDerivedFromAtomicType(context->getMemoryManager(), targetURI, targetType, this->asLexicalString(context), context); } default: { return AnyAtomicType::castAsInternal(targetURI, targetType, context); } } } /* returns the XMLCh* (canonical) representation of this type */ const XMLCh* ATDateOrDerivedImpl::asString(const DynamicContext* context) const { // since we actually store the date in its lexical representation all we have to // do is ask a normalized copy of this for it's lexical string and that will be our canonical const ATDateOrDerivedImpl* canonicalDate = this; if (_hasTimezone) { canonicalDate = (const ATDateOrDerivedImpl*) this->normalize(context); } return canonicalDate->asLexicalString(context); } /* returns the XMLCh* (lexical := prefix:localname) representation of this type */ const XMLCh* ATDateOrDerivedImpl::asLexicalString(const DynamicContext* context) const { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buffer(1023, context->getMemoryManager()); if(this->_YY->asMAPM() > 9999 || this->_YY->asMAPM() < -9999) { buffer.set(this->_YY->asString(context)); } else { buffer.set(this->_YY->asString(4, context)); //pad to 4 digits } buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buffer.append(this->_MM->asString(2, context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buffer.append(this->_DD->asString(2, context)); // Add timezone if exists if (this->_hasTimezone) { buffer.append(this->_timezone->asString(context)); } return context->getMemoryManager()->getPooledString(buffer.getRawBuffer()); } /* returns true if the two objects represent the same date, * false otherwise */ bool ATDateOrDerivedImpl::equals(const AnyAtomicType* target, const DynamicContext* context) const { if(this->getPrimitiveTypeIndex() != target->getPrimitiveTypeIndex()) { DSLthrow(IllegalArgumentException,X("ATDateOrDerivedImpl::equals"), X("Equality operator for given types not supported")); } ATDateOrDerivedImpl* targetDate = (ATDateOrDerivedImpl*)target; if ( _hasTimezone == targetDate->_hasTimezone ) { // must be in the same state return ( (!_hasTimezone || _timezone->equals(targetDate->_timezone)) && this->_YY->equals(targetDate->_YY, context) && this->_MM->equals(targetDate->_MM, context) && this->_DD->equals(targetDate->_DD, context) ); } else { return false; } } /** Releases the memory used by this Item */ void ATDateOrDerivedImpl::release() const { //TODO needs to check for ownership before releasing! getMemoryManager()->deallocate((void*)this); } /** * Returns true i and only if this date is greater than the given date. * The order relation on date values is based on their normalized values * ie. if a date doesn't have an explicit timezone then the implicit one from the context is assumed. */ bool ATDateOrDerivedImpl::greaterThan(const ATDateOrDerived* other, const DynamicContext* context) const { // ****************************************** // method #2, which mimics code in Date time.. somewhat cut and paste of code const ATDateOrDerived* myDateCopy = this; const ATDateOrDerived* otherDateCopy = other; if(myDateCopy->hasTimezone() || otherDateCopy->hasTimezone()) { myDateCopy=this->normalize(context); otherDateCopy=other->normalize(context); } // avoid doing too many comparisons if(myDateCopy->getYears()->greaterThan(otherDateCopy->getYears(), context)) return true; else if(myDateCopy->getYears()->equals(otherDateCopy->getYears(), context)) { if(myDateCopy->getMonths()->greaterThan(otherDateCopy->getMonths(), context)) return true; else if(myDateCopy->getMonths()->equals(otherDateCopy->getMonths(), context)) { if(myDateCopy->getDays()->greaterThan(otherDateCopy->getDays(), context)) return true; else if(myDateCopy->getDays()->equals(otherDateCopy->getDays(), context) && myDateCopy->getTimezone()!=NULL && otherDateCopy->getTimezone()!=NULL) return myDateCopy->getTimezone()->lessThan(otherDateCopy->getTimezone()); } } return false; } /** * Returns true if and only if this date is less than the given date. * The order relation on date values is based on their normalized values * ie. if a date doesn't have an explicit timezone then the implicit one from the context is assumed. */ bool ATDateOrDerivedImpl::lessThan(const ATDateOrDerived* other, const DynamicContext* context) const { const ATDateOrDerived* myDateCopy = this; const ATDateOrDerived* otherDateCopy = other; if(myDateCopy->hasTimezone() || otherDateCopy->hasTimezone()) { myDateCopy=this->normalize(context); otherDateCopy=other->normalize(context); } if (myDateCopy->getYears()->lessThan(otherDateCopy->getYears(), context)) return true; else if(myDateCopy->getYears()->equals(otherDateCopy->getYears(), context)) { if(myDateCopy->getMonths()->lessThan(otherDateCopy->getMonths(), context)) return true; else if(myDateCopy->getMonths()->equals(otherDateCopy->getMonths(), context)) { if(myDateCopy->getDays()->lessThan(otherDateCopy->getDays(), context)) return true; else if(myDateCopy->getDays()->equals(otherDateCopy->getDays(), context) && myDateCopy->getTimezone()!=NULL && otherDateCopy->getTimezone()!=NULL) return myDateCopy->getTimezone()->greaterThan(otherDateCopy->getTimezone()); } } return false; } /** * Returns an integer representing the year component of this object */ const ATDecimalOrDerived* ATDateOrDerivedImpl::getYears() const { return _YY; } /** * Returns an integer representing the month component of this object */ const ATDecimalOrDerived* ATDateOrDerivedImpl::getMonths() const { return _MM; } /** * Returns an integer representing the day component of this object */ const ATDecimalOrDerived* ATDateOrDerivedImpl::getDays() const { return _DD; } /** * Returns the timezone associated with this object, or * null, if the timezone is not set */ const Timezone* ATDateOrDerivedImpl::getTimezone() const { return _timezone; } /** * Returns true if the timezone is defined for this object, false otherwise. */ bool ATDateOrDerivedImpl::hasTimezone() const { return _hasTimezone; } /**mrg@decisionsoft.com * Setter for timezone. Overrides the current timezone. (Not to be * confused with addTimezone(). If passed NULL, timezone is removed (unset) */ const ATDateOrDerived* ATDateOrDerivedImpl::setTimezone(const Timezone* timezone, const DynamicContext* context) const { bool hasTimezone = timezone == 0 ? false : true; return new (context->getMemoryManager()) ATDateOrDerivedImpl(this->_typeURI, this->_typeName, this->_YY, this->_MM, this->_DD, timezone, hasTimezone, context->getMemoryManager()); } /** * Returns an ATDateOrDerived with a timezone added to it */ const ATDateOrDerived* ATDateOrDerivedImpl::addTimezone(const ATDurationOrDerived* timezone, const DynamicContext* context) const { // if we have a timezone, then ignore it, and replace it with the one given // if we don't have one, then we set it const Timezone* tz = new (context->getMemoryManager()) Timezone(timezone, context); return new (context->getMemoryManager()) ATDateOrDerivedImpl(this->getTypeURI(), this->getTypeName(), _YY, _MM, _DD, tz, true, context->getMemoryManager()); } /** * Returns a date with the given yearMonthDuration added to it */ const ATDateOrDerived* ATDateOrDerivedImpl::addYearMonthDuration(const ATDurationOrDerived* yearMonth, const DynamicContext* context) const { if(!yearMonth->isYearMonthDuration()) { DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::addYearMonthDuration"), X("addYearMonthDuration for given type not supported")); } MAPM year=yearMonth->getYears()->asMAPM(); MAPM month=yearMonth->getMonths()->asMAPM(); if(yearMonth->isNegative()) { year=year.neg(); month=month.neg(); } return this->addYearMonthDuration(year, month, context); } /** * Returns a date with the given yearMonthDuration added to it */ const ATDateOrDerived* ATDateOrDerivedImpl::addYearMonthDuration(MAPM years, MAPM months, const DynamicContext* context) const { const ATDateOrDerived* date = this; if (_hasTimezone) { date = this->normalize(context); } MAPM totalMonths = date->getMonths()->asMAPM()+months-MM_One; MAPM MM = DateUtils::modulo(totalMonths, 12) + MM_One; MAPM carry = (totalMonths/12).floor(); MAPM finalYears = carry + years + date->getYears()->asMAPM(); assert(!date->getYears()->isZero()); // We should never have _YY = 0000 MAPM YY; // Fix year 0000 problem if ( finalYears <= MM_Zero && date->getYears()->isPositive()) { YY = finalYears - MM_One; } else if (finalYears >= MM_Zero && date->getYears()->isNegative()) { YY = finalYears + MM_One; } else { YY = finalYears; } return new (context->getMemoryManager()) ATDateOrDerivedImpl(date->getTypeURI(), date->getTypeName(), DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), YY, context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), MM, context), _DD, date->getTimezone(), date->hasTimezone(), context->getMemoryManager()); } /** * Returns a date with the given dayTimeDuration added to it */ const ATDateOrDerived* ATDateOrDerivedImpl::addDayTimeDuration(const ATDurationOrDerived* dayTime, const DynamicContext* context) const { if(!dayTime->isDayTimeDuration()) { DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::addDayTimeDuration"), X("addDayTimeDuration for given type not supported")); } if(dayTime->isNegative()) { return subtractDays(dayTime->getDays(), context); } else { return addDays(dayTime->getDays(), context); } } /** * Returns a date with the given yearMonthDuration subtracted from it */ const ATDateOrDerived* ATDateOrDerivedImpl::subtractYearMonthDuration(const ATDurationOrDerived* yearMonth, const DynamicContext* context) const { if(!yearMonth->isYearMonthDuration()) { DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::subtractYearMonthDuration"), X("subtractYearMonthDuration for given type not supported")); } MAPM year=yearMonth->getYears()->asMAPM(); MAPM month=yearMonth->getMonths()->asMAPM(); if(!yearMonth->isNegative()) { year=year.neg(); month=month.neg(); } return this->addYearMonthDuration(year, month, context); } /** * Returns a date with the given dayTimeDuration subtracted from it */ const ATDateOrDerived* ATDateOrDerivedImpl::subtractDayTimeDuration(const ATDurationOrDerived* dayTime, const DynamicContext* context) const { if(!dayTime->isDayTimeDuration()) { DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::subtractDayTimeDuration"), X("subtractDayTimeDuration for given type not supported")); } if(dayTime->isNegative()) { return addDays(dayTime->getDays(), context); } else { return subtractDays(dayTime->getDays(), context); } } const ATDateOrDerived* ATDateOrDerivedImpl::addDays(MAPM days, const DynamicContext* context) const { const ATDateOrDerived* normDate = normalize(context); Date thisDate = Date(asInt(normDate->getDays()->asMAPM()), asInt(normDate->getMonths()->asMAPM()),asInt(normDate->getYears()->asMAPM())); Date sumDate = thisDate + asInt(days); return new (context->getMemoryManager()) ATDateOrDerivedImpl(this->_typeURI, this->_typeName, DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), sumDate.Year(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Month(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Day(), context), 0, false, // no timezone since normalized context->getMemoryManager()); } const ATDateOrDerived* ATDateOrDerivedImpl::addDays(const ATDecimalOrDerived* days, const DynamicContext* context) const { return addDays(days->asMAPM(),context); } const ATDateOrDerived* ATDateOrDerivedImpl::subtractDays(MAPM days, const DynamicContext* context) const { const ATDateOrDerived* normDate = normalize(context); Date thisDate = Date(asInt(normDate->getDays()->asMAPM()), asInt(normDate->getMonths()->asMAPM()),asInt(normDate->getYears()->asMAPM())); Date sumDate = operator-(thisDate, (long int)asInt(days)); return new (context->getMemoryManager()) ATDateOrDerivedImpl(this->_typeURI, this->_typeName, DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), sumDate.Year(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Month(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Day(), context), 0, false, // no timezone since normalized context->getMemoryManager()); } const ATDateOrDerived* ATDateOrDerivedImpl::subtractDays(const ATDecimalOrDerived* days, const DynamicContext* context) const { return subtractDays(days->asMAPM(),context); } /** * Returns a dayTimeDuration corresponding to the difference between this * and the given ATDateOrDerived* */ const ATDurationOrDerived* ATDateOrDerivedImpl::subtractDate(const ATDateOrDerived* date, const DynamicContext* context) const { // normalize both dates first const ATDateOrDerived* thisDate = this->normalize(context); const ATDateOrDerived* otherDate = date->normalize(context); // this as julian Date dateThis = Date(asInt(thisDate->getDays()->asMAPM()), asInt(thisDate->getMonths()->asMAPM()), asInt(thisDate->getYears()->asMAPM())); // date as julian Date dateOther = Date(asInt(otherDate->getDays()->asMAPM()), asInt(otherDate->getMonths()->asMAPM()), asInt(otherDate->getYears()->asMAPM())); // return the difference as a dayTimeDuration // Returns the number of days long diff = dateThis - dateOther; const ATDecimalOrDerived* dateDiff = (const ATDecimalOrDerived*)DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), diff, context); bool isNegative = dateDiff->isNegative(); const ATDecimalOrDerived* endDiff = dateDiff; if(isNegative) { endDiff = (const ATDecimalOrDerived*)dateDiff->invert(context); } XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buffer(1023, context->getMemoryManager()); if(isNegative) { buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); } buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buffer.append(endDiff->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_D); return DatatypeFactory::STR2AT::createDayTimeDuration(context->getMemoryManager(), buffer.getRawBuffer(), context); } AnyAtomicType::AtomicObjectType ATDateOrDerivedImpl::getPrimitiveTypeIndex() const { return this->getTypeIndex(); } const ATDateOrDerived* ATDateOrDerivedImpl::normalize(const DynamicContext* context) const { const Timezone* timezone; if (!_hasTimezone) { timezone = new (context->getMemoryManager()) Timezone(context->getImplicitTimezone(), context); } else { timezone = this->_timezone; } // Minutes MAPM temp = -timezone->getMinutes(); MAPM carry = (temp / DateUtils::g_minutesPerHour).floor(); // Hours temp = -timezone->getHours() + carry; carry = (temp / DateUtils::g_hoursPerDay).floor(); Date thisDate = Date(asInt(_DD->asMAPM()), asInt(_MM->asMAPM()), asInt(_YY->asMAPM())); Date sumDate = thisDate + asInt(carry); return new (context->getMemoryManager()) ATDateOrDerivedImpl(this->_typeURI, this->_typeName, DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), sumDate.Year(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Month(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Day(), context), new (context->getMemoryManager()) Timezone(0, 0), true, // timezone set to UTC context->getMemoryManager()); } ////////////////////////////////////// // Horrible Hack to make Dates // // work for now. Loss of Precision! // ////////////////////////////////////// int ATDateOrDerivedImpl::asInt(MAPM num) const { if(num < INT_MIN || num > INT_MAX) { DSLthrow(XPath2TypeCastException, X("ATDateOrDerivedImpl::asInt"), X("Invalid representation of an int")); } else { char out_string[256]; num.toIntegerString(out_string); return atoi(out_string); } } void ATDateOrDerivedImpl::setDate(const XMLCh* const date, const DynamicContext* context) { unsigned int length = XERCES_CPP_NAMESPACE_QUALIFIER XMLString::stringLen(date); if(date == 0) { DSLthrow(XPath2TypeCastException,X("ATDateOrDerived::setDate"), X("Invalid representation of date")); } // State variables etc. bool gotDigit = false; unsigned int pos = 0; long int tmpnum = 0; unsigned int numDigit = 0; bool negative = false; // defaulting values MAPM YY = 1; MAPM MM = 0; MAPM DD = 0; _hasTimezone = false; bool zonepos = false; int zonehh = 0; int zonemm = 0; int state = 0 ; // 0 = year / 1 = month / 2 = day // 6 = timezonehour / 7 = timezonemin XMLCh tmpChar; bool wrongformat = false; if ( length > 0 && date[0] == L'-' ) { negative = true; pos = 1; }else{ pos = 0; } while ( ! wrongformat && pos < length) { tmpChar = date[pos]; pos++; switch(tmpChar) { case 0x0030: case 0x0031: case 0x0032: case 0x0033: case 0x0034: case 0x0035: case 0x0036: case 0x0037: case 0x0038: case 0x0039: { numDigit ++; tmpnum *= 10; tmpnum += static_cast(tmpChar - 0x0030); gotDigit = true; break; } case L'-' : { if ( gotDigit ) { if (state == 0 && numDigit >= 4) { YY = tmpnum; if (negative) { YY = YY * -1; } tmpnum = 0; gotDigit = false; numDigit = 0 ; } else if (state == 1 && numDigit == 2) { MM = tmpnum; tmpnum = 0; gotDigit = false; numDigit = 0 ; } else if ( state == 2 && numDigit == 2) { DD += tmpnum; gotDigit = false; zonepos = false; _hasTimezone = true; tmpnum = 0; state = 5; numDigit = 0 ; } else { wrongformat = true; } state ++; } break; } case L':' : { if (gotDigit && state == 6 && numDigit == 2) { zonehh = tmpnum; tmpnum = 0; gotDigit = false; state ++; numDigit = 0 ; }else { wrongformat = true; } break; } case L'+' : { if ( gotDigit && state == 2 && numDigit == 2) { DD += tmpnum; state = 6; gotDigit = false; zonepos = true; _hasTimezone = true; tmpnum = 0; numDigit = 0 ; } else { wrongformat = true; } break; } case L'Z' : { if (gotDigit && state == 2 && numDigit == 2) { DD += tmpnum; state = 8; // final state _hasTimezone = true; gotDigit = false; tmpnum = 0; numDigit = 0 ; } else { wrongformat = true; } break; } default: wrongformat = true; } } if (gotDigit) { if ( gotDigit && state == 7 && numDigit == 2) { zonemm = tmpnum; _hasTimezone = true; }else if ( gotDigit && state == 2 && numDigit == 2) { DD += tmpnum; }else { wrongformat = true; } } // Verify date if ( MM > 12 || YY == 0 || zonehh > 24 || zonemm > 59 ) { wrongformat = true; } else if ( DD > 28) { bool leapyear = false; // the mod operator on mapm is called rem if ( YY.rem(400) == 0 || ( (YY.rem(100) != 0 ) && (YY.rem(4) == 0 ) ) ) leapyear = true; if ( (MM == 2 && leapyear && DD > 29 ) || (MM == 2 && !leapyear && DD > 28 ) || ( ( MM == 1 || MM == 3 || MM == 5 || MM == 7 || MM == 8 || MM == 10 || MM ==12 ) && DD > 31 ) || ( (MM == 4 || MM == 6 || MM == 9 || MM == 11) && DD > 30 ) || zonehh > 24 || zonemm > 60 || YY == 0) { wrongformat = true; } } if ( wrongformat) { DSLthrow(XPath2TypeCastException,X("ATDateOrDerivedImpl::setDate"), X("Invalid representation of date")); } // Create Timezone object, clean this up in future if (zonepos == false) { zonehh *= -1; zonemm *= -1; } _timezone = new (context->getMemoryManager()) Timezone(zonehh, zonemm); _DD = DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), DD, context); _MM = DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), MM, context); _YY = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), YY, context); }