1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_i18npool.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir #include "calendar_gregorian.hxx" 32*cdf0e10cSrcweir #include "localedata.hxx" 33*cdf0e10cSrcweir #include <com/sun/star/i18n/AmPmValue.hpp> 34*cdf0e10cSrcweir #include <com/sun/star/i18n/Months.hpp> 35*cdf0e10cSrcweir #include <com/sun/star/i18n/Weekdays.hpp> 36*cdf0e10cSrcweir #include <com/sun/star/i18n/reservedWords.hpp> 37*cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 38*cdf0e10cSrcweir #include <comphelper/processfactory.hxx> 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir #include <stdio.h> 41*cdf0e10cSrcweir #include <string.h> 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir #define erDUMP_ICU_CALENDAR 0 44*cdf0e10cSrcweir #define erDUMP_I18N_CALENDAR 0 45*cdf0e10cSrcweir #if erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR 46*cdf0e10cSrcweir // If both are used, DUMP_ICU_CAL_MSG() must be used before DUMP_I18N_CAL_MSG() 47*cdf0e10cSrcweir // to obtain internally set values from ICU, else Calendar::get() calls in 48*cdf0e10cSrcweir // DUMP_I18N_CAL_MSG() recalculate! 49*cdf0e10cSrcweir 50*cdf0e10cSrcweir // These pieces of macro are shamelessly borrowed from icu's olsontz.cpp, the 51*cdf0e10cSrcweir // double parens'ed approach to pass multiple parameters as one macro parameter 52*cdf0e10cSrcweir // is appealing. 53*cdf0e10cSrcweir static void debug_cal_loc(const char *f, int32_t l) 54*cdf0e10cSrcweir { 55*cdf0e10cSrcweir fprintf(stderr, "%s:%d: ", f, l); 56*cdf0e10cSrcweir } 57*cdf0e10cSrcweir # include <stdarg.h> 58*cdf0e10cSrcweir static void debug_cal_msg(const char *pat, ...) 59*cdf0e10cSrcweir { 60*cdf0e10cSrcweir va_list ap; 61*cdf0e10cSrcweir va_start(ap, pat); 62*cdf0e10cSrcweir vfprintf(stderr, pat, ap); 63*cdf0e10cSrcweir } 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir #if erDUMP_ICU_CALENDAR 66*cdf0e10cSrcweir // Make icu with 67*cdf0e10cSrcweir // DEFS = -DU_DEBUG_CALSVC -DUCAL_DEBUG_DUMP 68*cdf0e10cSrcweir // in icu/$(INPATH)/misc/build/icu/source/icudefs.mk 69*cdf0e10cSrcweir // May need some patches to fix unmaintained things there. 70*cdf0e10cSrcweir extern void ucal_dump( const icu::Calendar & ); 71*cdf0e10cSrcweir static void debug_icu_cal_dump( const ::icu::Calendar & r ) 72*cdf0e10cSrcweir { 73*cdf0e10cSrcweir ucal_dump(r); 74*cdf0e10cSrcweir fflush(stderr); 75*cdf0e10cSrcweir // set a breakpoint here to pause display between dumps 76*cdf0e10cSrcweir } 77*cdf0e10cSrcweir // must use double parens, i.e.: DUMP_ICU_CAL_MSG(("four is: %d",4)); 78*cdf0e10cSrcweir #define DUMP_ICU_CAL_MSG(x) {debug_cal_loc(__FILE__,__LINE__);debug_cal_msg x;debug_icu_cal_dump(*body);} 79*cdf0e10cSrcweir #else // erDUMP_ICU_CALENDAR 80*cdf0e10cSrcweir #define DUMP_ICU_CAL_MSG(x) 81*cdf0e10cSrcweir #endif // erDUMP_ICU_CALENDAR 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir #if erDUMP_I18N_CALENDAR 84*cdf0e10cSrcweir static void debug_cal_millis_to_time( long nMillis, long & h, long & m, long & s, long & f ) 85*cdf0e10cSrcweir { 86*cdf0e10cSrcweir int sign = (nMillis < 0 ? -1 : 1); 87*cdf0e10cSrcweir nMillis = ::std::abs(nMillis); 88*cdf0e10cSrcweir h = sign * nMillis / (60 * 60 * 1000); 89*cdf0e10cSrcweir nMillis -= sign * h * (60 * 60 * 1000); 90*cdf0e10cSrcweir m = nMillis / (60 * 1000); 91*cdf0e10cSrcweir nMillis -= m * (60 * 1000); 92*cdf0e10cSrcweir s = nMillis / (1000); 93*cdf0e10cSrcweir nMillis -= s * (1000); 94*cdf0e10cSrcweir f = nMillis; 95*cdf0e10cSrcweir } 96*cdf0e10cSrcweir static void debug_i18n_cal_dump( const ::icu::Calendar & r ) 97*cdf0e10cSrcweir { 98*cdf0e10cSrcweir UErrorCode status; 99*cdf0e10cSrcweir long nMillis, h, m, s, f; 100*cdf0e10cSrcweir fprintf( stderr, " %04ld", (long)r.get( UCAL_YEAR, status = U_ZERO_ERROR)); 101*cdf0e10cSrcweir fprintf( stderr, "-%02ld", (long)r.get( UCAL_MONTH, status = U_ZERO_ERROR)+1); 102*cdf0e10cSrcweir fprintf( stderr, "-%02ld", (long)r.get( UCAL_DATE, status = U_ZERO_ERROR)); 103*cdf0e10cSrcweir fprintf( stderr, " %02ld", (long)r.get( UCAL_HOUR_OF_DAY, status = U_ZERO_ERROR)); 104*cdf0e10cSrcweir fprintf( stderr, ":%02ld", (long)r.get( UCAL_MINUTE, status = U_ZERO_ERROR)); 105*cdf0e10cSrcweir fprintf( stderr, ":%02ld", (long)r.get( UCAL_SECOND, status = U_ZERO_ERROR)); 106*cdf0e10cSrcweir fprintf( stderr, " zone: %ld", (long)(nMillis = r.get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR))); 107*cdf0e10cSrcweir fprintf( stderr, " (%f min)", (double)nMillis / 60000); 108*cdf0e10cSrcweir debug_cal_millis_to_time( nMillis, h, m, s, f); 109*cdf0e10cSrcweir fprintf( stderr, " (%ld:%02ld:%02ld.%ld)", h, m, s, f); 110*cdf0e10cSrcweir fprintf( stderr, " DST: %ld", (long)(nMillis = r.get( UCAL_DST_OFFSET, status = U_ZERO_ERROR))); 111*cdf0e10cSrcweir fprintf( stderr, " (%f min)", (double)nMillis / 60000); 112*cdf0e10cSrcweir debug_cal_millis_to_time( nMillis, h, m, s, f); 113*cdf0e10cSrcweir fprintf( stderr, " (%ld:%02ld:%02ld.%ld)", h, m, s, f); 114*cdf0e10cSrcweir fprintf( stderr, "\n"); 115*cdf0e10cSrcweir fflush(stderr); 116*cdf0e10cSrcweir } 117*cdf0e10cSrcweir // must use double parens, i.e.: DUMP_I18N_CAL_MSG(("four is: %d",4)); 118*cdf0e10cSrcweir #define DUMP_I18N_CAL_MSG(x) {debug_cal_loc(__FILE__,__LINE__);debug_cal_msg x;debug_i18n_cal_dump(*body);} 119*cdf0e10cSrcweir #else // erDUMP_I18N_CALENDAR 120*cdf0e10cSrcweir #define DUMP_I18N_CAL_MSG(x) 121*cdf0e10cSrcweir #endif // erDUMP_I18N_CALENDAR 122*cdf0e10cSrcweir 123*cdf0e10cSrcweir #else // erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR 124*cdf0e10cSrcweir #define DUMP_ICU_CAL_MSG(x) 125*cdf0e10cSrcweir #define DUMP_I18N_CAL_MSG(x) 126*cdf0e10cSrcweir #endif // erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR 127*cdf0e10cSrcweir 128*cdf0e10cSrcweir 129*cdf0e10cSrcweir using namespace ::com::sun::star::uno; 130*cdf0e10cSrcweir using namespace ::com::sun::star::lang; 131*cdf0e10cSrcweir using namespace ::com::sun::star::i18n; 132*cdf0e10cSrcweir using namespace ::rtl; 133*cdf0e10cSrcweir 134*cdf0e10cSrcweir #define ERROR RuntimeException() 135*cdf0e10cSrcweir 136*cdf0e10cSrcweir Calendar_gregorian::Calendar_gregorian() 137*cdf0e10cSrcweir { 138*cdf0e10cSrcweir init(NULL); 139*cdf0e10cSrcweir } 140*cdf0e10cSrcweir Calendar_gregorian::Calendar_gregorian(Era *_earArray) 141*cdf0e10cSrcweir { 142*cdf0e10cSrcweir init(_earArray); 143*cdf0e10cSrcweir } 144*cdf0e10cSrcweir void SAL_CALL 145*cdf0e10cSrcweir Calendar_gregorian::init(Era *_eraArray) 146*cdf0e10cSrcweir { 147*cdf0e10cSrcweir cCalendar = "com.sun.star.i18n.Calendar_gregorian"; 148*cdf0e10cSrcweir 149*cdf0e10cSrcweir // #i102356# With icu::Calendar::createInstance(UErrorCode) in a Thai 150*cdf0e10cSrcweir // th_TH system locale we accidentally used a Buddhist calendar. Though 151*cdf0e10cSrcweir // the ICU documentation says that should be the case only for 152*cdf0e10cSrcweir // th_TH_TRADITIONAL (and ja_JP_TRADITIONAL Gengou), a plain th_TH 153*cdf0e10cSrcweir // already triggers that behavior, ja_JP does not. Strange enough, 154*cdf0e10cSrcweir // passing a th_TH locale to the calendar creation doesn't trigger 155*cdf0e10cSrcweir // this. 156*cdf0e10cSrcweir // See also http://userguide.icu-project.org/datetime/calendar 157*cdf0e10cSrcweir 158*cdf0e10cSrcweir // Whatever ICU offers as the default calendar for a locale, ensure we 159*cdf0e10cSrcweir // have a Gregorian calendar as requested. 160*cdf0e10cSrcweir 161*cdf0e10cSrcweir /* XXX: with the current implementation the aLocale member variable is 162*cdf0e10cSrcweir * not set prior to loading a calendar from locale data. This 163*cdf0e10cSrcweir * creates an empty (root) locale for ICU, but at least the correct 164*cdf0e10cSrcweir * calendar is used. The language part must not be NULL (respectively 165*cdf0e10cSrcweir * not all, language and country and variant), otherwise the current 166*cdf0e10cSrcweir * default locale would be used again and the calendar keyword ignored. 167*cdf0e10cSrcweir * */ 168*cdf0e10cSrcweir icu::Locale aIcuLocale( "", NULL, NULL, "calendar=gregorian"); 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir UErrorCode status; 171*cdf0e10cSrcweir body = icu::Calendar::createInstance( aIcuLocale, status = U_ZERO_ERROR); 172*cdf0e10cSrcweir if (!body || !U_SUCCESS(status)) throw ERROR; 173*cdf0e10cSrcweir 174*cdf0e10cSrcweir #if 0 175*cdf0e10cSrcweir { 176*cdf0e10cSrcweir icu::Locale loc; 177*cdf0e10cSrcweir loc = body->getLocale( ULOC_ACTUAL_LOCALE, status = U_ZERO_ERROR); 178*cdf0e10cSrcweir fprintf( stderr, "\nICU calendar actual locale: %s\n", loc.getName()); 179*cdf0e10cSrcweir loc = body->getLocale( ULOC_VALID_LOCALE, status = U_ZERO_ERROR); 180*cdf0e10cSrcweir fprintf( stderr, "ICU calendar valid locale: %s\n", loc.getName()); 181*cdf0e10cSrcweir } 182*cdf0e10cSrcweir #endif 183*cdf0e10cSrcweir 184*cdf0e10cSrcweir eraArray=_eraArray; 185*cdf0e10cSrcweir } 186*cdf0e10cSrcweir 187*cdf0e10cSrcweir Calendar_gregorian::~Calendar_gregorian() 188*cdf0e10cSrcweir { 189*cdf0e10cSrcweir delete body; 190*cdf0e10cSrcweir } 191*cdf0e10cSrcweir 192*cdf0e10cSrcweir Calendar_hanja::Calendar_hanja() 193*cdf0e10cSrcweir { 194*cdf0e10cSrcweir cCalendar = "com.sun.star.i18n.Calendar_hanja"; 195*cdf0e10cSrcweir } 196*cdf0e10cSrcweir 197*cdf0e10cSrcweir OUString SAL_CALL 198*cdf0e10cSrcweir Calendar_hanja::getDisplayName( sal_Int16 displayIndex, sal_Int16 idx, sal_Int16 nameType ) throw(RuntimeException) 199*cdf0e10cSrcweir { 200*cdf0e10cSrcweir if ( displayIndex == CalendarDisplayIndex::AM_PM ) { 201*cdf0e10cSrcweir // Am/Pm string for Korean Hanja calendar will refer to Japanese locale 202*cdf0e10cSrcweir com::sun::star::lang::Locale jaLocale = 203*cdf0e10cSrcweir com::sun::star::lang::Locale(OUString::createFromAscii("ja"), OUString(), OUString()); 204*cdf0e10cSrcweir if (idx == 0) return LocaleData().getLocaleItem(jaLocale).timeAM; 205*cdf0e10cSrcweir else if (idx == 1) return LocaleData().getLocaleItem(jaLocale).timePM; 206*cdf0e10cSrcweir else throw ERROR; 207*cdf0e10cSrcweir } 208*cdf0e10cSrcweir else 209*cdf0e10cSrcweir return Calendar_gregorian::getDisplayName( displayIndex, idx, nameType ); 210*cdf0e10cSrcweir } 211*cdf0e10cSrcweir 212*cdf0e10cSrcweir void SAL_CALL 213*cdf0e10cSrcweir Calendar_hanja::loadCalendar( const OUString& /*uniqueID*/, const com::sun::star::lang::Locale& rLocale ) throw(RuntimeException) 214*cdf0e10cSrcweir { 215*cdf0e10cSrcweir // Since this class could be called by service name 'hanja_yoil', we have to 216*cdf0e10cSrcweir // rename uniqueID to get right calendar defined in locale data. 217*cdf0e10cSrcweir Calendar_gregorian::loadCalendar(OUString::createFromAscii("hanja"), rLocale); 218*cdf0e10cSrcweir } 219*cdf0e10cSrcweir 220*cdf0e10cSrcweir static Era gengou_eraArray[] = { 221*cdf0e10cSrcweir {1868, 1, 1}, 222*cdf0e10cSrcweir {1912, 7, 30}, 223*cdf0e10cSrcweir {1926, 12, 25}, 224*cdf0e10cSrcweir {1989, 1, 8}, 225*cdf0e10cSrcweir {0, 0, 0} 226*cdf0e10cSrcweir }; 227*cdf0e10cSrcweir Calendar_gengou::Calendar_gengou() : Calendar_gregorian(gengou_eraArray) 228*cdf0e10cSrcweir { 229*cdf0e10cSrcweir cCalendar = "com.sun.star.i18n.Calendar_gengou"; 230*cdf0e10cSrcweir } 231*cdf0e10cSrcweir 232*cdf0e10cSrcweir static Era ROC_eraArray[] = { 233*cdf0e10cSrcweir {1912, 1, 1}, 234*cdf0e10cSrcweir {0, 0, 0} 235*cdf0e10cSrcweir }; 236*cdf0e10cSrcweir Calendar_ROC::Calendar_ROC() : Calendar_gregorian(ROC_eraArray) 237*cdf0e10cSrcweir { 238*cdf0e10cSrcweir cCalendar = "com.sun.star.i18n.Calendar_ROC"; 239*cdf0e10cSrcweir } 240*cdf0e10cSrcweir 241*cdf0e10cSrcweir static Era buddhist_eraArray[] = { 242*cdf0e10cSrcweir {-542, 1, 1}, 243*cdf0e10cSrcweir {0, 0, 0} 244*cdf0e10cSrcweir }; 245*cdf0e10cSrcweir Calendar_buddhist::Calendar_buddhist() : Calendar_gregorian(buddhist_eraArray) 246*cdf0e10cSrcweir { 247*cdf0e10cSrcweir cCalendar = "com.sun.star.i18n.Calendar_buddhist"; 248*cdf0e10cSrcweir } 249*cdf0e10cSrcweir 250*cdf0e10cSrcweir void SAL_CALL 251*cdf0e10cSrcweir Calendar_gregorian::loadCalendar( const OUString& uniqueID, const com::sun::star::lang::Locale& rLocale ) throw(RuntimeException) 252*cdf0e10cSrcweir { 253*cdf0e10cSrcweir // init. fieldValue[] 254*cdf0e10cSrcweir getValue(); 255*cdf0e10cSrcweir 256*cdf0e10cSrcweir aLocale = rLocale; 257*cdf0e10cSrcweir Sequence< Calendar> xC = LocaleData().getAllCalendars(rLocale); 258*cdf0e10cSrcweir for (sal_Int32 i = 0; i < xC.getLength(); i++) 259*cdf0e10cSrcweir { 260*cdf0e10cSrcweir if (uniqueID == xC[i].Name) 261*cdf0e10cSrcweir { 262*cdf0e10cSrcweir aCalendar = xC[i]; 263*cdf0e10cSrcweir // setup minimalDaysInFirstWeek 264*cdf0e10cSrcweir setMinimumNumberOfDaysForFirstWeek( 265*cdf0e10cSrcweir aCalendar.MinimumNumberOfDaysForFirstWeek); 266*cdf0e10cSrcweir // setup first day of week 267*cdf0e10cSrcweir for (sal_Int16 day = sal::static_int_cast<sal_Int16>( 268*cdf0e10cSrcweir aCalendar.Days.getLength()-1); day>=0; day--) 269*cdf0e10cSrcweir { 270*cdf0e10cSrcweir if (aCalendar.StartOfWeek == aCalendar.Days[day].ID) 271*cdf0e10cSrcweir { 272*cdf0e10cSrcweir setFirstDayOfWeek( day); 273*cdf0e10cSrcweir return; 274*cdf0e10cSrcweir } 275*cdf0e10cSrcweir } 276*cdf0e10cSrcweir } 277*cdf0e10cSrcweir } 278*cdf0e10cSrcweir // Calendar is not for the locale 279*cdf0e10cSrcweir throw ERROR; 280*cdf0e10cSrcweir } 281*cdf0e10cSrcweir 282*cdf0e10cSrcweir 283*cdf0e10cSrcweir com::sun::star::i18n::Calendar SAL_CALL 284*cdf0e10cSrcweir Calendar_gregorian::getLoadedCalendar() throw(RuntimeException) 285*cdf0e10cSrcweir { 286*cdf0e10cSrcweir return aCalendar; 287*cdf0e10cSrcweir } 288*cdf0e10cSrcweir 289*cdf0e10cSrcweir OUString SAL_CALL 290*cdf0e10cSrcweir Calendar_gregorian::getUniqueID() throw(RuntimeException) 291*cdf0e10cSrcweir { 292*cdf0e10cSrcweir return aCalendar.Name; 293*cdf0e10cSrcweir } 294*cdf0e10cSrcweir 295*cdf0e10cSrcweir void SAL_CALL 296*cdf0e10cSrcweir Calendar_gregorian::setDateTime( double timeInDays ) throw(RuntimeException) 297*cdf0e10cSrcweir { 298*cdf0e10cSrcweir UErrorCode status; 299*cdf0e10cSrcweir body->setTime(timeInDays * U_MILLIS_PER_DAY, status = U_ZERO_ERROR); 300*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) throw ERROR; 301*cdf0e10cSrcweir getValue(); 302*cdf0e10cSrcweir } 303*cdf0e10cSrcweir 304*cdf0e10cSrcweir double SAL_CALL 305*cdf0e10cSrcweir Calendar_gregorian::getDateTime() throw(RuntimeException) 306*cdf0e10cSrcweir { 307*cdf0e10cSrcweir if (fieldSet) { 308*cdf0e10cSrcweir setValue(); 309*cdf0e10cSrcweir getValue(); 310*cdf0e10cSrcweir } 311*cdf0e10cSrcweir UErrorCode status; 312*cdf0e10cSrcweir double r = body->getTime(status = U_ZERO_ERROR); 313*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) throw ERROR; 314*cdf0e10cSrcweir return r / U_MILLIS_PER_DAY; 315*cdf0e10cSrcweir } 316*cdf0e10cSrcweir 317*cdf0e10cSrcweir // map field value from gregorian calendar to other calendar, it can be overwritten by derived class. 318*cdf0e10cSrcweir // By using eraArray, it can take care Japanese and Taiwan ROC calendar. 319*cdf0e10cSrcweir void Calendar_gregorian::mapFromGregorian() throw(RuntimeException) 320*cdf0e10cSrcweir { 321*cdf0e10cSrcweir if (eraArray) { 322*cdf0e10cSrcweir sal_Int16 e, y, m, d; 323*cdf0e10cSrcweir 324*cdf0e10cSrcweir e = fieldValue[CalendarFieldIndex::ERA]; 325*cdf0e10cSrcweir y = fieldValue[CalendarFieldIndex::YEAR]; 326*cdf0e10cSrcweir m = fieldValue[CalendarFieldIndex::MONTH] + 1; 327*cdf0e10cSrcweir d = fieldValue[CalendarFieldIndex::DAY_OF_MONTH]; 328*cdf0e10cSrcweir 329*cdf0e10cSrcweir // since the year is reversed for first era, it is reversed again here for Era compare. 330*cdf0e10cSrcweir if (e == 0) 331*cdf0e10cSrcweir y = 1 - y; 332*cdf0e10cSrcweir 333*cdf0e10cSrcweir for (e = 0; eraArray[e].year; e++) 334*cdf0e10cSrcweir if ((y != eraArray[e].year) ? y < eraArray[e].year : 335*cdf0e10cSrcweir (m != eraArray[e].month) ? m < eraArray[e].month : d < eraArray[e].day) 336*cdf0e10cSrcweir break; 337*cdf0e10cSrcweir 338*cdf0e10cSrcweir fieldValue[CalendarFieldIndex::ERA] = e; 339*cdf0e10cSrcweir fieldValue[CalendarFieldIndex::YEAR] = 340*cdf0e10cSrcweir sal::static_int_cast<sal_Int16>( (e == 0) ? (eraArray[0].year - y) : (y - eraArray[e-1].year + 1) ); 341*cdf0e10cSrcweir } 342*cdf0e10cSrcweir } 343*cdf0e10cSrcweir 344*cdf0e10cSrcweir #define FIELDS ((1 << CalendarFieldIndex::ERA) | (1 << CalendarFieldIndex::YEAR)) 345*cdf0e10cSrcweir // map field value from other calendar to gregorian calendar, it can be overwritten by derived class. 346*cdf0e10cSrcweir // By using eraArray, it can take care Japanese and Taiwan ROC calendar. 347*cdf0e10cSrcweir void Calendar_gregorian::mapToGregorian() throw(RuntimeException) 348*cdf0e10cSrcweir { 349*cdf0e10cSrcweir if (eraArray && (fieldSet & FIELDS)) { 350*cdf0e10cSrcweir sal_Int16 y, e = fieldValue[CalendarFieldIndex::ERA]; 351*cdf0e10cSrcweir if (e == 0) 352*cdf0e10cSrcweir y = sal::static_int_cast<sal_Int16>( eraArray[0].year - fieldValue[CalendarFieldIndex::YEAR] ); 353*cdf0e10cSrcweir else 354*cdf0e10cSrcweir y = sal::static_int_cast<sal_Int16>( eraArray[e-1].year + fieldValue[CalendarFieldIndex::YEAR] - 1 ); 355*cdf0e10cSrcweir 356*cdf0e10cSrcweir fieldSetValue[CalendarFieldIndex::ERA] = y <= 0 ? 0 : 1; 357*cdf0e10cSrcweir fieldSetValue[CalendarFieldIndex::YEAR] = (y <= 0 ? 1 - y : y); 358*cdf0e10cSrcweir fieldSet |= FIELDS; 359*cdf0e10cSrcweir } 360*cdf0e10cSrcweir } 361*cdf0e10cSrcweir 362*cdf0e10cSrcweir static UCalendarDateFields fieldNameConverter(sal_Int16 fieldIndex) throw(RuntimeException) 363*cdf0e10cSrcweir { 364*cdf0e10cSrcweir UCalendarDateFields f; 365*cdf0e10cSrcweir 366*cdf0e10cSrcweir switch (fieldIndex) { 367*cdf0e10cSrcweir case CalendarFieldIndex::AM_PM: f = UCAL_AM_PM; break; 368*cdf0e10cSrcweir case CalendarFieldIndex::DAY_OF_MONTH: f = UCAL_DATE; break; 369*cdf0e10cSrcweir case CalendarFieldIndex::DAY_OF_WEEK: f = UCAL_DAY_OF_WEEK; break; 370*cdf0e10cSrcweir case CalendarFieldIndex::DAY_OF_YEAR: f = UCAL_DAY_OF_YEAR; break; 371*cdf0e10cSrcweir case CalendarFieldIndex::DST_OFFSET: f = UCAL_DST_OFFSET; break; 372*cdf0e10cSrcweir case CalendarFieldIndex::ZONE_OFFSET: f = UCAL_ZONE_OFFSET; break; 373*cdf0e10cSrcweir case CalendarFieldIndex::HOUR: f = UCAL_HOUR_OF_DAY; break; 374*cdf0e10cSrcweir case CalendarFieldIndex::MINUTE: f = UCAL_MINUTE; break; 375*cdf0e10cSrcweir case CalendarFieldIndex::SECOND: f = UCAL_SECOND; break; 376*cdf0e10cSrcweir case CalendarFieldIndex::MILLISECOND: f = UCAL_MILLISECOND; break; 377*cdf0e10cSrcweir case CalendarFieldIndex::WEEK_OF_MONTH: f = UCAL_WEEK_OF_MONTH; break; 378*cdf0e10cSrcweir case CalendarFieldIndex::WEEK_OF_YEAR: f = UCAL_WEEK_OF_YEAR; break; 379*cdf0e10cSrcweir case CalendarFieldIndex::YEAR: f = UCAL_YEAR; break; 380*cdf0e10cSrcweir case CalendarFieldIndex::MONTH: f = UCAL_MONTH; break; 381*cdf0e10cSrcweir case CalendarFieldIndex::ERA: f = UCAL_ERA; break; 382*cdf0e10cSrcweir default: throw ERROR; 383*cdf0e10cSrcweir } 384*cdf0e10cSrcweir return f; 385*cdf0e10cSrcweir } 386*cdf0e10cSrcweir 387*cdf0e10cSrcweir void SAL_CALL 388*cdf0e10cSrcweir Calendar_gregorian::setValue( sal_Int16 fieldIndex, sal_Int16 value ) throw(RuntimeException) 389*cdf0e10cSrcweir { 390*cdf0e10cSrcweir if (fieldIndex < 0 || FIELD_INDEX_COUNT <= fieldIndex) 391*cdf0e10cSrcweir throw ERROR; 392*cdf0e10cSrcweir fieldSet |= (1 << fieldIndex); 393*cdf0e10cSrcweir fieldValue[fieldIndex] = value; 394*cdf0e10cSrcweir } 395*cdf0e10cSrcweir 396*cdf0e10cSrcweir bool Calendar_gregorian::getCombinedOffset( sal_Int32 & o_nOffset, 397*cdf0e10cSrcweir sal_Int16 nParentFieldIndex, sal_Int16 nChildFieldIndex ) const 398*cdf0e10cSrcweir { 399*cdf0e10cSrcweir o_nOffset = 0; 400*cdf0e10cSrcweir bool bFieldsSet = false; 401*cdf0e10cSrcweir if (fieldSet & (1 << nParentFieldIndex)) 402*cdf0e10cSrcweir { 403*cdf0e10cSrcweir bFieldsSet = true; 404*cdf0e10cSrcweir o_nOffset = static_cast<sal_Int32>( fieldValue[nParentFieldIndex]) * 60000; 405*cdf0e10cSrcweir } 406*cdf0e10cSrcweir if (fieldSet & (1 << nChildFieldIndex)) 407*cdf0e10cSrcweir { 408*cdf0e10cSrcweir bFieldsSet = true; 409*cdf0e10cSrcweir if (o_nOffset < 0) 410*cdf0e10cSrcweir o_nOffset -= static_cast<sal_uInt16>( fieldValue[nChildFieldIndex]); 411*cdf0e10cSrcweir else 412*cdf0e10cSrcweir o_nOffset += static_cast<sal_uInt16>( fieldValue[nChildFieldIndex]); 413*cdf0e10cSrcweir } 414*cdf0e10cSrcweir return bFieldsSet; 415*cdf0e10cSrcweir } 416*cdf0e10cSrcweir 417*cdf0e10cSrcweir bool Calendar_gregorian::getZoneOffset( sal_Int32 & o_nOffset ) const 418*cdf0e10cSrcweir { 419*cdf0e10cSrcweir return getCombinedOffset( o_nOffset, CalendarFieldIndex::ZONE_OFFSET, 420*cdf0e10cSrcweir CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS); 421*cdf0e10cSrcweir } 422*cdf0e10cSrcweir 423*cdf0e10cSrcweir bool Calendar_gregorian::getDSTOffset( sal_Int32 & o_nOffset ) const 424*cdf0e10cSrcweir { 425*cdf0e10cSrcweir return getCombinedOffset( o_nOffset, CalendarFieldIndex::DST_OFFSET, 426*cdf0e10cSrcweir CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS); 427*cdf0e10cSrcweir } 428*cdf0e10cSrcweir 429*cdf0e10cSrcweir void Calendar_gregorian::submitFields() throw(com::sun::star::uno::RuntimeException) 430*cdf0e10cSrcweir { 431*cdf0e10cSrcweir for (sal_Int16 fieldIndex = 0; fieldIndex < FIELD_INDEX_COUNT; fieldIndex++) 432*cdf0e10cSrcweir { 433*cdf0e10cSrcweir if (fieldSet & (1 << fieldIndex)) 434*cdf0e10cSrcweir { 435*cdf0e10cSrcweir switch (fieldIndex) 436*cdf0e10cSrcweir { 437*cdf0e10cSrcweir default: 438*cdf0e10cSrcweir body->set(fieldNameConverter(fieldIndex), fieldSetValue[fieldIndex]); 439*cdf0e10cSrcweir break; 440*cdf0e10cSrcweir case CalendarFieldIndex::ZONE_OFFSET: 441*cdf0e10cSrcweir case CalendarFieldIndex::DST_OFFSET: 442*cdf0e10cSrcweir case CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS: 443*cdf0e10cSrcweir case CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS: 444*cdf0e10cSrcweir break; // nothing, extra handling 445*cdf0e10cSrcweir } 446*cdf0e10cSrcweir } 447*cdf0e10cSrcweir } 448*cdf0e10cSrcweir sal_Int32 nZoneOffset, nDSTOffset; 449*cdf0e10cSrcweir if (getZoneOffset( nZoneOffset)) 450*cdf0e10cSrcweir body->set( fieldNameConverter( CalendarFieldIndex::ZONE_OFFSET), nZoneOffset); 451*cdf0e10cSrcweir if (getDSTOffset( nDSTOffset)) 452*cdf0e10cSrcweir body->set( fieldNameConverter( CalendarFieldIndex::DST_OFFSET), nDSTOffset); 453*cdf0e10cSrcweir } 454*cdf0e10cSrcweir 455*cdf0e10cSrcweir void Calendar_gregorian::submitValues( sal_Int32 nYear, 456*cdf0e10cSrcweir sal_Int32 nMonth, sal_Int32 nDay, sal_Int32 nHour, sal_Int32 nMinute, 457*cdf0e10cSrcweir sal_Int32 nSecond, sal_Int32 nMilliSecond, sal_Int32 nZone, sal_Int32 nDST ) 458*cdf0e10cSrcweir throw(com::sun::star::uno::RuntimeException) 459*cdf0e10cSrcweir { 460*cdf0e10cSrcweir submitFields(); 461*cdf0e10cSrcweir if (nYear >= 0) 462*cdf0e10cSrcweir body->set( UCAL_YEAR, nYear); 463*cdf0e10cSrcweir if (nMonth >= 0) 464*cdf0e10cSrcweir body->set( UCAL_MONTH, nMonth); 465*cdf0e10cSrcweir if (nDay >= 0) 466*cdf0e10cSrcweir body->set( UCAL_DATE, nDay); 467*cdf0e10cSrcweir if (nHour >= 0) 468*cdf0e10cSrcweir body->set( UCAL_HOUR_OF_DAY, nHour); 469*cdf0e10cSrcweir if (nMinute >= 0) 470*cdf0e10cSrcweir body->set( UCAL_MINUTE, nMinute); 471*cdf0e10cSrcweir if (nSecond >= 0) 472*cdf0e10cSrcweir body->set( UCAL_SECOND, nSecond); 473*cdf0e10cSrcweir if (nMilliSecond >= 0) 474*cdf0e10cSrcweir body->set( UCAL_MILLISECOND, nMilliSecond); 475*cdf0e10cSrcweir if (nZone != 0) 476*cdf0e10cSrcweir body->set( UCAL_ZONE_OFFSET, nZone); 477*cdf0e10cSrcweir if (nDST != 0) 478*cdf0e10cSrcweir body->set( UCAL_DST_OFFSET, nDST); 479*cdf0e10cSrcweir } 480*cdf0e10cSrcweir 481*cdf0e10cSrcweir static void lcl_setCombinedOffsetFieldValues( sal_Int32 nValue, 482*cdf0e10cSrcweir sal_Int16 rFieldSetValue[], sal_Int16 rFieldValue[], 483*cdf0e10cSrcweir sal_Int16 nParentFieldIndex, sal_Int16 nChildFieldIndex ) 484*cdf0e10cSrcweir { 485*cdf0e10cSrcweir sal_Int32 nTrunc = nValue / 60000; 486*cdf0e10cSrcweir rFieldSetValue[nParentFieldIndex] = rFieldValue[nParentFieldIndex] = 487*cdf0e10cSrcweir static_cast<sal_Int16>( nTrunc); 488*cdf0e10cSrcweir sal_uInt16 nMillis = static_cast<sal_uInt16>( abs( nValue - nTrunc * 60000)); 489*cdf0e10cSrcweir rFieldSetValue[nChildFieldIndex] = rFieldValue[nChildFieldIndex] = 490*cdf0e10cSrcweir static_cast<sal_Int16>( nMillis); 491*cdf0e10cSrcweir } 492*cdf0e10cSrcweir 493*cdf0e10cSrcweir void Calendar_gregorian::setValue() throw(RuntimeException) 494*cdf0e10cSrcweir { 495*cdf0e10cSrcweir // Correct DST glitch, see also localtime/gmtime conversion pitfalls at 496*cdf0e10cSrcweir // http://www.erack.de/download/timetest.c 497*cdf0e10cSrcweir // 498*cdf0e10cSrcweir // #i24082# in order to make the DST correction work in all 499*cdf0e10cSrcweir // circumstances, the time values have to be always resubmitted, 500*cdf0e10cSrcweir // regardless whether specified by the caller or not. It is not 501*cdf0e10cSrcweir // sufficient to rely on the ICU internal values previously set, as the 502*cdf0e10cSrcweir // following may happen: 503*cdf0e10cSrcweir // - Let 2004-03-28T02:00 be the onsetRule. 504*cdf0e10cSrcweir // - On 2004-03-29 (calendar initialized with 2004-03-29T00:00 DST) set 505*cdf0e10cSrcweir // a date of 2004-03-28 => calendar results in 2004-03-27T23:00 no DST. 506*cdf0e10cSrcweir // - Correcting this with simply "2004-03-28 no DST" and no time 507*cdf0e10cSrcweir // specified results in 2004-03-29T00:00, the ICU internal 23:00 time 508*cdf0e10cSrcweir // being adjusted to 24:00 in this case, switching one day further. 509*cdf0e10cSrcweir // => submit 2004-03-28T00:00 no DST. 510*cdf0e10cSrcweir 511*cdf0e10cSrcweir // This got even weirder since ICU incorporated also historical data, 512*cdf0e10cSrcweir // even the timezone may differ for different dates! It is necessary to 513*cdf0e10cSrcweir // let ICU choose the corresponding OlsonTimeZone transitions and adapt 514*cdf0e10cSrcweir // values. 515*cdf0e10cSrcweir // #i86094# gives examples where that went wrong: 516*cdf0e10cSrcweir // TZ=Europe/Moscow date <= 1919-07-01 517*cdf0e10cSrcweir // zone +2:30:48 (!) instead of +3h, DST +2h instead of +1h 518*cdf0e10cSrcweir // TZ=America/St_Johns date <= 1935-03-30 519*cdf0e10cSrcweir // zone -3:30:52 (!) instead of -3:30 520*cdf0e10cSrcweir 521*cdf0e10cSrcweir // Copy fields before calling submitFields() directly or indirectly below. 522*cdf0e10cSrcweir memcpy(fieldSetValue, fieldValue, sizeof(fieldSetValue)); 523*cdf0e10cSrcweir // Possibly setup ERA and YEAR in fieldSetValue. 524*cdf0e10cSrcweir mapToGregorian(); 525*cdf0e10cSrcweir 526*cdf0e10cSrcweir DUMP_ICU_CAL_MSG(("%s\n","setValue() before any submission")); 527*cdf0e10cSrcweir DUMP_I18N_CAL_MSG(("%s\n","setValue() before any submission")); 528*cdf0e10cSrcweir 529*cdf0e10cSrcweir bool bNeedZone = !(fieldSet & (1 << CalendarFieldIndex::ZONE_OFFSET)); 530*cdf0e10cSrcweir bool bNeedDST = !(fieldSet & (1 << CalendarFieldIndex::DST_OFFSET)); 531*cdf0e10cSrcweir sal_Int32 nZone1, nDST1, nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilliSecond, nZone0, nDST0; 532*cdf0e10cSrcweir nZone1 = nDST1 = nZone0 = nDST0 = 0; 533*cdf0e10cSrcweir nYear = nMonth = nDay = nHour = nMinute = nSecond = nMilliSecond = -1; 534*cdf0e10cSrcweir if ( bNeedZone || bNeedDST ) 535*cdf0e10cSrcweir { 536*cdf0e10cSrcweir UErrorCode status; 537*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::YEAR)) ) 538*cdf0e10cSrcweir { 539*cdf0e10cSrcweir nYear = body->get( UCAL_YEAR, status = U_ZERO_ERROR); 540*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 541*cdf0e10cSrcweir nYear = -1; 542*cdf0e10cSrcweir } 543*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::MONTH)) ) 544*cdf0e10cSrcweir { 545*cdf0e10cSrcweir nMonth = body->get( UCAL_MONTH, status = U_ZERO_ERROR); 546*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 547*cdf0e10cSrcweir nMonth = -1; 548*cdf0e10cSrcweir } 549*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::DAY_OF_MONTH)) ) 550*cdf0e10cSrcweir { 551*cdf0e10cSrcweir nDay = body->get( UCAL_DATE, status = U_ZERO_ERROR); 552*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 553*cdf0e10cSrcweir nDay = -1; 554*cdf0e10cSrcweir } 555*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::HOUR)) ) 556*cdf0e10cSrcweir { 557*cdf0e10cSrcweir nHour = body->get( UCAL_HOUR_OF_DAY, status = U_ZERO_ERROR); 558*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 559*cdf0e10cSrcweir nHour = -1; 560*cdf0e10cSrcweir } 561*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::MINUTE)) ) 562*cdf0e10cSrcweir { 563*cdf0e10cSrcweir nMinute = body->get( UCAL_MINUTE, status = U_ZERO_ERROR); 564*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 565*cdf0e10cSrcweir nMinute = -1; 566*cdf0e10cSrcweir } 567*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::SECOND)) ) 568*cdf0e10cSrcweir { 569*cdf0e10cSrcweir nSecond = body->get( UCAL_SECOND, status = U_ZERO_ERROR); 570*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 571*cdf0e10cSrcweir nSecond = -1; 572*cdf0e10cSrcweir } 573*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::MILLISECOND)) ) 574*cdf0e10cSrcweir { 575*cdf0e10cSrcweir nMilliSecond = body->get( UCAL_MILLISECOND, status = U_ZERO_ERROR); 576*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 577*cdf0e10cSrcweir nMilliSecond = -1; 578*cdf0e10cSrcweir } 579*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::ZONE_OFFSET)) ) 580*cdf0e10cSrcweir { 581*cdf0e10cSrcweir nZone0 = body->get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR); 582*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 583*cdf0e10cSrcweir nZone0 = 0; 584*cdf0e10cSrcweir } 585*cdf0e10cSrcweir if ( !(fieldSet & (1 << CalendarFieldIndex::DST_OFFSET)) ) 586*cdf0e10cSrcweir { 587*cdf0e10cSrcweir nDST0 = body->get( UCAL_DST_OFFSET, status = U_ZERO_ERROR); 588*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 589*cdf0e10cSrcweir nDST0 = 0; 590*cdf0e10cSrcweir } 591*cdf0e10cSrcweir 592*cdf0e10cSrcweir // Submit values to obtain a time zone and DST corresponding to the date/time. 593*cdf0e10cSrcweir submitValues( nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilliSecond, nZone0, nDST0); 594*cdf0e10cSrcweir 595*cdf0e10cSrcweir DUMP_ICU_CAL_MSG(("%s\n","setValue() in bNeedZone||bNeedDST after submitValues()")); 596*cdf0e10cSrcweir DUMP_I18N_CAL_MSG(("%s\n","setValue() in bNeedZone||bNeedDST after submitValues()")); 597*cdf0e10cSrcweir nZone1 = body->get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR); 598*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 599*cdf0e10cSrcweir nZone1 = 0; 600*cdf0e10cSrcweir nDST1 = body->get( UCAL_DST_OFFSET, status = U_ZERO_ERROR); 601*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 602*cdf0e10cSrcweir nDST1 = 0; 603*cdf0e10cSrcweir } 604*cdf0e10cSrcweir 605*cdf0e10cSrcweir // The original submission, may lead to a different zone/DST and 606*cdf0e10cSrcweir // different date. 607*cdf0e10cSrcweir submitFields(); 608*cdf0e10cSrcweir DUMP_ICU_CAL_MSG(("%s\n","setValue() after original submission")); 609*cdf0e10cSrcweir DUMP_I18N_CAL_MSG(("%s\n","setValue() after original submission")); 610*cdf0e10cSrcweir 611*cdf0e10cSrcweir if ( bNeedZone || bNeedDST ) 612*cdf0e10cSrcweir { 613*cdf0e10cSrcweir UErrorCode status; 614*cdf0e10cSrcweir sal_Int32 nZone2 = body->get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR); 615*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 616*cdf0e10cSrcweir nZone2 = nZone1; 617*cdf0e10cSrcweir sal_Int32 nDST2 = body->get( UCAL_DST_OFFSET, status = U_ZERO_ERROR); 618*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 619*cdf0e10cSrcweir nDST2 = nDST1; 620*cdf0e10cSrcweir if ( nZone0 != nZone1 || nZone2 != nZone1 || nDST0 != nDST1 || nDST2 != nDST1 ) 621*cdf0e10cSrcweir { 622*cdf0e10cSrcweir // Due to different DSTs, resulting date values may differ if 623*cdf0e10cSrcweir // DST is onset at 00:00 and the very onsetRule date was 624*cdf0e10cSrcweir // submitted with DST off => date-1 23:00, for example, which 625*cdf0e10cSrcweir // is not what we want. 626*cdf0e10cSrcweir // Resubmit all values, this time including DST => date 01:00 627*cdf0e10cSrcweir // Similar for zone differences. 628*cdf0e10cSrcweir // If already the first full submission with nZone0 and nDST0 629*cdf0e10cSrcweir // lead to date-1 23:00, the original submission was based on 630*cdf0e10cSrcweir // that date if it wasn't a full date (nDST0 set, nDST1 not 631*cdf0e10cSrcweir // set, nDST2==nDST1). If it was January 1st without year we're 632*cdf0e10cSrcweir // even off by one year now. Resubmit all values including new 633*cdf0e10cSrcweir // DST => date 00:00. 634*cdf0e10cSrcweir 635*cdf0e10cSrcweir // Set field values accordingly in case they were used. 636*cdf0e10cSrcweir if (!bNeedZone) 637*cdf0e10cSrcweir lcl_setCombinedOffsetFieldValues( nZone2, fieldSetValue, 638*cdf0e10cSrcweir fieldValue, CalendarFieldIndex::ZONE_OFFSET, 639*cdf0e10cSrcweir CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS); 640*cdf0e10cSrcweir if (!bNeedDST) 641*cdf0e10cSrcweir lcl_setCombinedOffsetFieldValues( nDST2, fieldSetValue, 642*cdf0e10cSrcweir fieldValue, CalendarFieldIndex::DST_OFFSET, 643*cdf0e10cSrcweir CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS); 644*cdf0e10cSrcweir submitValues( nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilliSecond, nZone2, nDST2); 645*cdf0e10cSrcweir DUMP_ICU_CAL_MSG(("%s\n","setValue() after Zone/DST glitch resubmit")); 646*cdf0e10cSrcweir DUMP_I18N_CAL_MSG(("%s\n","setValue() after Zone/DST glitch resubmit")); 647*cdf0e10cSrcweir 648*cdf0e10cSrcweir // Time zone transition => resubmit. 649*cdf0e10cSrcweir // TZ=America/St_Johns date <= 1935-03-30 650*cdf0e10cSrcweir // -3:30:52 (!) instead of -3:30 651*cdf0e10cSrcweir // if first submission included time zone -3:30 that would be wrong. 652*cdf0e10cSrcweir bool bResubmit = false; 653*cdf0e10cSrcweir sal_Int32 nZone3 = body->get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR); 654*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 655*cdf0e10cSrcweir nZone3 = nZone2; 656*cdf0e10cSrcweir if (nZone3 != nZone2) 657*cdf0e10cSrcweir { 658*cdf0e10cSrcweir bResubmit = true; 659*cdf0e10cSrcweir if (!bNeedZone) 660*cdf0e10cSrcweir lcl_setCombinedOffsetFieldValues( nZone3, fieldSetValue, 661*cdf0e10cSrcweir fieldValue, CalendarFieldIndex::ZONE_OFFSET, 662*cdf0e10cSrcweir CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS); 663*cdf0e10cSrcweir } 664*cdf0e10cSrcweir 665*cdf0e10cSrcweir // If the DST onset rule says to switch from 00:00 to 01:00 and 666*cdf0e10cSrcweir // we tried to set onsetDay 00:00 with DST, the result was 667*cdf0e10cSrcweir // onsetDay-1 23:00 and no DST, which is not what we want. So 668*cdf0e10cSrcweir // once again without DST, resulting in onsetDay 01:00 and DST. 669*cdf0e10cSrcweir // Yes, this seems to be weird, but logically correct. 670*cdf0e10cSrcweir // It doesn't even have to be on an onsetDay as the DST is 671*cdf0e10cSrcweir // factored in all days by ICU and there seems to be some 672*cdf0e10cSrcweir // unknown behavior. 673*cdf0e10cSrcweir // TZ=Asia/Tehran 1999-03-22 exposes this, for example. 674*cdf0e10cSrcweir sal_Int32 nDST3 = body->get( UCAL_DST_OFFSET, status = U_ZERO_ERROR); 675*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) 676*cdf0e10cSrcweir nDST3 = nDST2; 677*cdf0e10cSrcweir if (nDST2 != nDST3 && !nDST3) 678*cdf0e10cSrcweir { 679*cdf0e10cSrcweir bResubmit = true; 680*cdf0e10cSrcweir if (!bNeedDST) 681*cdf0e10cSrcweir { 682*cdf0e10cSrcweir fieldSetValue[CalendarFieldIndex::DST_OFFSET] = 683*cdf0e10cSrcweir fieldValue[CalendarFieldIndex::DST_OFFSET] = 0; 684*cdf0e10cSrcweir fieldSetValue[CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS] = 685*cdf0e10cSrcweir fieldValue[CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS] = 0; 686*cdf0e10cSrcweir } 687*cdf0e10cSrcweir } 688*cdf0e10cSrcweir if (bResubmit) 689*cdf0e10cSrcweir { 690*cdf0e10cSrcweir submitValues( nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilliSecond, nZone3, nDST3); 691*cdf0e10cSrcweir DUMP_ICU_CAL_MSG(("%s\n","setValue() after Zone/DST glitch 2nd resubmit")); 692*cdf0e10cSrcweir DUMP_I18N_CAL_MSG(("%s\n","setValue() after Zone/DST glitch 2nd resubmit")); 693*cdf0e10cSrcweir } 694*cdf0e10cSrcweir } 695*cdf0e10cSrcweir } 696*cdf0e10cSrcweir #if erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR 697*cdf0e10cSrcweir { 698*cdf0e10cSrcweir // force icu::Calendar to recalculate 699*cdf0e10cSrcweir UErrorCode status; 700*cdf0e10cSrcweir sal_Int32 nTmp = body->get( UCAL_DATE, status = U_ZERO_ERROR); 701*cdf0e10cSrcweir DUMP_ICU_CAL_MSG(("%s: %d\n","setValue() result day",nTmp)); 702*cdf0e10cSrcweir DUMP_I18N_CAL_MSG(("%s: %d\n","setValue() result day",nTmp)); 703*cdf0e10cSrcweir } 704*cdf0e10cSrcweir #endif 705*cdf0e10cSrcweir } 706*cdf0e10cSrcweir 707*cdf0e10cSrcweir void Calendar_gregorian::getValue() throw(RuntimeException) 708*cdf0e10cSrcweir { 709*cdf0e10cSrcweir DUMP_ICU_CAL_MSG(("%s\n","getValue()")); 710*cdf0e10cSrcweir DUMP_I18N_CAL_MSG(("%s\n","getValue()")); 711*cdf0e10cSrcweir for (sal_Int16 fieldIndex = 0; fieldIndex < FIELD_INDEX_COUNT; fieldIndex++) 712*cdf0e10cSrcweir { 713*cdf0e10cSrcweir if (fieldIndex == CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS || 714*cdf0e10cSrcweir fieldIndex == CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS) 715*cdf0e10cSrcweir continue; // not ICU fields 716*cdf0e10cSrcweir 717*cdf0e10cSrcweir UErrorCode status; sal_Int32 value = body->get( fieldNameConverter( 718*cdf0e10cSrcweir fieldIndex), status = U_ZERO_ERROR); 719*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) throw ERROR; 720*cdf0e10cSrcweir 721*cdf0e10cSrcweir // Convert millisecond to minute for ZONE and DST and set remainder in 722*cdf0e10cSrcweir // second field. 723*cdf0e10cSrcweir if (fieldIndex == CalendarFieldIndex::ZONE_OFFSET) 724*cdf0e10cSrcweir { 725*cdf0e10cSrcweir sal_Int32 nMinutes = value / 60000; 726*cdf0e10cSrcweir sal_Int16 nMillis = static_cast<sal_Int16>( static_cast<sal_uInt16>( 727*cdf0e10cSrcweir abs( value - nMinutes * 60000))); 728*cdf0e10cSrcweir fieldValue[CalendarFieldIndex::ZONE_OFFSET] = static_cast<sal_Int16>( nMinutes); 729*cdf0e10cSrcweir fieldValue[CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS] = nMillis; 730*cdf0e10cSrcweir } 731*cdf0e10cSrcweir else if (fieldIndex == CalendarFieldIndex::DST_OFFSET) 732*cdf0e10cSrcweir { 733*cdf0e10cSrcweir sal_Int32 nMinutes = value / 60000; 734*cdf0e10cSrcweir sal_Int16 nMillis = static_cast<sal_Int16>( static_cast<sal_uInt16>( 735*cdf0e10cSrcweir abs( value - nMinutes * 60000))); 736*cdf0e10cSrcweir fieldValue[CalendarFieldIndex::DST_OFFSET] = static_cast<sal_Int16>( nMinutes); 737*cdf0e10cSrcweir fieldValue[CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS] = nMillis; 738*cdf0e10cSrcweir } 739*cdf0e10cSrcweir else 740*cdf0e10cSrcweir fieldValue[fieldIndex] = (sal_Int16) value; 741*cdf0e10cSrcweir 742*cdf0e10cSrcweir // offset 1 since the value for week start day SunDay is different between Calendar and Weekdays. 743*cdf0e10cSrcweir if ( fieldIndex == CalendarFieldIndex::DAY_OF_WEEK ) 744*cdf0e10cSrcweir fieldValue[fieldIndex]--; // UCAL_SUNDAY:/* == 1 */ ==> Weekdays::SUNDAY /* ==0 */ 745*cdf0e10cSrcweir } 746*cdf0e10cSrcweir mapFromGregorian(); 747*cdf0e10cSrcweir fieldSet = 0; 748*cdf0e10cSrcweir } 749*cdf0e10cSrcweir 750*cdf0e10cSrcweir sal_Int16 SAL_CALL 751*cdf0e10cSrcweir Calendar_gregorian::getValue( sal_Int16 fieldIndex ) throw(RuntimeException) 752*cdf0e10cSrcweir { 753*cdf0e10cSrcweir if (fieldIndex < 0 || FIELD_INDEX_COUNT <= fieldIndex) 754*cdf0e10cSrcweir throw ERROR; 755*cdf0e10cSrcweir 756*cdf0e10cSrcweir if (fieldSet) { 757*cdf0e10cSrcweir setValue(); 758*cdf0e10cSrcweir getValue(); 759*cdf0e10cSrcweir } 760*cdf0e10cSrcweir 761*cdf0e10cSrcweir return fieldValue[fieldIndex]; 762*cdf0e10cSrcweir } 763*cdf0e10cSrcweir 764*cdf0e10cSrcweir void SAL_CALL 765*cdf0e10cSrcweir Calendar_gregorian::addValue( sal_Int16 fieldIndex, sal_Int32 value ) throw(RuntimeException) 766*cdf0e10cSrcweir { 767*cdf0e10cSrcweir // since ZONE and DST could not be add, we don't need to convert value here 768*cdf0e10cSrcweir UErrorCode status; 769*cdf0e10cSrcweir body->add(fieldNameConverter(fieldIndex), value, status = U_ZERO_ERROR); 770*cdf0e10cSrcweir if ( !U_SUCCESS(status) ) throw ERROR; 771*cdf0e10cSrcweir getValue(); 772*cdf0e10cSrcweir } 773*cdf0e10cSrcweir 774*cdf0e10cSrcweir sal_Bool SAL_CALL 775*cdf0e10cSrcweir Calendar_gregorian::isValid() throw(RuntimeException) 776*cdf0e10cSrcweir { 777*cdf0e10cSrcweir if (fieldSet) { 778*cdf0e10cSrcweir sal_Int32 tmp = fieldSet; 779*cdf0e10cSrcweir setValue(); 780*cdf0e10cSrcweir memcpy(fieldSetValue, fieldValue, sizeof(fieldSetValue)); 781*cdf0e10cSrcweir getValue(); 782*cdf0e10cSrcweir for ( sal_Int16 fieldIndex = 0; fieldIndex < FIELD_INDEX_COUNT; fieldIndex++ ) { 783*cdf0e10cSrcweir // compare only with fields that are set and reset fieldSet[] 784*cdf0e10cSrcweir if (tmp & (1 << fieldIndex)) { 785*cdf0e10cSrcweir if (fieldSetValue[fieldIndex] != fieldValue[fieldIndex]) 786*cdf0e10cSrcweir return sal_False; 787*cdf0e10cSrcweir } 788*cdf0e10cSrcweir } 789*cdf0e10cSrcweir } 790*cdf0e10cSrcweir return true; 791*cdf0e10cSrcweir } 792*cdf0e10cSrcweir 793*cdf0e10cSrcweir // NativeNumberMode has different meaning between Number and Calendar for Asian locales. 794*cdf0e10cSrcweir // Here is the mapping table 795*cdf0e10cSrcweir // calendar(q/y/m/d) zh_CN zh_TW ja ko 796*cdf0e10cSrcweir // NatNum1 NatNum1/1/7/7 NatNum1/1/7/7 NatNum1/1/4/4 NatNum1/1/7/7 797*cdf0e10cSrcweir // NatNum2 NatNum2/2/8/8 NatNum2/2/8/8 NatNum2/2/5/5 NatNum2/2/8/8 798*cdf0e10cSrcweir // NatNum3 NatNum3/3/3/3 NatNum3/3/3/3 NatNum3/3/3/3 NatNum3/3/3/3 799*cdf0e10cSrcweir // NatNum4 NatNum9/9/11/11 800*cdf0e10cSrcweir 801*cdf0e10cSrcweir static sal_Int16 SAL_CALL NatNumForCalendar(const com::sun::star::lang::Locale& aLocale, 802*cdf0e10cSrcweir sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode, sal_Int16 value ) 803*cdf0e10cSrcweir { 804*cdf0e10cSrcweir sal_Bool isShort = ((nCalendarDisplayCode == CalendarDisplayCode::SHORT_YEAR || 805*cdf0e10cSrcweir nCalendarDisplayCode == CalendarDisplayCode::LONG_YEAR) && value >= 100) || 806*cdf0e10cSrcweir nCalendarDisplayCode == CalendarDisplayCode::SHORT_QUARTER || 807*cdf0e10cSrcweir nCalendarDisplayCode == CalendarDisplayCode::LONG_QUARTER; 808*cdf0e10cSrcweir sal_Bool isChinese = aLocale.Language.equalsAscii("zh"); 809*cdf0e10cSrcweir sal_Bool isJapanese = aLocale.Language.equalsAscii("ja"); 810*cdf0e10cSrcweir sal_Bool isKorean = aLocale.Language.equalsAscii("ko"); 811*cdf0e10cSrcweir 812*cdf0e10cSrcweir if (isChinese || isJapanese || isKorean) { 813*cdf0e10cSrcweir switch (nNativeNumberMode) { 814*cdf0e10cSrcweir case NativeNumberMode::NATNUM1: 815*cdf0e10cSrcweir if (!isShort) 816*cdf0e10cSrcweir nNativeNumberMode = isJapanese ? NativeNumberMode::NATNUM4 : NativeNumberMode::NATNUM7; 817*cdf0e10cSrcweir break; 818*cdf0e10cSrcweir case NativeNumberMode::NATNUM2: 819*cdf0e10cSrcweir if (!isShort) 820*cdf0e10cSrcweir nNativeNumberMode = isJapanese ? NativeNumberMode::NATNUM5 : NativeNumberMode::NATNUM8; 821*cdf0e10cSrcweir break; 822*cdf0e10cSrcweir case NativeNumberMode::NATNUM3: 823*cdf0e10cSrcweir break; 824*cdf0e10cSrcweir case NativeNumberMode::NATNUM4: 825*cdf0e10cSrcweir if (isKorean) 826*cdf0e10cSrcweir return isShort ? NativeNumberMode::NATNUM9 : NativeNumberMode::NATNUM11; 827*cdf0e10cSrcweir // fall through 828*cdf0e10cSrcweir default: return 0; 829*cdf0e10cSrcweir } 830*cdf0e10cSrcweir } 831*cdf0e10cSrcweir return nNativeNumberMode; 832*cdf0e10cSrcweir } 833*cdf0e10cSrcweir 834*cdf0e10cSrcweir static sal_Int32 SAL_CALL DisplayCode2FieldIndex(sal_Int32 nCalendarDisplayCode) 835*cdf0e10cSrcweir { 836*cdf0e10cSrcweir switch( nCalendarDisplayCode ) { 837*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_DAY: 838*cdf0e10cSrcweir case CalendarDisplayCode::LONG_DAY: 839*cdf0e10cSrcweir return CalendarFieldIndex::DAY_OF_MONTH; 840*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_DAY_NAME: 841*cdf0e10cSrcweir case CalendarDisplayCode::LONG_DAY_NAME: 842*cdf0e10cSrcweir return CalendarFieldIndex::DAY_OF_WEEK; 843*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_QUARTER: 844*cdf0e10cSrcweir case CalendarDisplayCode::LONG_QUARTER: 845*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_MONTH: 846*cdf0e10cSrcweir case CalendarDisplayCode::LONG_MONTH: 847*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_MONTH_NAME: 848*cdf0e10cSrcweir case CalendarDisplayCode::LONG_MONTH_NAME: 849*cdf0e10cSrcweir return CalendarFieldIndex::MONTH; 850*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_YEAR: 851*cdf0e10cSrcweir case CalendarDisplayCode::LONG_YEAR: 852*cdf0e10cSrcweir return CalendarFieldIndex::YEAR; 853*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_ERA: 854*cdf0e10cSrcweir case CalendarDisplayCode::LONG_ERA: 855*cdf0e10cSrcweir return CalendarFieldIndex::ERA; 856*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_YEAR_AND_ERA: 857*cdf0e10cSrcweir case CalendarDisplayCode::LONG_YEAR_AND_ERA: 858*cdf0e10cSrcweir return CalendarFieldIndex::YEAR; 859*cdf0e10cSrcweir default: 860*cdf0e10cSrcweir return 0; 861*cdf0e10cSrcweir } 862*cdf0e10cSrcweir } 863*cdf0e10cSrcweir 864*cdf0e10cSrcweir sal_Int16 SAL_CALL 865*cdf0e10cSrcweir Calendar_gregorian::getFirstDayOfWeek() throw(RuntimeException) 866*cdf0e10cSrcweir { 867*cdf0e10cSrcweir // UCAL_SUNDAY == 1, Weekdays::SUNDAY == 0 => offset -1 868*cdf0e10cSrcweir // Check for underflow just in case we're called "out of sync". 869*cdf0e10cSrcweir return ::std::max( sal::static_int_cast<sal_Int16>(0), 870*cdf0e10cSrcweir sal::static_int_cast<sal_Int16>( static_cast<sal_Int16>( 871*cdf0e10cSrcweir body->getFirstDayOfWeek()) - 1)); 872*cdf0e10cSrcweir } 873*cdf0e10cSrcweir 874*cdf0e10cSrcweir void SAL_CALL 875*cdf0e10cSrcweir Calendar_gregorian::setFirstDayOfWeek( sal_Int16 day ) 876*cdf0e10cSrcweir throw(RuntimeException) 877*cdf0e10cSrcweir { 878*cdf0e10cSrcweir // Weekdays::SUNDAY == 0, UCAL_SUNDAY == 1 => offset +1 879*cdf0e10cSrcweir body->setFirstDayOfWeek( static_cast<UCalendarDaysOfWeek>( day + 1)); 880*cdf0e10cSrcweir } 881*cdf0e10cSrcweir 882*cdf0e10cSrcweir void SAL_CALL 883*cdf0e10cSrcweir Calendar_gregorian::setMinimumNumberOfDaysForFirstWeek( sal_Int16 days ) throw(RuntimeException) 884*cdf0e10cSrcweir { 885*cdf0e10cSrcweir aCalendar.MinimumNumberOfDaysForFirstWeek = days; 886*cdf0e10cSrcweir body->setMinimalDaysInFirstWeek( static_cast<uint8_t>( days)); 887*cdf0e10cSrcweir } 888*cdf0e10cSrcweir 889*cdf0e10cSrcweir sal_Int16 SAL_CALL 890*cdf0e10cSrcweir Calendar_gregorian::getMinimumNumberOfDaysForFirstWeek() throw(RuntimeException) 891*cdf0e10cSrcweir { 892*cdf0e10cSrcweir return aCalendar.MinimumNumberOfDaysForFirstWeek; 893*cdf0e10cSrcweir } 894*cdf0e10cSrcweir 895*cdf0e10cSrcweir sal_Int16 SAL_CALL 896*cdf0e10cSrcweir Calendar_gregorian::getNumberOfMonthsInYear() throw(RuntimeException) 897*cdf0e10cSrcweir { 898*cdf0e10cSrcweir return (sal_Int16) aCalendar.Months.getLength(); 899*cdf0e10cSrcweir } 900*cdf0e10cSrcweir 901*cdf0e10cSrcweir 902*cdf0e10cSrcweir sal_Int16 SAL_CALL 903*cdf0e10cSrcweir Calendar_gregorian::getNumberOfDaysInWeek() throw(RuntimeException) 904*cdf0e10cSrcweir { 905*cdf0e10cSrcweir return (sal_Int16) aCalendar.Days.getLength(); 906*cdf0e10cSrcweir } 907*cdf0e10cSrcweir 908*cdf0e10cSrcweir 909*cdf0e10cSrcweir Sequence< CalendarItem > SAL_CALL 910*cdf0e10cSrcweir Calendar_gregorian::getMonths() throw(RuntimeException) 911*cdf0e10cSrcweir { 912*cdf0e10cSrcweir return aCalendar.Months; 913*cdf0e10cSrcweir } 914*cdf0e10cSrcweir 915*cdf0e10cSrcweir 916*cdf0e10cSrcweir Sequence< CalendarItem > SAL_CALL 917*cdf0e10cSrcweir Calendar_gregorian::getDays() throw(RuntimeException) 918*cdf0e10cSrcweir { 919*cdf0e10cSrcweir return aCalendar.Days; 920*cdf0e10cSrcweir } 921*cdf0e10cSrcweir 922*cdf0e10cSrcweir OUString SAL_CALL 923*cdf0e10cSrcweir Calendar_gregorian::getDisplayName( sal_Int16 displayIndex, sal_Int16 idx, sal_Int16 nameType ) throw(RuntimeException) 924*cdf0e10cSrcweir { 925*cdf0e10cSrcweir OUString aStr; 926*cdf0e10cSrcweir 927*cdf0e10cSrcweir switch( displayIndex ) { 928*cdf0e10cSrcweir case CalendarDisplayIndex::AM_PM:/* ==0 */ 929*cdf0e10cSrcweir if (idx == 0) aStr = LocaleData().getLocaleItem(aLocale).timeAM; 930*cdf0e10cSrcweir else if (idx == 1) aStr = LocaleData().getLocaleItem(aLocale).timePM; 931*cdf0e10cSrcweir else throw ERROR; 932*cdf0e10cSrcweir break; 933*cdf0e10cSrcweir case CalendarDisplayIndex::DAY: 934*cdf0e10cSrcweir if( idx >= aCalendar.Days.getLength() ) throw ERROR; 935*cdf0e10cSrcweir if (nameType == 0) aStr = aCalendar.Days[idx].AbbrevName; 936*cdf0e10cSrcweir else if (nameType == 1) aStr = aCalendar.Days[idx].FullName; 937*cdf0e10cSrcweir else throw ERROR; 938*cdf0e10cSrcweir break; 939*cdf0e10cSrcweir case CalendarDisplayIndex::MONTH: 940*cdf0e10cSrcweir if( idx >= aCalendar.Months.getLength() ) throw ERROR; 941*cdf0e10cSrcweir if (nameType == 0) aStr = aCalendar.Months[idx].AbbrevName; 942*cdf0e10cSrcweir else if (nameType == 1) aStr = aCalendar.Months[idx].FullName; 943*cdf0e10cSrcweir else throw ERROR; 944*cdf0e10cSrcweir break; 945*cdf0e10cSrcweir case CalendarDisplayIndex::ERA: 946*cdf0e10cSrcweir if( idx >= aCalendar.Eras.getLength() ) throw ERROR; 947*cdf0e10cSrcweir if (nameType == 0) aStr = aCalendar.Eras[idx].AbbrevName; 948*cdf0e10cSrcweir else if (nameType == 1) aStr = aCalendar.Eras[idx].FullName; 949*cdf0e10cSrcweir else throw ERROR; 950*cdf0e10cSrcweir break; 951*cdf0e10cSrcweir case CalendarDisplayIndex::YEAR: 952*cdf0e10cSrcweir break; 953*cdf0e10cSrcweir default: 954*cdf0e10cSrcweir throw ERROR; 955*cdf0e10cSrcweir } 956*cdf0e10cSrcweir return aStr; 957*cdf0e10cSrcweir } 958*cdf0e10cSrcweir 959*cdf0e10cSrcweir // Methods in XExtendedCalendar 960*cdf0e10cSrcweir OUString SAL_CALL 961*cdf0e10cSrcweir Calendar_gregorian::getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode ) 962*cdf0e10cSrcweir throw (RuntimeException) 963*cdf0e10cSrcweir { 964*cdf0e10cSrcweir sal_Int16 value = getValue(sal::static_int_cast<sal_Int16>( DisplayCode2FieldIndex(nCalendarDisplayCode) )); 965*cdf0e10cSrcweir OUString aOUStr; 966*cdf0e10cSrcweir 967*cdf0e10cSrcweir if (nCalendarDisplayCode == CalendarDisplayCode::SHORT_QUARTER || 968*cdf0e10cSrcweir nCalendarDisplayCode == CalendarDisplayCode::LONG_QUARTER) { 969*cdf0e10cSrcweir Sequence< OUString> xR = LocaleData().getReservedWord(aLocale); 970*cdf0e10cSrcweir sal_Int16 quarter = value / 3; 971*cdf0e10cSrcweir // Since this base class method may be called by derived calendar 972*cdf0e10cSrcweir // classes where a year consists of more than 12 months we need a check 973*cdf0e10cSrcweir // to not run out of bounds of reserved quarter words. Perhaps a more 974*cdf0e10cSrcweir // clean way (instead of dividing by 3) would be to first get the 975*cdf0e10cSrcweir // number of months, divide by 4 and then use that result to divide the 976*cdf0e10cSrcweir // actual month value. 977*cdf0e10cSrcweir if ( quarter > 3 ) 978*cdf0e10cSrcweir quarter = 3; 979*cdf0e10cSrcweir quarter = sal::static_int_cast<sal_Int16>( quarter + 980*cdf0e10cSrcweir ((nCalendarDisplayCode == CalendarDisplayCode::SHORT_QUARTER) ? 981*cdf0e10cSrcweir reservedWords::QUARTER1_ABBREVIATION : reservedWords::QUARTER1_WORD) ); 982*cdf0e10cSrcweir aOUStr = xR[quarter]; 983*cdf0e10cSrcweir } else { 984*cdf0e10cSrcweir // The "#100211# - checked" comments serve for detection of "use of 985*cdf0e10cSrcweir // sprintf is safe here" conditions. An sprintf encountered without 986*cdf0e10cSrcweir // having that comment triggers alarm ;-) 987*cdf0e10cSrcweir sal_Char aStr[10]; 988*cdf0e10cSrcweir switch( nCalendarDisplayCode ) { 989*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_MONTH: 990*cdf0e10cSrcweir value += 1; // month is zero based 991*cdf0e10cSrcweir // fall thru 992*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_DAY: 993*cdf0e10cSrcweir sprintf(aStr, "%d", value); // #100211# - checked 994*cdf0e10cSrcweir break; 995*cdf0e10cSrcweir case CalendarDisplayCode::LONG_YEAR: 996*cdf0e10cSrcweir if (aCalendar.Name.equalsAscii("gengou")) 997*cdf0e10cSrcweir sprintf(aStr, "%02d", value); // #100211# - checked 998*cdf0e10cSrcweir else 999*cdf0e10cSrcweir sprintf(aStr, "%d", value); // #100211# - checked 1000*cdf0e10cSrcweir break; 1001*cdf0e10cSrcweir case CalendarDisplayCode::LONG_MONTH: 1002*cdf0e10cSrcweir value += 1; // month is zero based 1003*cdf0e10cSrcweir sprintf(aStr, "%02d", value); // #100211# - checked 1004*cdf0e10cSrcweir break; 1005*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_YEAR: 1006*cdf0e10cSrcweir // Take last 2 digits, or only one if value<10, for example, 1007*cdf0e10cSrcweir // in case of the Gengou calendar. 1008*cdf0e10cSrcweir // #i116701# For values in non-Gregorian era years use all 1009*cdf0e10cSrcweir // digits. 1010*cdf0e10cSrcweir if (value < 100 || eraArray) 1011*cdf0e10cSrcweir sprintf(aStr, "%d", value); // #100211# - checked 1012*cdf0e10cSrcweir else 1013*cdf0e10cSrcweir sprintf(aStr, "%02d", value % 100); // #100211# - checked 1014*cdf0e10cSrcweir break; 1015*cdf0e10cSrcweir case CalendarDisplayCode::LONG_DAY: 1016*cdf0e10cSrcweir sprintf(aStr, "%02d", value); // #100211# - checked 1017*cdf0e10cSrcweir break; 1018*cdf0e10cSrcweir 1019*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_DAY_NAME: 1020*cdf0e10cSrcweir return getDisplayName(CalendarDisplayIndex::DAY, value, 0); 1021*cdf0e10cSrcweir case CalendarDisplayCode::LONG_DAY_NAME: 1022*cdf0e10cSrcweir return getDisplayName(CalendarDisplayIndex::DAY, value, 1); 1023*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_MONTH_NAME: 1024*cdf0e10cSrcweir return getDisplayName(CalendarDisplayIndex::MONTH, value, 0); 1025*cdf0e10cSrcweir case CalendarDisplayCode::LONG_MONTH_NAME: 1026*cdf0e10cSrcweir return getDisplayName(CalendarDisplayIndex::MONTH, value, 1); 1027*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_ERA: 1028*cdf0e10cSrcweir return getDisplayName(CalendarDisplayIndex::ERA, value, 0); 1029*cdf0e10cSrcweir case CalendarDisplayCode::LONG_ERA: 1030*cdf0e10cSrcweir return getDisplayName(CalendarDisplayIndex::ERA, value, 1); 1031*cdf0e10cSrcweir 1032*cdf0e10cSrcweir case CalendarDisplayCode::SHORT_YEAR_AND_ERA: 1033*cdf0e10cSrcweir return getDisplayString( CalendarDisplayCode::SHORT_ERA, nNativeNumberMode ) + 1034*cdf0e10cSrcweir getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNativeNumberMode ); 1035*cdf0e10cSrcweir 1036*cdf0e10cSrcweir case CalendarDisplayCode::LONG_YEAR_AND_ERA: 1037*cdf0e10cSrcweir return getDisplayString( CalendarDisplayCode::LONG_ERA, nNativeNumberMode ) + 1038*cdf0e10cSrcweir getDisplayString( CalendarDisplayCode::LONG_YEAR, nNativeNumberMode ); 1039*cdf0e10cSrcweir 1040*cdf0e10cSrcweir default: 1041*cdf0e10cSrcweir throw ERROR; 1042*cdf0e10cSrcweir } 1043*cdf0e10cSrcweir aOUStr = OUString::createFromAscii(aStr); 1044*cdf0e10cSrcweir } 1045*cdf0e10cSrcweir if (nNativeNumberMode > 0) { 1046*cdf0e10cSrcweir // For Japanese calendar, first year calls GAN, see bug 111668 for detail. 1047*cdf0e10cSrcweir if (eraArray == gengou_eraArray && value == 1 1048*cdf0e10cSrcweir && (nCalendarDisplayCode == CalendarDisplayCode::SHORT_YEAR || 1049*cdf0e10cSrcweir nCalendarDisplayCode == CalendarDisplayCode::LONG_YEAR) 1050*cdf0e10cSrcweir && (nNativeNumberMode == NativeNumberMode::NATNUM1 || 1051*cdf0e10cSrcweir nNativeNumberMode == NativeNumberMode::NATNUM2)) { 1052*cdf0e10cSrcweir static sal_Unicode gan = 0x5143; 1053*cdf0e10cSrcweir return OUString(&gan, 1); 1054*cdf0e10cSrcweir } 1055*cdf0e10cSrcweir sal_Int16 nNatNum = NatNumForCalendar(aLocale, nCalendarDisplayCode, nNativeNumberMode, value); 1056*cdf0e10cSrcweir if (nNatNum > 0) 1057*cdf0e10cSrcweir return aNatNum.getNativeNumberString(aOUStr, aLocale, nNatNum); 1058*cdf0e10cSrcweir } 1059*cdf0e10cSrcweir return aOUStr; 1060*cdf0e10cSrcweir } 1061*cdf0e10cSrcweir 1062*cdf0e10cSrcweir // Methods in XExtendedCalendar 1063*cdf0e10cSrcweir OUString SAL_CALL 1064*cdf0e10cSrcweir Calendar_buddhist::getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode ) 1065*cdf0e10cSrcweir throw (RuntimeException) 1066*cdf0e10cSrcweir { 1067*cdf0e10cSrcweir // make year and era in different order for year before and after 0. 1068*cdf0e10cSrcweir if ((nCalendarDisplayCode == CalendarDisplayCode::LONG_YEAR_AND_ERA || 1069*cdf0e10cSrcweir nCalendarDisplayCode == CalendarDisplayCode::SHORT_YEAR_AND_ERA) && 1070*cdf0e10cSrcweir getValue(CalendarFieldIndex::ERA) == 0) { 1071*cdf0e10cSrcweir if (nCalendarDisplayCode == CalendarDisplayCode::LONG_YEAR_AND_ERA) 1072*cdf0e10cSrcweir return getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNativeNumberMode ) + 1073*cdf0e10cSrcweir getDisplayString( CalendarDisplayCode::SHORT_ERA, nNativeNumberMode ); 1074*cdf0e10cSrcweir else 1075*cdf0e10cSrcweir return getDisplayString( CalendarDisplayCode::LONG_YEAR, nNativeNumberMode ) + 1076*cdf0e10cSrcweir getDisplayString( CalendarDisplayCode::LONG_ERA, nNativeNumberMode ); 1077*cdf0e10cSrcweir } 1078*cdf0e10cSrcweir return Calendar_gregorian::getDisplayString(nCalendarDisplayCode, nNativeNumberMode); 1079*cdf0e10cSrcweir } 1080*cdf0e10cSrcweir 1081*cdf0e10cSrcweir OUString SAL_CALL 1082*cdf0e10cSrcweir Calendar_gregorian::getImplementationName(void) throw( RuntimeException ) 1083*cdf0e10cSrcweir { 1084*cdf0e10cSrcweir return OUString::createFromAscii(cCalendar); 1085*cdf0e10cSrcweir } 1086*cdf0e10cSrcweir 1087*cdf0e10cSrcweir sal_Bool SAL_CALL 1088*cdf0e10cSrcweir Calendar_gregorian::supportsService(const rtl::OUString& rServiceName) throw( RuntimeException ) 1089*cdf0e10cSrcweir { 1090*cdf0e10cSrcweir return !rServiceName.compareToAscii(cCalendar); 1091*cdf0e10cSrcweir } 1092*cdf0e10cSrcweir 1093*cdf0e10cSrcweir Sequence< OUString > SAL_CALL 1094*cdf0e10cSrcweir Calendar_gregorian::getSupportedServiceNames(void) throw( RuntimeException ) 1095*cdf0e10cSrcweir { 1096*cdf0e10cSrcweir Sequence< OUString > aRet(1); 1097*cdf0e10cSrcweir aRet[0] = OUString::createFromAscii(cCalendar); 1098*cdf0e10cSrcweir return aRet; 1099*cdf0e10cSrcweir } 1100*cdf0e10cSrcweir 1101