LibreOffice Module i18npool (master)  1
calendar_gregorian.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <algorithm>
21 
22 #include <calendar_gregorian.hxx>
23 #include <localedata.hxx>
24 #include <nativenumbersupplier.hxx>
25 #include <com/sun/star/i18n/CalendarDisplayCode.hpp>
26 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
27 #include <com/sun/star/i18n/NativeNumberMode.hpp>
28 #include <com/sun/star/i18n/reservedWords.hpp>
30 #include <rtl/math.hxx>
31 #include <sal/log.hxx>
32 
33 #include <stdio.h>
34 #include <string.h>
35 
36 #define erDUMP_ICU_CALENDAR 0
37 #define erDUMP_I18N_CALENDAR 0
38 #if erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR
39 // If both are used, DUMP_ICU_CAL_MSG() must be used before DUMP_I18N_CAL_MSG()
40 // to obtain internally set values from ICU, else Calendar::get() calls in
41 // DUMP_I18N_CAL_MSG() recalculate!
42 
43 // These pieces of macro are shamelessly borrowed from icu's olsontz.cpp, the
44 // double parens'ed approach to pass multiple parameters as one macro parameter
45 // is appealing.
46 static void debug_cal_loc(const char *f, int32_t l)
47 {
48  fprintf(stderr, "%s:%d: ", f, l);
49 }
50 # include <stdarg.h>
51 static void debug_cal_msg(const char *pat, ...)
52 {
53  va_list ap;
54  va_start(ap, pat);
55  vfprintf(stderr, pat, ap);
56  va_end(ap);
57 }
58 
59 #if erDUMP_ICU_CALENDAR
60 // Make icu with
61 // DEFS = -DU_DEBUG_CALSVC -DUCAL_DEBUG_DUMP
62 // in workdir/UnpackedTarball/icu/source/icudefs.mk
63 // May need some patches to fix unmaintained things there.
64 extern void ucal_dump( const icu::Calendar & );
65 static void debug_icu_cal_dump( const ::icu::Calendar & r )
66 {
67  ucal_dump(r);
68  fflush(stderr);
69  // set a breakpoint here to pause display between dumps
70 }
71 // must use double parens, i.e.: DUMP_ICU_CAL_MSG(("four is: %d",4));
72 #define DUMP_ICU_CAL_MSG(x) {debug_cal_loc(__FILE__,__LINE__);debug_cal_msg x;debug_icu_cal_dump(*body);}
73 #else // erDUMP_ICU_CALENDAR
74 #define DUMP_ICU_CAL_MSG(x)
75 #endif // erDUMP_ICU_CALENDAR
76 
77 #if erDUMP_I18N_CALENDAR
78 static void debug_cal_millis_to_time( long nMillis, long & h, long & m, long & s, long & f )
79 {
80  int sign = (nMillis < 0 ? -1 : 1);
81  nMillis = ::std::abs(nMillis);
82  h = sign * nMillis / (60 * 60 * 1000);
83  nMillis -= sign * h * (60 * 60 * 1000);
84  m = nMillis / (60 * 1000);
85  nMillis -= m * (60 * 1000);
86  s = nMillis / (1000);
87  nMillis -= s * (1000);
88  f = nMillis;
89 }
90 static void debug_i18n_cal_dump( const ::icu::Calendar & r )
91 {
92  UErrorCode status;
93  long nMillis, h, m, s, f;
94  fprintf( stderr, " %04ld", (long)r.get( UCAL_YEAR, status = U_ZERO_ERROR));
95  fprintf( stderr, "-%02ld", (long)r.get( UCAL_MONTH, status = U_ZERO_ERROR)+1);
96  fprintf( stderr, "-%02ld", (long)r.get( UCAL_DATE, status = U_ZERO_ERROR));
97  fprintf( stderr, " %02ld", (long)r.get( UCAL_HOUR_OF_DAY, status = U_ZERO_ERROR));
98  fprintf( stderr, ":%02ld", (long)r.get( UCAL_MINUTE, status = U_ZERO_ERROR));
99  fprintf( stderr, ":%02ld", (long)r.get( UCAL_SECOND, status = U_ZERO_ERROR));
100  fprintf( stderr, " zone: %ld", (long)(nMillis = r.get( UCAL_ZONE_OFFSET, status = U_ZERO_ERROR)));
101  fprintf( stderr, " (%f min)", (double)nMillis / 60000);
102  debug_cal_millis_to_time( nMillis, h, m, s, f);
103  fprintf( stderr, " (%ld:%02ld:%02ld.%ld)", h, m, s, f);
104  fprintf( stderr, " DST: %ld", (long)(nMillis = r.get( UCAL_DST_OFFSET, status = U_ZERO_ERROR)));
105  fprintf( stderr, " (%f min)", (double)nMillis / 60000);
106  debug_cal_millis_to_time( nMillis, h, m, s, f);
107  fprintf( stderr, " (%ld:%02ld:%02ld.%ld)", h, m, s, f);
108  fprintf( stderr, "\n");
109  fflush(stderr);
110 }
111 // must use double parens, i.e.: DUMP_I18N_CAL_MSG(("four is: %d",4));
112 #define DUMP_I18N_CAL_MSG(x) {debug_cal_loc(__FILE__,__LINE__);debug_cal_msg x;debug_i18n_cal_dump(*body);}
113 #else // erDUMP_I18N_CALENDAR
114 #define DUMP_I18N_CAL_MSG(x)
115 #endif // erDUMP_I18N_CALENDAR
116 
117 #else // erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR
118 #define DUMP_ICU_CAL_MSG(x)
119 #define DUMP_I18N_CAL_MSG(x)
120 #endif // erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR
121 
122 
123 using namespace ::com::sun::star::uno;
124 using namespace ::com::sun::star::i18n;
125 using namespace ::com::sun::star::lang;
126 
127 
128 namespace i18npool {
129 
131  : mxNatNum(new NativeNumberSupplierService)
132 {
133  init(nullptr);
134 }
136  : mxNatNum(new NativeNumberSupplierService)
137 {
138  init(_earArray);
139 }
140 void
141 Calendar_gregorian::init(const Era *_eraArray)
142 {
143  cCalendar = "com.sun.star.i18n.Calendar_gregorian";
144 
145  fieldSet = 0;
146 
147  // #i102356# With icu::Calendar::createInstance(UErrorCode) in a Thai
148  // th_TH system locale we accidentally used a Buddhist calendar. Though
149  // the ICU documentation says that should be the case only for
150  // th_TH_TRADITIONAL (and ja_JP_TRADITIONAL Gengou), a plain th_TH
151  // already triggers that behavior, ja_JP does not. Strange enough,
152  // passing a th_TH locale to the calendar creation doesn't trigger
153  // this.
154  // See also http://userguide.icu-project.org/datetime/calendar
155 
156  // Whatever ICU offers as the default calendar for a locale, ensure we
157  // have a Gregorian calendar as requested.
158 
159  /* XXX: with the current implementation the aLocale member variable is
160  * not set prior to loading a calendar from locale data. This
161  * creates an empty (root) locale for ICU, but at least the correct
162  * calendar is used. The language part must not be NULL (respectively
163  * not all, language and country and variant), otherwise the current
164  * default locale would be used again and the calendar keyword ignored.
165  * */
166  icu::Locale aIcuLocale( "", nullptr, nullptr, "calendar=gregorian");
167 
168  /* XXX: not specifying a timezone when creating a calendar assigns the
169  * system's timezone with all DST quirks, invalid times when switching
170  * to/from DST and so on. The XCalendar* interfaces are defined to support
171  * local time and UTC time so we can not override that here.
172  */
173  UErrorCode status = U_ZERO_ERROR;
174  body.reset( icu::Calendar::createInstance( aIcuLocale, status) );
175  if (!body || !U_SUCCESS(status)) throw RuntimeException();
176  eraArray=_eraArray;
177 }
178 
180 {
181 }
182 
184 {
185  cCalendar = "com.sun.star.i18n.Calendar_hanja";
186 }
187 
188 OUString SAL_CALL
189 Calendar_hanja::getDisplayName( sal_Int16 displayIndex, sal_Int16 idx, sal_Int16 nameType )
190 {
191  if ( displayIndex == CalendarDisplayIndex::AM_PM ) {
192  // Am/Pm string for Korean Hanja calendar will refer to Japanese locale
193  css::lang::Locale jaLocale("ja", OUString(), OUString());
194  if (idx == 0) return LocaleDataImpl::get()->getLocaleItem(jaLocale).timeAM;
195  else if (idx == 1) return LocaleDataImpl::get()->getLocaleItem(jaLocale).timePM;
196  else throw RuntimeException();
197  }
198  else
199  return Calendar_gregorian::getDisplayName( displayIndex, idx, nameType );
200 }
201 
202 
204 {
205  cCalendar = "com.sun.star.i18n.Calendar_Calendar_hanja_yoil";
206 }
207 
208 OUString SAL_CALL
209 Calendar_hanja_yoil::getDisplayName( sal_Int16 displayIndex, sal_Int16 idx, sal_Int16 nameType )
210 {
211  if ( displayIndex == CalendarDisplayIndex::AM_PM ) {
212  // Am/Pm string for Korean Hanja calendar will refer to Japanese locale
213  css::lang::Locale jaLocale("ja", OUString(), OUString());
214  if (idx == 0) return LocaleDataImpl::get()->getLocaleItem(jaLocale).timeAM;
215  else if (idx == 1) return LocaleDataImpl::get()->getLocaleItem(jaLocale).timePM;
216  else throw RuntimeException();
217  }
218  else
219  return Calendar_gregorian::getDisplayName( displayIndex, idx, nameType );
220 }
221 
222 
223 const Era gengou_eraArray[] = {
224  {1868, 1, 1, 0}, // Meiji
225  {1912, 7, 30, 0}, // Taisho
226  {1926, 12, 25, 0}, // Showa
227  {1989, 1, 8, 0}, // Heisei
228  {2019, 5, 1, 0}, // Reiwa
229  {0, 0, 0, 0}
230 };
232 {
233  cCalendar = "com.sun.star.i18n.Calendar_gengou";
234 }
235 
236 const Era ROC_eraArray[] = {
237  {1912, 1, 1, kDisplayEraForcedLongYear}, // #i116701#
238  {0, 0, 0, 0}
239 };
241 {
242  cCalendar = "com.sun.star.i18n.Calendar_ROC";
243 }
244 
249 const Era dangi_eraArray[] = {
250  {-2332, 1, 1, 0},
251  {0, 0, 0, 0}
252 };
254 {
255  cCalendar = "com.sun.star.i18n.Calendar_dangi";
256 }
257 
259  {-542, 1, 1, 0},
260  {0, 0, 0, 0}
261 };
263 {
264  cCalendar = "com.sun.star.i18n.Calendar_buddhist";
265 }
266 
267 void SAL_CALL
268 Calendar_gregorian::loadCalendar( const OUString& uniqueID, const css::lang::Locale& rLocale )
269 {
270  // init. fieldValue[]
271  getValue();
272 
273  aLocale = rLocale;
274  const Sequence< Calendar2 > xC = LocaleDataImpl::get()->getAllCalendars2(rLocale);
275  for (const auto& rCal : xC)
276  {
277  if (uniqueID == rCal.Name)
278  {
279  aCalendar = rCal;
280  // setup minimalDaysInFirstWeek
282  aCalendar.MinimumNumberOfDaysForFirstWeek);
283  // setup first day of week
284  for (sal_Int16 day = sal::static_int_cast<sal_Int16>(
285  aCalendar.Days.getLength()-1); day>=0; day--)
286  {
287  if (aCalendar.StartOfWeek == aCalendar.Days[day].ID)
288  {
290  return;
291  }
292  }
293  }
294  }
295  // Calendar is not for the locale
296  throw RuntimeException();
297 }
298 
299 
300 css::i18n::Calendar2 SAL_CALL
302 {
303  return aCalendar;
304 }
305 
306 css::i18n::Calendar SAL_CALL
308 {
310 }
311 
312 OUString SAL_CALL
314 {
315  return aCalendar.Name;
316 }
317 
318 void SAL_CALL
319 Calendar_gregorian::setDateTime( double fTimeInDays )
320 {
321  // ICU handles dates in milliseconds as double values and uses floor()
322  // to obtain integer values, which may yield a date decremented by one
323  // for odd (historical) timezone values where the computed value due to
324  // rounding errors has a fractional part in milliseconds. Ensure we
325  // pass a value without fraction here. If not, that may lead to
326  // fdo#44286 or fdo#52619 and the like, e.g. when passing
327  // -2136315212000.000244 instead of -2136315212000.000000
328  double fM = fTimeInDays * U_MILLIS_PER_DAY;
329  double fR = rtl::math::round( fM );
330  SAL_INFO_IF( fM != fR, "i18npool",
331  "Calendar_gregorian::setDateTime: " << std::fixed << fM << " rounded to " << fR);
332  UErrorCode status = U_ZERO_ERROR;
333  body->setTime( fR, status);
334  if ( !U_SUCCESS(status) ) throw RuntimeException();
335  getValue();
336 }
337 
338 double SAL_CALL
340 {
341  if (fieldSet) {
342  setValue();
343  getValue();
344  }
345  UErrorCode status = U_ZERO_ERROR;
346  double fR = body->getTime(status);
347  if ( !U_SUCCESS(status) ) throw RuntimeException();
348  return fR / U_MILLIS_PER_DAY;
349 }
350 
351 void SAL_CALL
353 {
354  // See setDateTime() for why the rounding.
355  double fM = fTimeInDays * U_MILLIS_PER_DAY;
356  double fR = rtl::math::round( fM );
357  SAL_INFO_IF( fM != fR, "i18npool",
358  "Calendar_gregorian::setLocalDateTime: " << std::fixed << fM << " rounded to " << fR);
359  int32_t nZoneOffset, nDSTOffset;
360  UErrorCode status = U_ZERO_ERROR;
361  body->getTimeZone().getOffset( fR, true, nZoneOffset, nDSTOffset, status );
362 
363  if ( !U_SUCCESS(status) ) throw RuntimeException();
364  status = U_ZERO_ERROR;
365  body->setTime( fR - (nZoneOffset + nDSTOffset), status );
366  if ( !U_SUCCESS(status) ) throw RuntimeException();
367  getValue();
368 }
369 
370 double SAL_CALL
372 {
373  if (fieldSet) {
374  setValue();
375  getValue();
376  }
377  UErrorCode status = U_ZERO_ERROR;
378  double fTime = body->getTime( status );
379  if ( !U_SUCCESS(status) ) throw RuntimeException();
380  status = U_ZERO_ERROR;
381  int32_t nZoneOffset = body->get( UCAL_ZONE_OFFSET, status );
382  if ( !U_SUCCESS(status) ) throw RuntimeException();
383  status = U_ZERO_ERROR;
384  int32_t nDSTOffset = body->get( UCAL_DST_OFFSET, status );
385  if ( !U_SUCCESS(status) ) throw RuntimeException();
386  return (fTime + (nZoneOffset + nDSTOffset)) / U_MILLIS_PER_DAY;
387 }
388 
389 bool Calendar_gregorian::setTimeZone( const OUString& rTimeZone )
390 {
391  if (fieldSet)
392  {
393  setValue();
394  getValue();
395  }
396  const icu::UnicodeString aID( reinterpret_cast<const UChar*>(rTimeZone.getStr()), rTimeZone.getLength());
397  const std::unique_ptr<const icu::TimeZone> pTZ( icu::TimeZone::createTimeZone(aID));
398  if (!pTZ)
399  return false;
400 
401  body->setTimeZone(*pTZ);
402  return true;
403 }
404 
405 // map field value from gregorian calendar to other calendar, it can be overwritten by derived class.
406 // By using eraArray, it can take care Japanese and Taiwan ROC calendar.
408 {
409  if (!eraArray)
410  return;
411 
412  sal_Int16 e, y, m, d;
413 
414  e = fieldValue[CalendarFieldIndex::ERA];
415  y = fieldValue[CalendarFieldIndex::YEAR];
416  m = fieldValue[CalendarFieldIndex::MONTH] + 1;
417  d = fieldValue[CalendarFieldIndex::DAY_OF_MONTH];
418 
419  // since the year is reversed for first era, it is reversed again here for Era compare.
420  if (e == 0)
421  y = 1 - y;
422 
423  for (e = 0; eraArray[e].year; e++)
424  if ((y != eraArray[e].year) ? y < eraArray[e].year :
425  (m != eraArray[e].month) ? m < eraArray[e].month : d < eraArray[e].day)
426  break;
427 
428  fieldValue[CalendarFieldIndex::ERA] = e;
429  fieldValue[CalendarFieldIndex::YEAR] =
430  sal::static_int_cast<sal_Int16>( (e == 0) ? (eraArray[0].year - y) : (y - eraArray[e-1].year + 1) );
431 }
432 
433 #define FIELDS ((1 << CalendarFieldIndex::ERA) | (1 << CalendarFieldIndex::YEAR))
434 // map field value from other calendar to gregorian calendar, it can be overwritten by derived class.
435 // By using eraArray, it can take care Japanese and Taiwan ROC calendar.
437 {
438  if (eraArray && (fieldSet & FIELDS)) {
439  sal_Int16 y, e = fieldValue[CalendarFieldIndex::ERA];
440  if (e == 0)
441  y = sal::static_int_cast<sal_Int16>( eraArray[0].year - fieldValue[CalendarFieldIndex::YEAR] );
442  else
443  y = sal::static_int_cast<sal_Int16>( eraArray[e-1].year + fieldValue[CalendarFieldIndex::YEAR] - 1 );
444 
445  fieldSetValue[CalendarFieldIndex::ERA] = y <= 0 ? 0 : 1;
446  fieldSetValue[CalendarFieldIndex::YEAR] = (y <= 0 ? 1 - y : y);
447  fieldSet |= FIELDS;
448  }
449 }
450 
452 static UCalendarDateFields fieldNameConverter(sal_Int16 fieldIndex)
453 {
454  UCalendarDateFields f;
455 
456  switch (fieldIndex) {
457  case CalendarFieldIndex::AM_PM: f = UCAL_AM_PM; break;
458  case CalendarFieldIndex::DAY_OF_MONTH: f = UCAL_DATE; break;
459  case CalendarFieldIndex::DAY_OF_WEEK: f = UCAL_DAY_OF_WEEK; break;
460  case CalendarFieldIndex::DAY_OF_YEAR: f = UCAL_DAY_OF_YEAR; break;
461  case CalendarFieldIndex::DST_OFFSET: f = UCAL_DST_OFFSET; break;
462  case CalendarFieldIndex::ZONE_OFFSET: f = UCAL_ZONE_OFFSET; break;
463  case CalendarFieldIndex::HOUR: f = UCAL_HOUR_OF_DAY; break;
464  case CalendarFieldIndex::MINUTE: f = UCAL_MINUTE; break;
465  case CalendarFieldIndex::SECOND: f = UCAL_SECOND; break;
466  case CalendarFieldIndex::MILLISECOND: f = UCAL_MILLISECOND; break;
467  case CalendarFieldIndex::WEEK_OF_MONTH: f = UCAL_WEEK_OF_MONTH; break;
468  case CalendarFieldIndex::WEEK_OF_YEAR: f = UCAL_WEEK_OF_YEAR; break;
469  case CalendarFieldIndex::YEAR: f = UCAL_YEAR; break;
470  case CalendarFieldIndex::MONTH: f = UCAL_MONTH; break;
471  case CalendarFieldIndex::ERA: f = UCAL_ERA; break;
472  default: throw RuntimeException();
473  }
474  return f;
475 }
476 
477 void SAL_CALL
478 Calendar_gregorian::setValue( sal_Int16 fieldIndex, sal_Int16 value )
479 {
480  if (fieldIndex < 0 || FIELD_INDEX_COUNT <= fieldIndex)
481  throw RuntimeException();
482  fieldSet |= (1 << fieldIndex);
483  fieldValue[fieldIndex] = value;
484 }
485 
486 bool Calendar_gregorian::getCombinedOffset( sal_Int32 & o_nOffset,
487  sal_Int16 nParentFieldIndex, sal_Int16 nChildFieldIndex ) const
488 {
489  o_nOffset = 0;
490  bool bFieldsSet = false;
491  if (fieldSet & (1 << nParentFieldIndex))
492  {
493  bFieldsSet = true;
494  o_nOffset = static_cast<sal_Int32>( fieldValue[nParentFieldIndex]) * 60000;
495  }
496  if (fieldSet & (1 << nChildFieldIndex))
497  {
498  bFieldsSet = true;
499  if (o_nOffset < 0)
500  o_nOffset -= static_cast<sal_uInt16>( fieldValue[nChildFieldIndex]);
501  else
502  o_nOffset += static_cast<sal_uInt16>( fieldValue[nChildFieldIndex]);
503  }
504  return bFieldsSet;
505 }
506 
507 bool Calendar_gregorian::getZoneOffset( sal_Int32 & o_nOffset ) const
508 {
509  return getCombinedOffset( o_nOffset, CalendarFieldIndex::ZONE_OFFSET,
510  CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS);
511 }
512 
513 bool Calendar_gregorian::getDSTOffset( sal_Int32 & o_nOffset ) const
514 {
515  return getCombinedOffset( o_nOffset, CalendarFieldIndex::DST_OFFSET,
516  CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS);
517 }
518 
520 {
521  for (sal_Int16 fieldIndex = 0; fieldIndex < FIELD_INDEX_COUNT; fieldIndex++)
522  {
523  if (fieldSet & (1 << fieldIndex))
524  {
525  switch (fieldIndex)
526  {
527  default:
528  body->set(fieldNameConverter(fieldIndex), fieldSetValue[fieldIndex]);
529  break;
530  case CalendarFieldIndex::ZONE_OFFSET:
531  case CalendarFieldIndex::DST_OFFSET:
532  case CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS:
533  case CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS:
534  break; // nothing, extra handling
535  }
536  }
537  }
538  sal_Int32 nZoneOffset, nDSTOffset;
539  if (getZoneOffset( nZoneOffset))
540  body->set( fieldNameConverter( CalendarFieldIndex::ZONE_OFFSET), nZoneOffset);
541  if (getDSTOffset( nDSTOffset))
542  body->set( fieldNameConverter( CalendarFieldIndex::DST_OFFSET), nDSTOffset);
543 }
544 
546 {
547  // Copy fields before calling submitFields() directly or indirectly below.
548  memcpy(fieldSetValue, fieldValue, sizeof(fieldSetValue));
549  // Possibly setup ERA and YEAR in fieldSetValue.
550  mapToGregorian();
551 
552  DUMP_ICU_CAL_MSG(("%s\n","setValue() before submission"));
553  DUMP_I18N_CAL_MSG(("%s\n","setValue() before submission"));
554 
555  submitFields();
556 
557  DUMP_ICU_CAL_MSG(("%s\n","setValue() after submission"));
558  DUMP_I18N_CAL_MSG(("%s\n","setValue() after submission"));
559 
560 #if erDUMP_ICU_CALENDAR || erDUMP_I18N_CALENDAR
561  {
562  // force icu::Calendar to recalculate
563  UErrorCode status;
564  sal_Int32 nTmp = body->get( UCAL_DATE, status = U_ZERO_ERROR);
565  DUMP_ICU_CAL_MSG(("%s: %d\n","setValue() result day",nTmp));
566  DUMP_I18N_CAL_MSG(("%s: %d\n","setValue() result day",nTmp));
567  }
568 #endif
569 }
570 
572 {
573  DUMP_ICU_CAL_MSG(("%s\n","getValue()"));
574  DUMP_I18N_CAL_MSG(("%s\n","getValue()"));
575  for (sal_Int16 fieldIndex = 0; fieldIndex < FIELD_INDEX_COUNT; fieldIndex++)
576  {
577  if (fieldIndex == CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS ||
578  fieldIndex == CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS)
579  continue; // not ICU fields
580 
581  UErrorCode status = U_ZERO_ERROR;
582  sal_Int32 value = body->get( fieldNameConverter(
583  fieldIndex), status);
584  if ( !U_SUCCESS(status) ) throw RuntimeException();
585 
586  // Convert millisecond to minute for ZONE and DST and set remainder in
587  // second field.
588  if (fieldIndex == CalendarFieldIndex::ZONE_OFFSET)
589  {
590  sal_Int32 nMinutes = value / 60000;
591  sal_Int16 nMillis = static_cast<sal_Int16>( static_cast<sal_uInt16>(
592  abs( value - nMinutes * 60000)));
593  fieldValue[CalendarFieldIndex::ZONE_OFFSET] = static_cast<sal_Int16>( nMinutes);
594  fieldValue[CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS] = nMillis;
595  }
596  else if (fieldIndex == CalendarFieldIndex::DST_OFFSET)
597  {
598  sal_Int32 nMinutes = value / 60000;
599  sal_Int16 nMillis = static_cast<sal_Int16>( static_cast<sal_uInt16>(
600  abs( value - nMinutes * 60000)));
601  fieldValue[CalendarFieldIndex::DST_OFFSET] = static_cast<sal_Int16>( nMinutes);
602  fieldValue[CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS] = nMillis;
603  }
604  else
605  fieldValue[fieldIndex] = static_cast<sal_Int16>(value);
606 
607  // offset 1 since the value for week start day SunDay is different between Calendar and Weekdays.
608  if ( fieldIndex == CalendarFieldIndex::DAY_OF_WEEK )
609  fieldValue[fieldIndex]--; // UCAL_SUNDAY:/* == 1 */ ==> Weekdays::SUNDAY /* ==0 */
610  }
612  fieldSet = 0;
613 }
614 
615 sal_Int16 SAL_CALL
616 Calendar_gregorian::getValue( sal_Int16 fieldIndex )
617 {
618  if (fieldIndex < 0 || FIELD_INDEX_COUNT <= fieldIndex)
619  throw RuntimeException();
620 
621  if (fieldSet) {
622  setValue();
623  getValue();
624  }
625 
626  return fieldValue[fieldIndex];
627 }
628 
629 void SAL_CALL
630 Calendar_gregorian::addValue( sal_Int16 fieldIndex, sal_Int32 value )
631 {
632  // since ZONE and DST could not be add, we don't need to convert value here
633  UErrorCode status = U_ZERO_ERROR;
634  body->add(fieldNameConverter(fieldIndex), value, status);
635  if ( !U_SUCCESS(status) ) throw RuntimeException();
636  getValue();
637 }
638 
639 sal_Bool SAL_CALL
641 {
642  if (fieldSet) {
643  sal_Int32 tmp = fieldSet;
644  setValue();
645  memcpy(fieldSetValue, fieldValue, sizeof(fieldSetValue));
646  getValue();
647  for ( sal_Int16 fieldIndex = 0; fieldIndex < FIELD_INDEX_COUNT; fieldIndex++ ) {
648  // compare only with fields that are set and reset fieldSet[]
649  if (tmp & (1 << fieldIndex)) {
650  if (fieldSetValue[fieldIndex] != fieldValue[fieldIndex])
651  return false;
652  }
653  }
654  }
655  return true;
656 }
657 
658 // NativeNumberMode has different meaning between Number and Calendar for Asian locales.
659 // Here is the mapping table
660 // calendar(q/y/m/d) zh_CN zh_TW ja ko
661 // NatNum1 NatNum1/1/7/7 NatNum1/1/7/7 NatNum1/1/4/4 NatNum1/1/7/7
662 // NatNum2 NatNum2/2/8/8 NatNum2/2/8/8 NatNum2/2/5/5 NatNum2/2/8/8
663 // NatNum3 NatNum3/3/3/3 NatNum3/3/3/3 NatNum3/3/3/3 NatNum3/3/3/3
664 // NatNum4 NatNum9/9/11/11
665 
666 static sal_Int16 NatNumForCalendar(const css::lang::Locale& aLocale,
667  sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode, sal_Int16 value )
668 {
669  bool isShort = ((nCalendarDisplayCode == CalendarDisplayCode::SHORT_YEAR ||
670  nCalendarDisplayCode == CalendarDisplayCode::LONG_YEAR) && value >= 100) ||
671  nCalendarDisplayCode == CalendarDisplayCode::SHORT_QUARTER ||
672  nCalendarDisplayCode == CalendarDisplayCode::LONG_QUARTER;
673  bool isChinese = aLocale.Language == "zh";
674  bool isJapanese = aLocale.Language == "ja";
675  bool isKorean = aLocale.Language == "ko";
676 
677  if (isChinese || isJapanese || isKorean) {
678  switch (nNativeNumberMode) {
679  case NativeNumberMode::NATNUM1:
680  if (!isShort)
681  nNativeNumberMode = isJapanese ? NativeNumberMode::NATNUM4 : NativeNumberMode::NATNUM7;
682  break;
683  case NativeNumberMode::NATNUM2:
684  if (!isShort)
685  nNativeNumberMode = isJapanese ? NativeNumberMode::NATNUM5 : NativeNumberMode::NATNUM8;
686  break;
687  case NativeNumberMode::NATNUM3:
688  break;
689  case NativeNumberMode::NATNUM4:
690  if (isKorean)
691  return isShort ? NativeNumberMode::NATNUM9 : NativeNumberMode::NATNUM11;
692  [[fallthrough]];
693  default: return 0;
694  }
695  }
696  return nNativeNumberMode;
697 }
698 
699 static sal_Int32 DisplayCode2FieldIndex(sal_Int32 nCalendarDisplayCode)
700 {
701  switch( nCalendarDisplayCode ) {
702  case CalendarDisplayCode::SHORT_DAY:
703  case CalendarDisplayCode::LONG_DAY:
704  return CalendarFieldIndex::DAY_OF_MONTH;
705  case CalendarDisplayCode::SHORT_DAY_NAME:
706  case CalendarDisplayCode::LONG_DAY_NAME:
707  case CalendarDisplayCode::NARROW_DAY_NAME:
708  return CalendarFieldIndex::DAY_OF_WEEK;
709  case CalendarDisplayCode::SHORT_QUARTER:
710  case CalendarDisplayCode::LONG_QUARTER:
711  case CalendarDisplayCode::SHORT_MONTH:
712  case CalendarDisplayCode::LONG_MONTH:
713  case CalendarDisplayCode::SHORT_MONTH_NAME:
714  case CalendarDisplayCode::LONG_MONTH_NAME:
715  case CalendarDisplayCode::NARROW_MONTH_NAME:
716  case CalendarDisplayCode::SHORT_GENITIVE_MONTH_NAME:
717  case CalendarDisplayCode::LONG_GENITIVE_MONTH_NAME:
718  case CalendarDisplayCode::NARROW_GENITIVE_MONTH_NAME:
719  case CalendarDisplayCode::SHORT_PARTITIVE_MONTH_NAME:
720  case CalendarDisplayCode::LONG_PARTITIVE_MONTH_NAME:
721  case CalendarDisplayCode::NARROW_PARTITIVE_MONTH_NAME:
722  return CalendarFieldIndex::MONTH;
723  case CalendarDisplayCode::SHORT_YEAR:
724  case CalendarDisplayCode::LONG_YEAR:
725  return CalendarFieldIndex::YEAR;
726  case CalendarDisplayCode::SHORT_ERA:
727  case CalendarDisplayCode::LONG_ERA:
728  return CalendarFieldIndex::ERA;
729  case CalendarDisplayCode::SHORT_YEAR_AND_ERA:
730  case CalendarDisplayCode::LONG_YEAR_AND_ERA:
731  return CalendarFieldIndex::YEAR;
732  default:
733  return 0;
734  }
735 }
736 
737 sal_Int16 SAL_CALL
739 {
740  // UCAL_SUNDAY == 1, Weekdays::SUNDAY == 0 => offset -1
741  // Check for underflow just in case we're called "out of sync".
742  return ::std::max( sal::static_int_cast<sal_Int16>(0),
743  sal::static_int_cast<sal_Int16>( static_cast<sal_Int16>(
744  body->getFirstDayOfWeek()) - 1));
745 }
746 
747 void SAL_CALL
749 {
750  // Weekdays::SUNDAY == 0, UCAL_SUNDAY == 1 => offset +1
751  body->setFirstDayOfWeek( static_cast<UCalendarDaysOfWeek>( day + 1));
752 }
753 
754 void SAL_CALL
756 {
757  aCalendar.MinimumNumberOfDaysForFirstWeek = days;
758  body->setMinimalDaysInFirstWeek( static_cast<uint8_t>( days));
759 }
760 
761 sal_Int16 SAL_CALL
763 {
764  return aCalendar.MinimumNumberOfDaysForFirstWeek;
765 }
766 
767 sal_Int16 SAL_CALL
769 {
770  return static_cast<sal_Int16>(aCalendar.Months.getLength());
771 }
772 
773 
774 sal_Int16 SAL_CALL
776 {
777  return static_cast<sal_Int16>(aCalendar.Days.getLength());
778 }
779 
780 
781 Sequence< CalendarItem > SAL_CALL
783 {
785 }
786 
787 
788 Sequence< CalendarItem > SAL_CALL
790 {
792 }
793 
794 
795 Sequence< CalendarItem2 > SAL_CALL
797 {
798  return aCalendar.Days;
799 }
800 
801 
802 Sequence< CalendarItem2 > SAL_CALL
804 {
805  return aCalendar.Months;
806 }
807 
808 
809 Sequence< CalendarItem2 > SAL_CALL
811 {
812  return aCalendar.GenitiveMonths;
813 }
814 
815 
816 Sequence< CalendarItem2 > SAL_CALL
818 {
819  return aCalendar.PartitiveMonths;
820 }
821 
822 
823 OUString SAL_CALL
824 Calendar_gregorian::getDisplayName( sal_Int16 displayIndex, sal_Int16 idx, sal_Int16 nameType )
825 {
826  OUString aStr;
827 
828  switch( displayIndex ) {
829  case CalendarDisplayIndex::AM_PM:/* ==0 */
830  if (idx == 0) aStr = LocaleDataImpl::get()->getLocaleItem(aLocale).timeAM;
831  else if (idx == 1) aStr = LocaleDataImpl::get()->getLocaleItem(aLocale).timePM;
832  else throw RuntimeException();
833  break;
834  case CalendarDisplayIndex::DAY:
835  if( idx >= aCalendar.Days.getLength() ) throw RuntimeException();
836  if (nameType == 0) aStr = aCalendar.Days[idx].AbbrevName;
837  else if (nameType == 1) aStr = aCalendar.Days[idx].FullName;
838  else if (nameType == 2) aStr = aCalendar.Days[idx].NarrowName;
839  else throw RuntimeException();
840  break;
841  case CalendarDisplayIndex::MONTH:
842  if( idx >= aCalendar.Months.getLength() ) throw RuntimeException();
843  if (nameType == 0) aStr = aCalendar.Months[idx].AbbrevName;
844  else if (nameType == 1) aStr = aCalendar.Months[idx].FullName;
845  else if (nameType == 2) aStr = aCalendar.Months[idx].NarrowName;
846  else throw RuntimeException();
847  break;
848  case CalendarDisplayIndex::GENITIVE_MONTH:
849  if( idx >= aCalendar.GenitiveMonths.getLength() ) throw RuntimeException();
850  if (nameType == 0) aStr = aCalendar.GenitiveMonths[idx].AbbrevName;
851  else if (nameType == 1) aStr = aCalendar.GenitiveMonths[idx].FullName;
852  else if (nameType == 2) aStr = aCalendar.GenitiveMonths[idx].NarrowName;
853  else throw RuntimeException();
854  break;
855  case CalendarDisplayIndex::PARTITIVE_MONTH:
856  if( idx >= aCalendar.PartitiveMonths.getLength() ) throw RuntimeException();
857  if (nameType == 0) aStr = aCalendar.PartitiveMonths[idx].AbbrevName;
858  else if (nameType == 1) aStr = aCalendar.PartitiveMonths[idx].FullName;
859  else if (nameType == 2) aStr = aCalendar.PartitiveMonths[idx].NarrowName;
860  else throw RuntimeException();
861  break;
862  case CalendarDisplayIndex::ERA:
863  if( idx >= aCalendar.Eras.getLength() ) throw RuntimeException();
864  if (nameType == 0) aStr = aCalendar.Eras[idx].AbbrevName;
865  else if (nameType == 1) aStr = aCalendar.Eras[idx].FullName;
866  else throw RuntimeException();
867  break;
868  case CalendarDisplayIndex::YEAR:
869  break;
870  default:
871  throw RuntimeException();
872  }
873  return aStr;
874 }
875 
876 // Methods in XExtendedCalendar
877 OUString SAL_CALL
878 Calendar_gregorian::getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode )
879 {
880  return getDisplayStringImpl( nCalendarDisplayCode, nNativeNumberMode, false);
881 }
882 
883 OUString
884 Calendar_gregorian::getDisplayStringImpl( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode, bool bEraMode )
885 {
886  sal_Int16 value = getValue(sal::static_int_cast<sal_Int16>( DisplayCode2FieldIndex(nCalendarDisplayCode) ));
887  OUString aOUStr;
888 
889  if (nCalendarDisplayCode == CalendarDisplayCode::SHORT_QUARTER ||
890  nCalendarDisplayCode == CalendarDisplayCode::LONG_QUARTER) {
891  Sequence< OUString> xR = LocaleDataImpl::get()->getReservedWord(aLocale);
892  sal_Int16 quarter = value / 3;
893  // Since this base class method may be called by derived calendar
894  // classes where a year consists of more than 12 months we need a check
895  // to not run out of bounds of reserved quarter words. Perhaps a more
896  // clean way (instead of dividing by 3) would be to first get the
897  // number of months, divide by 4 and then use that result to divide the
898  // actual month value.
899  if ( quarter > 3 )
900  quarter = 3;
901  quarter = sal::static_int_cast<sal_Int16>( quarter +
902  ((nCalendarDisplayCode == CalendarDisplayCode::SHORT_QUARTER) ?
903  reservedWords::QUARTER1_ABBREVIATION : reservedWords::QUARTER1_WORD) );
904  aOUStr = xR[quarter];
905  } else {
906  // The "#100211# - checked" comments serve for detection of "use of
907  // sprintf is safe here" conditions. An sprintf encountered without
908  // having that comment triggers alarm ;-)
909  char aStr[10];
910  switch( nCalendarDisplayCode ) {
911  case CalendarDisplayCode::SHORT_MONTH:
912  value += 1; // month is zero based
913  [[fallthrough]];
914  case CalendarDisplayCode::SHORT_DAY:
915  sprintf(aStr, "%d", value); // #100211# - checked
916  break;
917  case CalendarDisplayCode::LONG_YEAR:
918  if ( aCalendar.Name == "gengou" )
919  sprintf(aStr, "%02d", value); // #100211# - checked
920  else
921  sprintf(aStr, "%d", value); // #100211# - checked
922  break;
923  case CalendarDisplayCode::LONG_MONTH:
924  value += 1; // month is zero based
925  sprintf(aStr, "%02d", value); // #100211# - checked
926  break;
927  case CalendarDisplayCode::SHORT_YEAR:
928  // Take last 2 digits, or only one if value<10, for example,
929  // in case of the Gengou calendar. For combined era+year always
930  // the full year is displayed, without leading 0.
931  // Workaround for non-combined calls in certain calendars is
932  // the kDisplayEraForcedLongYear flag, but this also could get
933  // called for YY not only E format codes, no differentiation
934  // possible here; the good news is that usually the Gregorian
935  // calendar is the default and hence YY calls for Gregorian and
936  // E for the other calendar and currently (2013-02-28) ROC is
937  // the only calendar using this.
938  // See i#116701 and fdo#60915
939  if (value < 100 || bEraMode || (eraArray && (eraArray[0].flags & kDisplayEraForcedLongYear)))
940  sprintf(aStr, "%d", value); // #100211# - checked
941  else
942  sprintf(aStr, "%02d", value % 100); // #100211# - checked
943  break;
944  case CalendarDisplayCode::LONG_DAY:
945  sprintf(aStr, "%02d", value); // #100211# - checked
946  break;
947 
948  case CalendarDisplayCode::SHORT_DAY_NAME:
949  return getDisplayName(CalendarDisplayIndex::DAY, value, 0);
950  case CalendarDisplayCode::LONG_DAY_NAME:
951  return getDisplayName(CalendarDisplayIndex::DAY, value, 1);
952  case CalendarDisplayCode::NARROW_DAY_NAME:
953  return getDisplayName(CalendarDisplayIndex::DAY, value, 2);
954  case CalendarDisplayCode::SHORT_MONTH_NAME:
955  return getDisplayName(CalendarDisplayIndex::MONTH, value, 0);
956  case CalendarDisplayCode::LONG_MONTH_NAME:
957  return getDisplayName(CalendarDisplayIndex::MONTH, value, 1);
958  case CalendarDisplayCode::NARROW_MONTH_NAME:
959  return getDisplayName(CalendarDisplayIndex::MONTH, value, 2);
960  case CalendarDisplayCode::SHORT_GENITIVE_MONTH_NAME:
961  return getDisplayName(CalendarDisplayIndex::GENITIVE_MONTH, value, 0);
962  case CalendarDisplayCode::LONG_GENITIVE_MONTH_NAME:
963  return getDisplayName(CalendarDisplayIndex::GENITIVE_MONTH, value, 1);
964  case CalendarDisplayCode::NARROW_GENITIVE_MONTH_NAME:
965  return getDisplayName(CalendarDisplayIndex::GENITIVE_MONTH, value, 2);
966  case CalendarDisplayCode::SHORT_PARTITIVE_MONTH_NAME:
967  return getDisplayName(CalendarDisplayIndex::PARTITIVE_MONTH, value, 0);
968  case CalendarDisplayCode::LONG_PARTITIVE_MONTH_NAME:
969  return getDisplayName(CalendarDisplayIndex::PARTITIVE_MONTH, value, 1);
970  case CalendarDisplayCode::NARROW_PARTITIVE_MONTH_NAME:
971  return getDisplayName(CalendarDisplayIndex::PARTITIVE_MONTH, value, 2);
972  case CalendarDisplayCode::SHORT_ERA:
973  return getDisplayName(CalendarDisplayIndex::ERA, value, 0);
974  case CalendarDisplayCode::LONG_ERA:
975  return getDisplayName(CalendarDisplayIndex::ERA, value, 1);
976 
977  case CalendarDisplayCode::SHORT_YEAR_AND_ERA:
978  return getDisplayStringImpl( CalendarDisplayCode::SHORT_ERA, nNativeNumberMode, true ) +
979  getDisplayStringImpl( CalendarDisplayCode::SHORT_YEAR, nNativeNumberMode, true );
980 
981  case CalendarDisplayCode::LONG_YEAR_AND_ERA:
982  return getDisplayStringImpl( CalendarDisplayCode::LONG_ERA, nNativeNumberMode, true ) +
983  getDisplayStringImpl( CalendarDisplayCode::LONG_YEAR, nNativeNumberMode, true );
984 
985  default:
986  throw RuntimeException();
987  }
988  aOUStr = OUString::createFromAscii(aStr);
989  }
990  // NatNum12 used only for selected parts
991  if (nNativeNumberMode > 0 && nNativeNumberMode != 12) {
992  // For Japanese calendar, first year calls GAN, see bug 111668 for detail.
993  if (eraArray == gengou_eraArray && value == 1
994  && (nCalendarDisplayCode == CalendarDisplayCode::SHORT_YEAR ||
995  nCalendarDisplayCode == CalendarDisplayCode::LONG_YEAR)
996  && (nNativeNumberMode == NativeNumberMode::NATNUM1 ||
997  nNativeNumberMode == NativeNumberMode::NATNUM2)) {
998  static sal_Unicode gan = 0x5143;
999  return OUString(&gan, 1);
1000  }
1001  sal_Int16 nNatNum = NatNumForCalendar(aLocale, nCalendarDisplayCode, nNativeNumberMode, value);
1002  if (nNatNum > 0)
1003  return mxNatNum->getNativeNumberString(aOUStr, aLocale, nNatNum);
1004  }
1005  return aOUStr;
1006 }
1007 
1008 // Methods in XExtendedCalendar
1009 OUString SAL_CALL
1010 Calendar_buddhist::getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode )
1011 {
1012  // make year and era in different order for year before and after 0.
1013  if ((nCalendarDisplayCode == CalendarDisplayCode::LONG_YEAR_AND_ERA ||
1014  nCalendarDisplayCode == CalendarDisplayCode::SHORT_YEAR_AND_ERA) &&
1015  getValue(CalendarFieldIndex::ERA) == 0) {
1016  if (nCalendarDisplayCode == CalendarDisplayCode::LONG_YEAR_AND_ERA)
1017  return getDisplayStringImpl( CalendarDisplayCode::SHORT_YEAR, nNativeNumberMode, true ) +
1018  getDisplayStringImpl( CalendarDisplayCode::SHORT_ERA, nNativeNumberMode, true );
1019  else
1020  return getDisplayStringImpl( CalendarDisplayCode::LONG_YEAR, nNativeNumberMode, true ) +
1021  getDisplayStringImpl( CalendarDisplayCode::LONG_ERA, nNativeNumberMode, true );
1022  }
1023  return Calendar_gregorian::getDisplayString(nCalendarDisplayCode, nNativeNumberMode);
1024 }
1025 
1026 OUString SAL_CALL
1028 {
1029  return OUString::createFromAscii(cCalendar);
1030 }
1031 
1032 sal_Bool SAL_CALL
1033 Calendar_gregorian::supportsService(const OUString& rServiceName)
1034 {
1035  return cppu::supportsService(this, rServiceName);
1036 }
1037 
1038 Sequence< OUString > SAL_CALL
1040 {
1041  Sequence< OUString > aRet { OUString::createFromAscii(cCalendar) };
1042  return aRet;
1043 }
1044 
1045 }
1046 
1047 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const Era gengou_eraArray[]
exports com.sun.star.frame. status
sal_Int16 value
sal_Int32 month
virtual double SAL_CALL getDateTime() override
virtual double SAL_CALL getLocalDateTime() override
#define SAL_INFO_IF(condition, area, stream)
void init(const Era *_eraArray)
virtual ~Calendar_gregorian() override
Destructor.
virtual void SAL_CALL addValue(sal_Int16 nFieldIndex, sal_Int32 nAmount) override
virtual css::uno::Sequence< css::i18n::CalendarItem > SAL_CALL getMonths() override
static sal_Int32 DisplayCode2FieldIndex(sal_Int32 nCalendarDisplayCode)
void setValue()
Set fields internally.
virtual sal_Int16 SAL_CALL getNumberOfDaysInWeek() override
OUString getDisplayStringImpl(sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode, bool bEraMode)
virtual css::uno::Sequence< css::i18n::CalendarItem2 > SAL_CALL getPartitiveMonths2() override
const sal_Int16 FIELD_INDEX_COUNT
virtual css::i18n::Calendar SAL_CALL getLoadedCalendar() override
sal_uInt16 sal_Unicode
virtual OUString SAL_CALL getUniqueID() override
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
const Era dangi_eraArray[]
The start year of the Korean traditional calendar (Dan-gi) is the inaugural year of Dan-gun (BC 2333)...
virtual OUString SAL_CALL getImplementationName() override
double d
virtual css::uno::Sequence< css::i18n::CalendarItem2 > SAL_CALL getGenitiveMonths2() override
float y
virtual void SAL_CALL setDateTime(double fTimeInDays) override
virtual OUString SAL_CALL getDisplayString(sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode) override
void submitFields()
Submit fieldSetValue array according to fieldSet.
virtual sal_Bool SAL_CALL isValid() override
static rtl::Reference< LocaleDataImpl > get()
Definition: localedata.hxx:62
virtual css::uno::Sequence< css::i18n::CalendarItem2 > SAL_CALL getMonths2() override
const Era ROC_eraArray[]
bool getCombinedOffset(sal_Int32 &o_nOffset, sal_Int16 nParentFieldIndex, sal_Int16 nChildFieldIndex) const
Used by getZoneOffset() and getDSTOffset().
bool getDSTOffset(sal_Int32 &o_nOffset) const
Obtain combined field values for DST offset (minutes+secondmillis) in milliseconds and whether fields...
virtual css::uno::Sequence< css::i18n::CalendarItem > SAL_CALL getDays() override
const sal_uInt8 kDisplayEraForcedLongYear
unsigned char sal_Bool
sal_Int16 fieldValue[FIELD_INDEX_COUNT]
Constant values shared between i18npool and, for example, the number formatter.
virtual OUString SAL_CALL getDisplayName(sal_Int16 nCalendarDisplayIndex, sal_Int16 nIdx, sal_Int16 nNameType) override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
bool getZoneOffset(sal_Int32 &o_nOffset) const
Obtain combined field values for timezone offset (minutes+secondmillis) in milliseconds and whether f...
virtual OUString SAL_CALL getDisplayName(sal_Int16 nCalendarDisplayIndex, sal_Int16 nIdx, sal_Int16 nNameType) override
static sal_Int16 NatNumForCalendar(const css::lang::Locale &aLocale, sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode, sal_Int16 value)
const sal_uInt16 idx[]
virtual void SAL_CALL setFirstDayOfWeek(sal_Int16 nDay) override
sal_Int16 fieldSetValue[FIELD_INDEX_COUNT]
virtual sal_Int16 SAL_CALL getMinimumNumberOfDaysForFirstWeek() override
virtual css::uno::Sequence< css::i18n::CalendarItem2 > SAL_CALL getDays2() override
sal_Int32 day
static css::uno::Sequence< css::i18n::CalendarItem > downcastCalendarItems(const css::uno::Sequence< css::i18n::CalendarItem2 > &rCi)
Definition: localedata.cxx:369
rtl::Reference< NativeNumberSupplierService > mxNatNum
static UCalendarDateFields fieldNameConverter(sal_Int16 fieldIndex)
const Era buddhist_eraArray[]
virtual OUString SAL_CALL getDisplayString(sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode) override
virtual sal_Int16 SAL_CALL getNumberOfMonthsInYear() override
virtual sal_Int16 SAL_CALL getFirstDayOfWeek() override
virtual void SAL_CALL setLocalDateTime(double TimeInDays) override
#define DUMP_ICU_CAL_MSG(x)
virtual OUString SAL_CALL getDisplayName(sal_Int16 nCalendarDisplayIndex, sal_Int16 nIdx, sal_Int16 nNameType) override
#define FIELDS
#define DUMP_I18N_CAL_MSG(x)
void(* f)(TrueTypeTable *)
Degree100 abs(Degree100 x)
static css::i18n::Calendar downcastCalendar(const css::i18n::Calendar2 &rC)
Definition: localedata.cxx:376
virtual void SAL_CALL setMinimumNumberOfDaysForFirstWeek(sal_Int16 nDays) override
tuple m
std::unique_ptr< icu::Calendar > body
sal_Int32 year
sal_Int32 nNatNum
virtual void SAL_CALL loadCalendar(const OUString &uniqueID, const css::lang::Locale &rLocale) override
sal_Int32 h
aStr
virtual css::i18n::Calendar2 SAL_CALL getLoadedCalendar2() override
bool setTimeZone(const OUString &rTimeZone)