#include "../../config/pathan_config.h" /** Copyright (c) 2001, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include "ATDateTimeOrDerivedImpl.hpp" #include #include #include #include #include #include #include #include "../../exceptions/XPath2TypeCastException.hpp" #include #include #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" ATDateTimeOrDerivedImpl:: ATDateTimeOrDerivedImpl(const XMLCh* typeURI, const XMLCh* typeName, const XMLCh* value, XPath2MemoryManager* memMgr, const DynamicContext* context): ATDateTimeOrDerived(memMgr), _typeName(typeName), _typeURI(typeURI) { setDateTime(value, context); } // private constructor for internal use ATDateTimeOrDerivedImpl::ATDateTimeOrDerivedImpl(const XMLCh* typeURI, const XMLCh* typeName, const ATDecimalOrDerived* YY, const ATDecimalOrDerived* MM, const ATDecimalOrDerived* DD, const ATDecimalOrDerived* hh, const ATDecimalOrDerived* mm, const ATDecimalOrDerived* ss, const Timezone* timezone, bool hasTimezone, XPath2MemoryManager* memMgr) : ATDateTimeOrDerived(memMgr), _YY(YY), _MM(MM), _DD(DD), _hh(hh), _mm(mm), _ss(ss), _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* ATDateTimeOrDerivedImpl::getPrimitiveTypeName() const { return this->getPrimitiveName(); } const XMLCh* ATDateTimeOrDerivedImpl::getPrimitiveName() { return XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DATETIME; } /* Get the name of this type (ie "integer" for xs:integer) */ const XMLCh* ATDateTimeOrDerivedImpl::getTypeName() const { return _typeName; } /* Get the namespace URI for this type */ const XMLCh* ATDateTimeOrDerivedImpl::getTypeURI() const { return _typeURI; } AnyAtomicType::AtomicObjectType ATDateTimeOrDerivedImpl::getTypeIndex() { return AnyAtomicType::DATE_TIME; } /* If possible, cast this type to the target type */ const AnyAtomicType* ATDateTimeOrDerivedImpl::castAsInternal(const XMLCh* targetURI, const XMLCh* targetType, const DynamicContext* context) const { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); const DatatypeFactory* target = context->getDatatypeFactory(targetURI, targetType); AnyAtomicType::AtomicObjectType targetIndex = target->getPrimitiveTypeIndex(); switch (targetIndex) { case DATE: { 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)); // Add timezone if exists if (this->_hasTimezone) { buf.append(this->_timezone->asString(context)); } return DatatypeFactory::STR2AT::createDateOrDerived(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 TIME: { buf.append(this->_hh->asString(2, context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chColon); buf.append(this->_mm->asString(2, context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chColon); if(this->_ss->lessThan(DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), 10, context), context)) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0); } buf.append(this->_ss->asString(context)); if (this->_hasTimezone) { buf.append(this->_timezone->asString(context)); } return DatatypeFactory::STR2AT::createTimeOrDerived(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* ATDateTimeOrDerivedImpl::asString(const DynamicContext* context) const { // since we actually store the dateTime 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 ATDateTimeOrDerivedImpl* canonicalDT = this; if (_hasTimezone) { canonicalDT = (const ATDateTimeOrDerivedImpl*) this->normalize(context); } return canonicalDT->asLexicalString(context); } const XMLCh* ATDateTimeOrDerivedImpl::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)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buffer.append(this->_hh->asString(2, context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chColon); buffer.append(this->_mm->asString(2, context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chColon); if(this->_ss->asMAPM() < MM_Ten) { // TODO: deal with precision in a better way! buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0); } if (this->_ss->equals(this->_ss->floor(context), context)) { const ATDecimalOrDerived* int_ss = (const ATDecimalOrDerived*) this->_ss->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); buffer.append(int_ss->asString(context)); } else { buffer.append(this->_ss->asString(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 ATDateTimeOrDerivedImpl::equals(const AnyAtomicType* target, const DynamicContext* context) const { if(this->getPrimitiveTypeIndex() != target->getPrimitiveTypeIndex()) { DSLthrow(IllegalArgumentException,X("ATDateTimeOrDerivedImpl::equals"), X("Equality operator for given types not supported")); } const ATDateTimeOrDerived* myDateTimeCopy = this; const ATDateTimeOrDerived* otherDateTimeCopy = (const ATDateTimeOrDerived*)target; if(myDateTimeCopy->hasTimezone() || otherDateTimeCopy->hasTimezone()) { myDateTimeCopy = myDateTimeCopy->normalize(context); otherDateTimeCopy = otherDateTimeCopy->normalize(context); } return ( myDateTimeCopy->getYears()->equals(otherDateTimeCopy->getYears(), context) && myDateTimeCopy->getMonths()->equals(otherDateTimeCopy->getMonths(), context) && myDateTimeCopy->getDays()->equals(otherDateTimeCopy->getDays(), context) && myDateTimeCopy->getHours()->equals(otherDateTimeCopy->getHours(), context) && myDateTimeCopy->getMinutes()->equals(otherDateTimeCopy->getMinutes(), context) && myDateTimeCopy->getSeconds()->equals(otherDateTimeCopy->getSeconds(), context) ); } /** Releases the memory used by this Item */ void ATDateTimeOrDerivedImpl::release() const { //TODO needs to check for ownership before releasing! getMemoryManager()->deallocate((void*)this); } /** * Returns true if and only if this date is greater than the given date. * The order relation on date values is the order relation on their * starting instants. */ bool ATDateTimeOrDerivedImpl::greaterThan(const ATDateTimeOrDerived* other, const DynamicContext* context) const { const ATDateTimeOrDerived* myDateTimeCopy = this; const ATDateTimeOrDerived* otherDateTimeCopy = (const ATDateTimeOrDerived*)other; if(myDateTimeCopy->hasTimezone() || otherDateTimeCopy->hasTimezone()) { myDateTimeCopy = myDateTimeCopy->normalize(context); otherDateTimeCopy = otherDateTimeCopy->normalize(context); } if(myDateTimeCopy->getYears()->greaterThan(otherDateTimeCopy->getYears(), context)) return true; else if(myDateTimeCopy->getYears()->lessThan(otherDateTimeCopy->getYears(), context)) return false; if(myDateTimeCopy->getMonths()->greaterThan(otherDateTimeCopy->getMonths(), context)) return true; else if(myDateTimeCopy->getMonths()->lessThan(otherDateTimeCopy->getMonths(), context)) return false; if(myDateTimeCopy->getDays()->greaterThan(otherDateTimeCopy->getDays(), context)) return true; else if(myDateTimeCopy->getDays()->lessThan(otherDateTimeCopy->getDays(), context)) return false; if(myDateTimeCopy->getHours()->greaterThan(otherDateTimeCopy->getHours(), context)) return true; else if(myDateTimeCopy->getHours()->lessThan(otherDateTimeCopy->getHours(), context)) return false; if(myDateTimeCopy->getMinutes()->greaterThan(otherDateTimeCopy->getMinutes(), context)) return true; else if(myDateTimeCopy->getMinutes()->lessThan(otherDateTimeCopy->getMinutes(), context)) return false; return myDateTimeCopy->getSeconds()->greaterThan(otherDateTimeCopy->getSeconds(), context); } /** * Returns true if and only if this date is less than the given date. * The order relation on date values is the order relation on their * starting instants. */ bool ATDateTimeOrDerivedImpl::lessThan(const ATDateTimeOrDerived* other, const DynamicContext* context) const { const ATDateTimeOrDerived* myDateTimeCopy = this; const ATDateTimeOrDerived* otherDateTimeCopy = (const ATDateTimeOrDerived*)other; if(myDateTimeCopy->hasTimezone() || otherDateTimeCopy->hasTimezone()) { myDateTimeCopy = myDateTimeCopy->normalize(context); otherDateTimeCopy = otherDateTimeCopy->normalize(context); } if(myDateTimeCopy->getYears()->greaterThan(otherDateTimeCopy->getYears(), context)) return false; else if(myDateTimeCopy->getYears()->lessThan(otherDateTimeCopy->getYears(), context)) return true; if(myDateTimeCopy->getMonths()->greaterThan(otherDateTimeCopy->getMonths(), context)) return false; else if(myDateTimeCopy->getMonths()->lessThan(otherDateTimeCopy->getMonths(), context)) return true; if(myDateTimeCopy->getDays()->greaterThan(otherDateTimeCopy->getDays(), context)) return false; else if(myDateTimeCopy->getDays()->lessThan(otherDateTimeCopy->getDays(), context)) return true; if(myDateTimeCopy->getHours()->greaterThan(otherDateTimeCopy->getHours(), context)) return false; else if(myDateTimeCopy->getHours()->lessThan(otherDateTimeCopy->getHours(), context)) return true; if(myDateTimeCopy->getMinutes()->greaterThan(otherDateTimeCopy->getMinutes(), context)) return false; else if(myDateTimeCopy->getMinutes()->lessThan(otherDateTimeCopy->getMinutes(), context)) return true; return myDateTimeCopy->getSeconds()->lessThan(otherDateTimeCopy->getSeconds(), context); } /** * Returns an integer representing the year component of this object */ const ATDecimalOrDerived* ATDateTimeOrDerivedImpl::getYears() const { return _YY; } /** * Returns an integer representing the month component of this object */ const ATDecimalOrDerived* ATDateTimeOrDerivedImpl::getMonths() const { return _MM; } /** * Returns an integer representing the day component of this object */ const ATDecimalOrDerived* ATDateTimeOrDerivedImpl::getDays() const { return _DD; } /** * Returns an integer representing the hour component of this object */ const ATDecimalOrDerived* ATDateTimeOrDerivedImpl::getHours() const { return _hh; } /** * Returns an integer representing the minute component of this object */ const ATDecimalOrDerived* ATDateTimeOrDerivedImpl::getMinutes() const { return _mm; } /** * Returns an decimal representing the second component of this object */ const ATDecimalOrDerived* ATDateTimeOrDerivedImpl::getSeconds() const { return _ss; } /** * Returns the timezone associated with this object, or * null, if the timezone is not set */ const Timezone* ATDateTimeOrDerivedImpl::getTimezone() const { return _timezone; } /** * Returns true if the timezone is defined for this object, false otherwise. */ bool ATDateTimeOrDerivedImpl::hasTimezone() const { return _hasTimezone; } /** * Setter for timezone. Overrides the current timezone. (Not to be * confused with addTimezone(). If passed null, timezone is removed (unset) */ const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::setTimezone(const Timezone* timezone, const DynamicContext* context) const { bool hasTimezone = timezone == 0 ? false : true; return new (context->getMemoryManager()) ATDateTimeOrDerivedImpl(this->_typeURI, this->_typeName, this->_YY, this->_MM, this->_DD, this->_hh, this->_mm, this->_ss, timezone, hasTimezone, context->getMemoryManager()); } /** * Returns an ATDateTimeOrDerived with a timezone added to it */ const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::addTimezone(const ATDurationOrDerived* timezone, const DynamicContext* context) const { const Timezone* tz = new (context->getMemoryManager()) Timezone(timezone, context); // If this dateTime does not have a timezone, add the given timezone if (!_hasTimezone) { return this->setTimezone(tz, context); } else { //else convert the dateTime into an equivalent one with given timezone // Minutes MAPM offset = tz->getMinutes()-_timezone->getMinutes(); MAPM temp = _mm->asMAPM()+offset; MAPM mm = DateUtils::modulo(temp, DateUtils::g_minutesPerHour); MAPM carry = (temp / DateUtils::g_minutesPerHour).floor(); // Hours offset = tz->getHours()-_timezone->getHours(); temp = _hh->asMAPM()+offset+carry; MAPM hh = DateUtils::modulo(temp, DateUtils::g_hoursPerDay); 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()) ATDateTimeOrDerivedImpl(this->getTypeURI(), this->getTypeName(), DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), sumDate.Year(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Month(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Day(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), hh, context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), mm, context), _ss, tz, true, context->getMemoryManager()); } } /** * Returns a date with the given yearMonthDuration added to it */ const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::addYearMonthDuration(const ATDurationOrDerived* yearMonth, const DynamicContext* context) const { MAPM year=yearMonth->getYears()->asMAPM(); MAPM month=yearMonth->getMonths()->asMAPM(); if(yearMonth->isNegative()) { year=year.neg(); month=month.neg(); } return addYearMonthDuration(year, month, context); } /** * Returns a date with the given yearMonthDuration added to it */ const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::addYearMonthDuration(MAPM years, MAPM months, const DynamicContext* context) const { const ATDateTimeOrDerivedImpl* date = this; if (_hasTimezone) { date = (const ATDateTimeOrDerivedImpl*) this->normalize(context); } MAPM totalMonths = date->_MM->asMAPM()+months-MM_One; MAPM MM = DateUtils::modulo(totalMonths, 12)+MM_One; MAPM carry = (totalMonths / 12).floor(); MAPM finalYears = carry + years + date->_YY->asMAPM(); assert(!date->_YY->isZero()); // We should never have _YY = 0000 MAPM YY; // Fix year 0000 problem if ( finalYears <= MM_Zero && date->_YY->isPositive()) { YY = finalYears - MM_One; } else if (finalYears >= MM_Zero && date->_YY->isNegative()) { YY = finalYears+ MM_One; } else { YY = finalYears; } return new (context->getMemoryManager()) ATDateTimeOrDerivedImpl(date->getTypeURI(), date->getTypeName(), DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), YY, context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), MM, context), _DD, date->_hh, date->_mm, date->_ss, date->getTimezone(), date->hasTimezone(), context->getMemoryManager()); } /** * Returns a date with the given dayTimeDuration added to it */ const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::addDayTimeDuration(const ATDurationOrDerived* dayTime, const DynamicContext* context) const { if(dayTime->isNegative()) { return subtractDayTimeDuration(dayTime->getDays()->asMAPM(), dayTime->getHours()->asMAPM(), dayTime->getMinutes()->asMAPM(), dayTime->getSeconds()->asMAPM(), context); } else { return addDayTimeDuration(dayTime->getDays()->asMAPM(), dayTime->getHours()->asMAPM(), dayTime->getMinutes()->asMAPM(), dayTime->getSeconds()->asMAPM(), context); } } const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::normalize(const DynamicContext* context) const { const Timezone* timezone; if (!_hasTimezone) { timezone = new (context->getMemoryManager()) Timezone(context->getImplicitTimezone(), context); } else { timezone = this->_timezone; } // Minutes MAPM tzMinutes = timezone->getMinutes(); MAPM temp = _mm->asMAPM() - tzMinutes; MAPM mm = DateUtils::modulo(temp, DateUtils::g_minutesPerHour); MAPM carry = (temp / DateUtils::g_minutesPerHour).floor(); // Hours MAPM tzHours = timezone->getHours(); temp = _hh->asMAPM() - tzHours + carry; MAPM hh = DateUtils::modulo(temp, DateUtils::g_hoursPerDay); 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()) ATDateTimeOrDerivedImpl(this->getTypeURI(), this->getTypeName(), DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), sumDate.Year(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Month(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), sumDate.Day(), context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), hh, context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), mm, context), _ss, new (context->getMemoryManager()) Timezone(0, 0), true, // timezone set to UTC context->getMemoryManager()); } /** * Returns a date with the given yearMonthDuration subtracted from it */ const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::subtractYearMonthDuration(const ATDurationOrDerived* yearMonth, const DynamicContext* context) const { 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 ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::subtractDayTimeDuration(const ATDurationOrDerived* dayTime, const DynamicContext* context) const { if(dayTime->isNegative()) { return addDayTimeDuration(dayTime->getDays()->asMAPM(), dayTime->getHours()->asMAPM(), dayTime->getMinutes()->asMAPM(), dayTime->getSeconds()->asMAPM(), context); } else { return subtractDayTimeDuration(dayTime->getDays()->asMAPM(), dayTime->getHours()->asMAPM(), dayTime->getMinutes()->asMAPM(), dayTime->getSeconds()->asMAPM(), context); } } const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::addDayTimeDuration(MAPM days, MAPM hours, MAPM minutes, MAPM seconds, const DynamicContext* context) const { // This algorithm is according to spec from http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes const ATDateTimeOrDerivedImpl* date = this; if (_hasTimezone) { date = (const ATDateTimeOrDerivedImpl*) this->normalize(context); } // Seconds MAPM temp = date->_ss->asMAPM() + seconds; MAPM ss = DateUtils::modulo(temp, DateUtils::g_secondsPerMinute); MAPM carry = (temp / DateUtils::g_secondsPerMinute).floor(); // Minutes temp = date->_mm->asMAPM()+minutes+carry; MAPM mm = DateUtils::modulo(temp, DateUtils::g_minutesPerHour); carry = (temp/DateUtils::g_minutesPerHour).floor(); // Hours temp = date->_hh->asMAPM()+hours+carry; MAPM hh = DateUtils::modulo(temp, DateUtils::g_hoursPerDay); carry = (temp / DateUtils::g_hoursPerDay); Date thisDate = Date(asInt(date->getDays()->asMAPM()), asInt(date->getMonths()->asMAPM()),asInt(date->getYears()->asMAPM())); Date sumDate = thisDate + asInt(days) + asInt(carry); return new (context->getMemoryManager()) ATDateTimeOrDerivedImpl(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), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), hh, context), DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), mm, context), DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), ss, context), date->getTimezone(), date->hasTimezone(), context->getMemoryManager()); } const ATDateTimeOrDerived* ATDateTimeOrDerivedImpl::subtractDayTimeDuration(MAPM days, MAPM hours, MAPM minutes, MAPM seconds, const DynamicContext* context) const { return this->addDayTimeDuration(days.neg(), hours.neg(), minutes.neg(), seconds.neg(), context); } /** * Returns a dayTimeDuration corresponding to the difference between this * and the given ATDateTimeOrDerived* */ const ATDurationOrDerived* ATDateTimeOrDerivedImpl::subtractDateTimeAsDayTimeDuration(const ATDateTimeOrDerived* date, const DynamicContext* context) const { // normalize both dates first const ATDateTimeOrDerived* thisDate = this->normalize(context); const ATDateTimeOrDerived* otherDate = date->normalize(context); // this as julian Date dateThis = Date(asInt(thisDate->getDays()->asMAPM()), asInt(thisDate->getMonths()->asMAPM()), asInt(thisDate->getYears()->asMAPM())); // other date as julian Date dateOther = Date(asInt(date->getDays()->asMAPM()), asInt(date->getMonths()->asMAPM()), asInt(date->getYears()->asMAPM())); // difference in days long dateDiff = dateThis - dateOther; MAPM dateDiffInSeconds = dateDiff*DateUtils::g_secondsPerDay; // calculate the differences in seconds MAPM thisSeconds = thisDate->getHours()->asMAPM() * DateUtils::g_secondsPerHour + thisDate->getMinutes()->asMAPM() * DateUtils::g_secondsPerMinute + thisDate->getSeconds()->asMAPM(); MAPM otherSeconds = otherDate->getHours()->asMAPM() * DateUtils::g_secondsPerHour + otherDate->getMinutes()->asMAPM() * DateUtils::g_secondsPerMinute + otherDate->getSeconds()->asMAPM(); MAPM secDiff = thisSeconds - otherSeconds + dateDiffInSeconds; bool isNegative = (secDiff < MM_Zero); MAPM endDiff = secDiff.abs(); // getDays const ATDecimalOrDerived* DD = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), (endDiff / DateUtils::g_secondsPerDay).floor(), context); MAPM carry = DateUtils::modulo(endDiff,DateUtils::g_secondsPerDay); // get hour const ATDecimalOrDerived* hh = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), (carry/DateUtils::g_secondsPerHour).floor(), context); // get minute const ATDecimalOrDerived* mm = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), (DateUtils::modulo(carry,DateUtils::g_secondsPerHour)/DateUtils::g_secondsPerMinute).floor(), context); // get seconds const ATDecimalOrDerived* ss = DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), DateUtils::modulo( DateUtils::modulo(carry,DateUtils::g_secondsPerHour), DateUtils::g_secondsPerMinute) , 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(DD->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_D); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buffer.append(hh->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_H); buffer.append(mm->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); buffer.append(ss->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); return DatatypeFactory::STR2AT::createDayTimeDuration(context->getMemoryManager(), buffer.getRawBuffer(), context); } /** * Returns a dayTimeDuration corresponding to the difference between this * and the given ATDateTimeOrDerived* */ const ATDurationOrDerived* ATDateTimeOrDerivedImpl::subtractDateTimeAsYearMonthDuration(const ATDateTimeOrDerived* date, const DynamicContext* context) const { // normalize both dates first const ATDateTimeOrDerived* thisDate = this->normalize(context); const ATDateTimeOrDerived* otherDate = date->normalize(context); // Call getDayTimeDuration const ATDurationOrDerived* dayTimeDiff = thisDate->subtractDateTimeAsDayTimeDuration(otherDate, context); // put it into yearMonthDuration form MAPM days = dayTimeDiff->getDays()->asMAPM(); if(dayTimeDiff->isNegative()) days = days.neg(); MAPM months = MM_Zero; // Get number of months const ATDateTimeOrDerivedImpl* cur = (const ATDateTimeOrDerivedImpl*)date; while (true) { int currentDaysInMonth = DateUtils::maximumDayInMonthFor(asInt(cur->getYears()->asMAPM()), asInt(cur->getMonths()->asMAPM())); int daysToNextMonth = currentDaysInMonth-asInt(cur->getDays()->asMAPM())+1; if (days > daysToNextMonth) { days = days - daysToNextMonth; months = months + MM_One; cur = (const ATDateTimeOrDerivedImpl*)cur->addDayTimeDuration(daysToNextMonth, MM_Zero, MM_Zero, MM_Zero, context); } else break; }//while // Get year and month XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buffer(1023, context->getMemoryManager()); if(months < MM_Zero) { buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); months=months.neg(); } const ATDecimalOrDerived* MM=DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), months, context); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buffer.append(MM->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); return DatatypeFactory::STR2AT::createYearMonthDuration(context->getMemoryManager(), buffer.getRawBuffer(), context); } ////////////////////////////////////// // Horrible Hack to make Dates // // work for now. Loss of Precision! // ////////////////////////////////////// int ATDateTimeOrDerivedImpl::asInt(MAPM num) const { if(num < INT_MIN || num > INT_MAX) { DSLthrow(XPath2TypeCastException, X("ATDateTimeOrDerivedImpl::asInt"), X("Invalid representation of an int")); } else { char out_string[256]; num.toIntegerString(out_string); return atoi(out_string); } } AnyAtomicType::AtomicObjectType ATDateTimeOrDerivedImpl::getPrimitiveTypeIndex() const { return this->getTypeIndex(); } void ATDateTimeOrDerivedImpl::setDateTime(const XMLCh* const dateTime, const DynamicContext* context) { unsigned int length = XERCES_CPP_NAMESPACE_QUALIFIER XMLString::stringLen(dateTime); if(dateTime == 0) { DSLthrow(XPath2TypeCastException,X("ATDateTimeOrDerivedImpl::setDateTime"), X("Invalid representation of dateTime")); } // State variables etc. bool gotDot = false; bool gotDigit = false; unsigned int pos = 0; long int tmpnum = 0; MAPM decplace = 1; MAPM tmpdec = 0; bool negative = false; unsigned numDigit = 0; // defaulting values MAPM YY = 0; MAPM MM = 0; MAPM DD = 0; MAPM hh = 0; MAPM mm = 0; MAPM ss = 0; _hasTimezone = false; bool zonepos = true; int zonehh = 0; int zonemm = 0; int state = 0 ; // 0 = year / 1 = month / 2 = day / 3 = hour // 4 = minutes / 5 = sec / 6 = timezonehour / 7 = timezonemin XMLCh tmpChar; bool wrongformat = false; if ( length > 0 && dateTime[0] == L'-' ) { negative = true; pos = 1; }else{ pos = 0; } while ( ! wrongformat && pos < length) { tmpChar = dateTime[pos]; pos++; switch(tmpChar) { case L'.': { if (! gotDot && gotDigit && state == 5 && numDigit == 2) { gotDot = true; ss = tmpnum; gotDigit = false; tmpnum = 0; break; } wrongformat = true; break; } case 0x0030: case 0x0031: case 0x0032: case 0x0033: case 0x0034: case 0x0035: case 0x0036: case 0x0037: case 0x0038: case 0x0039: { if ( gotDot && state == 5) { decplace *= 10; } else { numDigit ++; } tmpnum *= 10; tmpnum += static_cast(tmpChar - 0x0030); gotDigit = true; break; } case L'T' : { if ( state == 2 && gotDigit && !gotDot && numDigit == 2) { state ++; DD = tmpnum; tmpnum = 0; gotDigit = false; numDigit = 0; } else { wrongformat = 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 == 5 && numDigit == 2) { tmpdec = tmpnum / decplace; ss += tmpdec; gotDigit = false; _hasTimezone = true; zonepos = false; tmpnum = 0; numDigit = 0; } else { wrongformat = true; } state ++; } break; } case L'+' : { if ( gotDigit && state == 5 && numDigit == 2) { tmpdec = tmpnum / decplace; ss += tmpdec; state = 6; gotDigit = false; _hasTimezone = true; zonepos = true; tmpnum = 0; numDigit = 0; } else { wrongformat = true; } break; } case L':' : { if (gotDigit ) { if (state == 3 && numDigit == 2) { hh = tmpnum; tmpnum = 0; gotDigit = false; numDigit = 0; } else if ( state == 4 && numDigit == 2) { mm = tmpnum; tmpnum = 0; gotDigit = false; numDigit = 0; } else if ( state == 6 && numDigit == 2) { zonehh = tmpnum; tmpnum = 0; gotDigit = false; numDigit = 0; } state ++; }else { wrongformat = true; } break; } case L'Z' : { if (gotDigit && state == 5 && numDigit == 2) { tmpdec = tmpnum / decplace; ss += tmpdec; 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; }else if ( gotDigit && state == 5 && numDigit == 2) { tmpdec = tmpnum / decplace; ss += tmpdec; }else { wrongformat = true; } } // check time format if ( MM > 12 || DD > 28 || hh > 24 || mm > 60 || ss >= 61 || zonehh > 24 || zonemm > 60 || YY == 0 ) { // mod in MAPM is called rem bool leapyear = false; 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 ) || hh > 24 || mm > 60 || ss >= 61 || zonehh > 24 || zonemm > 60 || YY == 0) { wrongformat = true; } } if (wrongformat) { DSLthrow(XPath2TypeCastException,X("XSDateTimeImpl::setDateTime"), X("Invalid representation of dateTime")); } // Create Timezone object, clean this up in future if (zonepos == false) { zonehh *= -1; zonemm *= -1; } _timezone = new (getMemoryManager()) Timezone(zonehh, zonemm); _YY = DatatypeFactory::POD2AT::createInteger(getMemoryManager(), YY, context); _MM = DatatypeFactory::POD2AT::createNonNegativeInteger(getMemoryManager(), MM, context); _DD = DatatypeFactory::POD2AT::createNonNegativeInteger(getMemoryManager(), DD, context); _hh = DatatypeFactory::POD2AT::createNonNegativeInteger(getMemoryManager(), hh, context); _mm = DatatypeFactory::POD2AT::createNonNegativeInteger(getMemoryManager(), mm, context); _ss = DatatypeFactory::POD2AT::createDecimal(getMemoryManager(), ss, context); }