diff options
-rw-r--r-- | i18npool/inc/calendar_gregorian.hxx | 3 | ||||
-rw-r--r-- | i18npool/source/calendar/calendar_gregorian.cxx | 247 |
2 files changed, 4 insertions, 246 deletions
diff --git a/i18npool/inc/calendar_gregorian.hxx b/i18npool/inc/calendar_gregorian.hxx index 4a16c00c3eb6..283e1b7c60e9 100644 --- a/i18npool/inc/calendar_gregorian.hxx +++ b/i18npool/inc/calendar_gregorian.hxx @@ -116,9 +116,6 @@ private: /** Submit fieldSetValue array according to fieldSet. */ void submitFields() throw(css::uno::RuntimeException); - /** Submit fieldSetValue array according to fieldSet, plus EYMDhms if >=0, - plus zone and DST if != 0 */ - void submitValues( sal_Int32 nEra, sal_Int32 nYear, sal_Int32 nMonth, sal_Int32 nDay, sal_Int32 nHour, sal_Int32 nMinute, sal_Int32 nSecond, sal_Int32 nMilliSecond, sal_Int32 nZone, sal_Int32 nDST) throw(css::uno::RuntimeException); /** Set fields internally. */ void setValue() throw(css::uno::RuntimeException); /** Obtain combined field values for timezone offset (minutes+secondmillis) diff --git a/i18npool/source/calendar/calendar_gregorian.cxx b/i18npool/source/calendar/calendar_gregorian.cxx index 275b24dff0ed..f3fa8ea6dac8 100644 --- a/i18npool/source/calendar/calendar_gregorian.cxx +++ b/i18npool/source/calendar/calendar_gregorian.cxx @@ -491,260 +491,21 @@ void Calendar_gregorian::submitFields() throw(css::uno::RuntimeException) body->set( fieldNameConverter( CalendarFieldIndex::DST_OFFSET), nDSTOffset); } -void Calendar_gregorian::submitValues( sal_Int32 nEra, sal_Int32 nYear, - sal_Int32 nMonth, sal_Int32 nDay, sal_Int32 nHour, sal_Int32 nMinute, - sal_Int32 nSecond, sal_Int32 nMilliSecond, sal_Int32 nZone, sal_Int32 nDST ) - throw(css::uno::RuntimeException) -{ - submitFields(); - if (nEra >= 0) - body->set( UCAL_ERA, nEra); - if (nYear >= 0) - body->set( UCAL_YEAR, nYear); - if (nMonth >= 0) - body->set( UCAL_MONTH, nMonth); - if (nDay >= 0) - body->set( UCAL_DATE, nDay); - if (nHour >= 0) - body->set( UCAL_HOUR_OF_DAY, nHour); - if (nMinute >= 0) - body->set( UCAL_MINUTE, nMinute); - if (nSecond >= 0) - body->set( UCAL_SECOND, nSecond); - if (nMilliSecond >= 0) - body->set( UCAL_MILLISECOND, nMilliSecond); - if (nZone != 0) - body->set( UCAL_ZONE_OFFSET, nZone); - if (nDST != 0) - body->set( UCAL_DST_OFFSET, nDST); -} - -static void lcl_setCombinedOffsetFieldValues( sal_Int32 nValue, - sal_Int16 rFieldSetValue[], sal_Int16 rFieldValue[], - sal_Int16 nParentFieldIndex, sal_Int16 nChildFieldIndex ) -{ - sal_Int32 nTrunc = nValue / 60000; - rFieldSetValue[nParentFieldIndex] = rFieldValue[nParentFieldIndex] = - static_cast<sal_Int16>( nTrunc); - sal_uInt16 nMillis = static_cast<sal_uInt16>( abs( nValue - nTrunc * 60000)); - rFieldSetValue[nChildFieldIndex] = rFieldValue[nChildFieldIndex] = - static_cast<sal_Int16>( nMillis); -} - void Calendar_gregorian::setValue() throw(RuntimeException) { - // Correct DST glitch, see also localtime/gmtime conversion pitfalls at - // http://www.erack.de/download/timetest.c - - // #i24082# in order to make the DST correction work in all - // circumstances, the time values have to be always resubmitted, - // regardless whether specified by the caller or not. It is not - // sufficient to rely on the ICU internal values previously set, as the - // following may happen: - // - Let 2004-03-28T02:00 be the onsetRule. - // - On 2004-03-29 (calendar initialized with 2004-03-29T00:00 DST) set - // a date of 2004-03-28 => calendar results in 2004-03-27T23:00 no DST. - // - Correcting this with simply "2004-03-28 no DST" and no time - // specified results in 2004-03-29T00:00, the ICU internal 23:00 time - // being adjusted to 24:00 in this case, switching one day further. - // => submit 2004-03-28T00:00 no DST. - - // This got even weirder since ICU incorporated also historical data, - // even the timezone may differ for different dates! It is necessary to - // let ICU choose the corresponding OlsonTimeZone transitions and adapt - // values. - // #i86094# gives examples where that went wrong: - // TZ=Europe/Moscow date <= 1919-07-01 - // zone +2:30:48 (!) instead of +3h, DST +2h instead of +1h - // TZ=America/St_Johns date <= 1935-03-30 - // zone -3:30:52 (!) instead of -3:30 - // Copy fields before calling submitFields() directly or indirectly below. memcpy(fieldSetValue, fieldValue, sizeof(fieldSetValue)); // Possibly setup ERA and YEAR in fieldSetValue. mapToGregorian(); - DUMP_ICU_CAL_MSG(("%s\n","setValue() before any submission")); - DUMP_I18N_CAL_MSG(("%s\n","setValue() before any submission")); - - bool bNeedZone = !(fieldSet & (1 << CalendarFieldIndex::ZONE_OFFSET)); - bool bNeedDST = !(fieldSet & (1 << CalendarFieldIndex::DST_OFFSET)); - sal_Int32 nZone1, nDST1, nEra, nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilliSecond, nZone0, nDST0; - nZone1 = nDST1 = nZone0 = nDST0 = 0; - nEra = nYear = nMonth = nDay = nHour = nMinute = nSecond = nMilliSecond = -1; - if ( bNeedZone || bNeedDST ) - { - UErrorCode status; - if ( !(fieldSet & (1 << CalendarFieldIndex::ERA)) ) - { - nEra = body->get( UCAL_ERA, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nEra = -1; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::YEAR)) ) - { - nYear = body->get( UCAL_YEAR, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nYear = -1; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::MONTH)) ) - { - nMonth = body->get( UCAL_MONTH, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nMonth = -1; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::DAY_OF_MONTH)) ) - { - nDay = body->get( UCAL_DATE, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nDay = -1; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::HOUR)) ) - { - nHour = body->get( UCAL_HOUR_OF_DAY, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nHour = -1; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::MINUTE)) ) - { - nMinute = body->get( UCAL_MINUTE, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nMinute = -1; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::SECOND)) ) - { - nSecond = body->get( UCAL_SECOND, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nSecond = -1; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::MILLISECOND)) ) - { - nMilliSecond = body->get( UCAL_MILLISECOND, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nMilliSecond = -1; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::ZONE_OFFSET)) ) - { - nZone0 = body->get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nZone0 = 0; - } - if ( !(fieldSet & (1 << CalendarFieldIndex::DST_OFFSET)) ) - { - nDST0 = body->get( UCAL_DST_OFFSET, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nDST0 = 0; - } - - // Submit values to obtain a time zone and DST corresponding to the date/time. - submitValues( nEra, nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilliSecond, nZone0, nDST0); - - DUMP_ICU_CAL_MSG(("%s\n","setValue() in bNeedZone||bNeedDST after submitValues()")); - DUMP_I18N_CAL_MSG(("%s\n","setValue() in bNeedZone||bNeedDST after submitValues()")); - nZone1 = body->get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nZone1 = 0; - nDST1 = body->get( UCAL_DST_OFFSET, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nDST1 = 0; - } + DUMP_ICU_CAL_MSG(("%s\n","setValue() before submission")); + DUMP_I18N_CAL_MSG(("%s\n","setValue() before submission")); - // The original submission, may lead to a different zone/DST and - // different date. submitFields(); - DUMP_ICU_CAL_MSG(("%s\n","setValue() after original submission")); - DUMP_I18N_CAL_MSG(("%s\n","setValue() after original submission")); - if ( bNeedZone || bNeedDST ) - { - UErrorCode status; - sal_Int32 nZone2 = body->get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nZone2 = nZone1; - sal_Int32 nDST2 = body->get( UCAL_DST_OFFSET, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nDST2 = nDST1; - if ( nZone0 != nZone1 || nZone2 != nZone1 || nDST0 != nDST1 || nDST2 != nDST1 ) - { - // Due to different DSTs, resulting date values may differ if - // DST is onset at 00:00 and the very onsetRule date was - // submitted with DST off => date-1 23:00, for example, which - // is not what we want. - // Resubmit all values, this time including DST => date 01:00 - // Similar for zone differences. - // If already the first full submission with nZone0 and nDST0 - // lead to date-1 23:00, the original submission was based on - // that date if it wasn't a full date (nDST0 set, nDST1 not - // set, nDST2==nDST1). If it was January 1st without year we're - // even off by one year now. Resubmit all values including new - // DST => date 00:00. - - // Set field values accordingly in case they were used. - if (!bNeedZone) - lcl_setCombinedOffsetFieldValues( nZone2, fieldSetValue, - fieldValue, CalendarFieldIndex::ZONE_OFFSET, - CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS); - if (!bNeedDST) - lcl_setCombinedOffsetFieldValues( nDST2, fieldSetValue, - fieldValue, CalendarFieldIndex::DST_OFFSET, - CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS); - submitValues( nEra, nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilliSecond, nZone2, nDST2); - DUMP_ICU_CAL_MSG(("%s\n","setValue() after Zone/DST glitch resubmit")); - DUMP_I18N_CAL_MSG(("%s\n","setValue() after Zone/DST glitch resubmit")); - - // Time zone transition => resubmit. - // TZ=America/St_Johns date <= 1935-03-30 - // -3:30:52 (!) instead of -3:30 - // if first submission included time zone -3:30 that would be wrong. - bool bResubmit = false; - sal_Int32 nZone3 = body->get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nZone3 = nZone2; - if (nZone3 != nZone2) - { - bResubmit = true; - if (!bNeedZone) - lcl_setCombinedOffsetFieldValues( nZone3, fieldSetValue, - fieldValue, CalendarFieldIndex::ZONE_OFFSET, - CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS); - } + DUMP_ICU_CAL_MSG(("%s\n","setValue() after submission")); + DUMP_I18N_CAL_MSG(("%s\n","setValue() after submission")); - // If the DST onset rule says to switch from 00:00 to 01:00 and - // we tried to set onsetDay 00:00 with DST, the result was - // onsetDay-1 23:00 and no DST, which is not what we want. So - // once again without DST, resulting in onsetDay 01:00 and DST. - // Yes, this seems to be weird, but logically correct. - // It doesn't even have to be on an onsetDay as the DST is - // factored in all days by ICU and there seems to be some - // unknown behavior. - // TZ=Asia/Tehran 1999-03-22 exposes this, for example. - sal_Int32 nDST3 = body->get( UCAL_DST_OFFSET, status = U_ZERO_ERROR); - if ( !U_SUCCESS(status) ) - nDST3 = nDST2; - if (nDST2 != nDST3 && !nDST3) - { - bResubmit = true; - if (!bNeedDST) - { - fieldSetValue[CalendarFieldIndex::DST_OFFSET] = - fieldValue[CalendarFieldIndex::DST_OFFSET] = 0; - fieldSetValue[CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS] = - fieldValue[CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS] = 0; - } - } - if (bResubmit) - { - submitValues( nEra, nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilliSecond, nZone3, nDST3); - DUMP_ICU_CAL_MSG(("%s\n","setValue() after Zone/DST glitch 2nd resubmit")); - DUMP_I18N_CAL_MSG(("%s\n","setValue() after Zone/DST glitch 2nd resubmit")); - } - SAL_INFO( "i18npool", "Calendar_gregorian::setValue:" - " nZone0 " << nZone0 << ", nDST0 " << nDST0 << - ", nZone1 " << nZone1 << ", nDST1 " << nDST1 << - ", nZone2 " << nZone2 << ", nDST2 " << nDST2 << - ", nZone3 " << nZone3 << ", nDST3 " << nDST3); - } - } #if erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR { // force icu::Calendar to recalculate |