1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <sal/types.h>
11 #include <cppunit/TestAssert.h>
12 #include <cppunit/TestFixture.h>
13 #include <cppunit/extensions/HelperMacros.h>
14 #include <cppunit/plugin/TestPlugIn.h>
16 #include <sal/config.h>
18 #include <cppuhelper/bootstrap.hxx>
19 #include <comphelper/processfactory.hxx>
21 #include <com/sun/star/lang/XComponent.hpp>
22 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
23 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
24 #include <com/sun/star/uno/XComponentContext.hpp>
26 #include <i18nlangtag/lang.h>
30 #include <o3tl/nonstaticstring.hxx>
31 #include <svl/numformat.hxx>
32 #include <svl/zforlist.hxx>
33 #include <svl/zformat.hxx>
34 #include <svl/sharedstringpool.hxx>
35 #include <svl/sharedstring.hxx>
36 #include <tools/color.hxx>
37 #include <unotools/syslocale.hxx>
41 #include <unicode/timezone.h>
43 using namespace ::com::sun::star
;
48 static std::ostream
& operator<<(std::ostream
& rStrm
, const SharedString
& string
)
50 return rStrm
<< "(" << static_cast<const void*>(string
.getData()) << ")" << string
.getString();
57 class Test
: public CppUnit::TestFixture
{
60 virtual ~Test() override
;
62 virtual void tearDown() override
;
64 void testNumberFormat();
65 void testSharedString();
66 void testSharedStringPool();
67 void testSharedStringPoolPurge();
68 void testSharedStringPoolPurgeBug1();
69 void testSharedStringPoolEmptyString();
74 void testIsNumberFormat();
75 void testIsNumberFormatSpecific();
76 void testUserDefinedNumberFormats();
77 void testNfEnglishKeywordsIntegrity();
78 void testStandardColorIntegrity();
79 void testColorNamesConversion();
80 void testExcelExportFormats();
82 CPPUNIT_TEST_SUITE(Test
);
83 CPPUNIT_TEST(testNumberFormat
);
84 CPPUNIT_TEST(testSharedString
);
85 CPPUNIT_TEST(testSharedStringPool
);
86 CPPUNIT_TEST(testSharedStringPoolPurge
);
87 CPPUNIT_TEST(testSharedStringPoolPurgeBug1
);
88 CPPUNIT_TEST(testSharedStringPoolEmptyString
);
89 CPPUNIT_TEST(testFdo60915
);
90 CPPUNIT_TEST(testI116701
);
91 CPPUNIT_TEST(testTdf103060
);
92 CPPUNIT_TEST(testDateInput
);
93 CPPUNIT_TEST(testIsNumberFormat
);
94 CPPUNIT_TEST(testIsNumberFormatSpecific
);
95 CPPUNIT_TEST(testUserDefinedNumberFormats
);
96 CPPUNIT_TEST(testNfEnglishKeywordsIntegrity
);
97 CPPUNIT_TEST(testStandardColorIntegrity
);
98 CPPUNIT_TEST(testColorNamesConversion
);
99 CPPUNIT_TEST(testExcelExportFormats
);
100 CPPUNIT_TEST_SUITE_END();
103 uno::Reference
< uno::XComponentContext
> m_xContext
;
104 void checkPreviewString(SvNumberFormatter
& aFormatter
,
105 const OUString
& sCode
,
106 double fPreviewNumber
,
108 OUString
const & sExpected
);
109 void checkDateInput( SvNumberFormatter
& rFormatter
, const char* pTimezone
, const char* pIsoDate
);
110 std::unique_ptr
<icu::TimeZone
> m_pDefaultTimeZone
;
113 Test::Test() : m_xContext(cppu::defaultBootstrap_InitialComponentContext())
115 uno::Reference
<lang::XMultiComponentFactory
> xFactory(m_xContext
->getServiceManager());
116 uno::Reference
<lang::XMultiServiceFactory
> xSM(xFactory
, uno::UNO_QUERY_THROW
);
118 //Without this we're crashing because callees are using
119 //getProcessServiceFactory. In general those should be removed in favour
120 //of retaining references to the root ServiceFactory as it's passed around
121 comphelper::setProcessServiceFactory(xSM
);
122 m_pDefaultTimeZone
.reset(icu::TimeZone::createDefault());
125 void Test::tearDown()
127 icu::TimeZone::setDefault(*m_pDefaultTimeZone
);
132 uno::Reference
< lang::XComponent
>(m_xContext
, uno::UNO_QUERY_THROW
)->dispose();
135 void Test::testNumberFormat()
137 LanguageType eLang
= LANGUAGE_ENGLISH_US
;
139 const char* pNumber
[] = {
149 const char* pScientific
[] = {
155 const char* pPercent
[] = {
161 const char* pFraction
[] = {
167 // Following aren't in range of NF_FRACTION_START and NF_FRACTION_END
168 // see enum NfIndexTableOffset in svl/inc/svl/zforlist.hxx
169 const char* pFractionExt
[] = {
180 const char* pCurrency
[] = {
182 "$#,##0.00;-$#,##0.00",
183 "$#,##0;[RED]-$#,##0",
184 "$#,##0.00;[RED]-$#,##0.00",
186 "$#,##0.--;[RED]-$#,##0.--",
190 const char* pDate
[] = {
215 const char* pTime
[] = {
226 const char* pDateTime
[] = {
227 "MM/DD/YY HH:MM AM/PM",
228 "MM/DD/YYYY HH:MM:SS",
232 // Following aren't in range of NF_DATETIME_START and NF_DATETIME_END
233 // see enum NfIndexTableOffset in svl/inc/svl/zforlist.hxx
234 const char* pDateTimeExt1
[] = {
235 "MM/DD/YYYY HH:MM AM/PM",
239 const char* pDateTimeExt2
[] = {
240 "YYYY-MM-DD HH:MM:SS",
241 "YYYY-MM-DD HH:MM:SS.000",
242 "YYYY-MM-DD\"T\"HH:MM:SS",
243 "YYYY-MM-DD\"T\"HH:MM:SS.000",
247 const char* pBoolean
[] = {
252 const char* pText
[] = {
258 NfIndexTableOffset eStart
;
259 NfIndexTableOffset eEnd
;
263 { NF_NUMBER_START
, NF_NUMBER_END
, 6, pNumber
},
264 { NF_SCIENTIFIC_START
, NF_SCIENTIFIC_END
, 2, pScientific
},
265 { NF_PERCENT_START
, NF_PERCENT_END
, 2, pPercent
},
266 { NF_FRACTION_START
, NF_FRACTION_END
, 2, pFraction
},
267 { NF_CURRENCY_START
, NF_CURRENCY_END
, 6, pCurrency
},
268 { NF_DATE_START
, NF_DATE_END
, 21, pDate
},
269 { NF_TIME_START
, NF_TIME_END
, 7, pTime
},
270 { NF_DATETIME_START
, NF_DATETIME_END
, 2, pDateTime
},
271 { NF_BOOLEAN
, NF_BOOLEAN
, 1, pBoolean
},
272 { NF_TEXT
, NF_TEXT
, 1, pText
},
273 { NF_DATETIME_SYS_DDMMYYYY_HHMM
, NF_DATETIME_SYS_DDMMYYYY_HHMM
, 1, pDateTimeExt1
},
274 { NF_FRACTION_3D
, NF_FRACTION_100
, 7, pFractionExt
},
275 { NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, NF_DATETIME_ISO_YYYYMMDDTHHMMSS000
, 4, pDateTimeExt2
}
278 SvNumberFormatter
aFormatter(m_xContext
, eLang
);
280 for (auto const[eStart
, eEnd
, nSize
, pCodes
] : aTests
)
282 size_t nStart
= eStart
;
284 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected number of formats for this category.", nSize
,
285 (nEnd
- nStart
+ 1));
287 for (size_t j
= nStart
; j
<= nEnd
; ++j
)
290 aFormatter
.GetFormatIndex(static_cast<NfIndexTableOffset
>(j
));
291 const SvNumberformat
* p
= aFormatter
.GetEntry(nIndex
);
293 CPPUNIT_ASSERT_MESSAGE("Number format entry is expected, but doesn't exist.", p
);
294 OUString aCode
= p
->GetFormatstring();
295 CPPUNIT_ASSERT_EQUAL(OString( pCodes
[j
-nStart
]), aCode
.toUtf8());
300 SvNumFormatType nType
= SvNumFormatType::DEFINED
;
303 // Thai date format (implicit locale).
304 aCode
= "[$-1070000]d/mm/yyyy;@";
305 if (!aFormatter
.PutEntry(aCode
, nPos
, nType
, nKey
))
307 CPPUNIT_ASSERT_MESSAGE("failed to insert format code '[$-1070000]d/mm/yyyy;@'", false);
310 // Thai date format (explicit locale)
311 aCode
= "[$-107041E]d/mm/yyyy;@";
312 if (!aFormatter
.PutEntry(aCode
, nPos
, nType
, nKey
))
314 CPPUNIT_ASSERT_MESSAGE("failed to insert format code '[$-107041E]d/mm/yyyy;@'", false);
317 // Thai date format (using buddhist calendar type).
318 aCode
= "[~buddhist]D MMMM YYYY";
319 if (!aFormatter
.PutEntry(aCode
, nPos
, nType
, nKey
))
321 CPPUNIT_ASSERT_MESSAGE("failed to insert format code '[~buddhist]D MMMM YYYY'", false);
325 void Test::testSharedString()
327 // Use shared string as normal, non-shared string, which is allowed.
328 SharedString
aSS1(u
"Test"_ustr
), aSS2(u
"Test"_ustr
);
329 CPPUNIT_ASSERT_MESSAGE("Equality check should return true.", bool(aSS1
== aSS2
));
330 SharedString
aSS3(u
"test"_ustr
);
331 CPPUNIT_ASSERT_MESSAGE("Equality check is case sensitive.", aSS1
!= aSS3
);
334 void Test::testSharedStringPool()
336 SvtSysLocale aSysLocale
;
337 svl::SharedStringPool
aPool(aSysLocale
.GetCharClass());
339 svl::SharedString p1
, p2
;
340 p1
= aPool
.intern(u
"Andy"_ustr
);
341 p2
= aPool
.intern(u
"Andy"_ustr
);
342 CPPUNIT_ASSERT_EQUAL(p1
.getData(), p2
.getData());
344 p2
= aPool
.intern(u
"Bruce"_ustr
);
345 CPPUNIT_ASSERT_MESSAGE("They must differ.", p1
.getData() != p2
.getData());
347 OUString
aAndy(u
"Andy"_ustr
);
348 p1
= aPool
.intern(u
"Andy"_ustr
);
349 p2
= aPool
.intern(aAndy
);
350 CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be NULL.", p1
.getData());
351 CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be NULL.", p2
.getData());
352 CPPUNIT_ASSERT_EQUAL(p1
.getData(), p2
.getData());
354 // Test case insensitive string ID's.
355 p1
= aPool
.intern(aAndy
);
356 p2
= aPool
.intern(u
"andy"_ustr
);
357 CPPUNIT_ASSERT_MESSAGE("Failed to intern strings.", p1
.getData());
358 CPPUNIT_ASSERT_MESSAGE("Failed to intern strings.", p2
.getData());
359 CPPUNIT_ASSERT_MESSAGE("These two ID's should differ.", p1
.getData() != p2
.getData());
360 CPPUNIT_ASSERT_EQUAL_MESSAGE("These two ID's should be equal.", p2
.getDataIgnoreCase(), p1
.getDataIgnoreCase());
361 p2
= aPool
.intern(u
"ANDY"_ustr
);
362 CPPUNIT_ASSERT_MESSAGE("Failed to intern string.", p2
.getData());
363 CPPUNIT_ASSERT_MESSAGE("These two ID's should differ.", p1
.getData() != p2
.getData());
364 CPPUNIT_ASSERT_EQUAL_MESSAGE("These two ID's should be equal.", p2
.getDataIgnoreCase(), p1
.getDataIgnoreCase());
367 void Test::testSharedStringPoolPurge()
369 SvtSysLocale aSysLocale
;
370 svl::SharedStringPool
aPool(aSysLocale
.GetCharClass());
371 size_t extraCount
= aPool
.getCount(); // internal items such as SharedString::getEmptyString()
372 size_t extraCountIgnoreCase
= aPool
.getCountIgnoreCase();
374 aPool
.intern(o3tl::nonStaticString(u
"Andy"));
375 aPool
.intern(o3tl::nonStaticString(u
"andy"));
376 aPool
.intern(o3tl::nonStaticString(u
"ANDY"));
378 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong string count.", 3+extraCount
, aPool
.getCount());
379 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong case insensitive string count.", 1+extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
381 // Since no string objects referencing the pooled strings exist, purging
382 // the pool should empty it (except for internal items).
384 CPPUNIT_ASSERT_EQUAL(extraCount
, aPool
.getCount());
385 CPPUNIT_ASSERT_EQUAL(extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
387 // Now, create string objects using optional so we can clear them
388 std::optional
<svl::SharedString
> pStr1
= aPool
.intern(o3tl::nonStaticString(u
"Andy"));
389 std::optional
<svl::SharedString
> pStr2
= aPool
.intern(o3tl::nonStaticString(u
"andy"));
390 std::optional
<svl::SharedString
> pStr3
= aPool
.intern(o3tl::nonStaticString(u
"ANDY"));
391 std::optional
<svl::SharedString
> pStr4
= aPool
.intern(o3tl::nonStaticString(u
"Bruce"));
393 CPPUNIT_ASSERT_EQUAL(5+extraCount
, aPool
.getCount());
394 CPPUNIT_ASSERT_EQUAL(2+extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
396 // This shouldn't purge anything.
398 CPPUNIT_ASSERT_EQUAL(5+extraCount
, aPool
.getCount());
399 CPPUNIT_ASSERT_EQUAL(2+extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
401 // Delete one heap string object, and purge. That should purge one string.
404 CPPUNIT_ASSERT_EQUAL(4+extraCount
, aPool
.getCount());
405 CPPUNIT_ASSERT_EQUAL(2+extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
407 // Nothing changes, because the upper-string is still in the map
410 CPPUNIT_ASSERT_EQUAL(4+extraCount
, aPool
.getCount());
411 CPPUNIT_ASSERT_EQUAL(2+extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
416 CPPUNIT_ASSERT_EQUAL(2+extraCount
, aPool
.getCount());
417 CPPUNIT_ASSERT_EQUAL(1+extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
419 // Delete 'Bruce' and purge.
422 CPPUNIT_ASSERT_EQUAL(extraCount
, aPool
.getCount());
423 CPPUNIT_ASSERT_EQUAL(extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
426 void Test::testSharedStringPoolPurgeBug1()
428 // We had a bug where, if we had two strings that mapped to the same uppercase string,
429 // purge() would de-reference a dangling pointer and consequently cause an ASAN failure.
430 SvtSysLocale aSysLocale
;
431 svl::SharedStringPool
aPool(aSysLocale
.GetCharClass());
432 size_t extraCount
= aPool
.getCount(); // internal items such as SharedString::getEmptyString()
433 size_t extraCountIgnoreCase
= aPool
.getCountIgnoreCase();
434 aPool
.intern(o3tl::nonStaticString(u
"Andy"));
435 aPool
.intern(o3tl::nonStaticString(u
"andy"));
437 CPPUNIT_ASSERT_EQUAL(extraCount
, aPool
.getCount());
438 CPPUNIT_ASSERT_EQUAL(extraCountIgnoreCase
, aPool
.getCountIgnoreCase());
441 void Test::testSharedStringPoolEmptyString()
443 // Make sure SharedString::getEmptyString() is in the pool and matches empty strings.
444 SvtSysLocale aSysLocale
;
445 svl::SharedStringPool
aPool(aSysLocale
.GetCharClass());
446 aPool
.intern(u
""_ustr
);
447 CPPUNIT_ASSERT_EQUAL(SharedString::getEmptyString(), aPool
.intern(u
""_ustr
));
448 CPPUNIT_ASSERT_EQUAL(SharedString::getEmptyString(), aPool
.intern(SharedString::EMPTY_STRING
));
449 // And it should still work even after purging.
451 CPPUNIT_ASSERT_EQUAL(SharedString::getEmptyString(), aPool
.intern(SharedString::EMPTY_STRING
));
454 void Test::checkPreviewString(SvNumberFormatter
& aFormatter
,
455 const OUString
& sCode
,
456 double fPreviewNumber
,
458 OUString
const & sExpected
)
461 const Color
* pColor
= nullptr;
462 if (!aFormatter
.GetPreviewString(sCode
, fPreviewNumber
, sStr
, &pColor
, eLang
))
464 OString aMessage
= "GetPreviewString( \"" +
465 OUStringToOString( sCode
, RTL_TEXTENCODING_ASCII_US
) +
467 OString::number( fPreviewNumber
) +
469 aMessage
+= OString::number( static_cast<sal_uInt16
>(eLang
) ) +
471 CPPUNIT_FAIL( aMessage
.getStr() );
473 CPPUNIT_ASSERT_EQUAL(sExpected
, sStr
);
476 void Test::testFdo60915()
478 LanguageType eLang
= LANGUAGE_THAI
;
479 OUString sCode
, sExpected
;
480 double fPreviewNumber
= 36486; // equals 1999-11-22 (2542 B.E.)
481 SvNumberFormatter
aFormatter(m_xContext
, eLang
);
483 sCode
= "[~buddhist]D/MM/YYYY";
484 sExpected
= "22/11/2542";
485 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
488 sCode
= "[~buddhist]D/MM/YY";
489 sExpected
= "22/11/42";
490 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
493 sCode
= "[NatNum1][$-41E][~buddhist]D/MM/YYYY";
494 sal_Unicode sTemp
[] =
496 0x0E52, 0x0E52, 0x002F,
497 0x0E51, 0x0E51, 0x002F,
498 0x0E52, 0x0E55, 0x0E54, 0x0E52
500 sExpected
= OUString(sTemp
, SAL_N_ELEMENTS(sTemp
));
501 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
504 sCode
= "[NatNum1][$-41E][~buddhist]D/MM/YY";
505 sal_Unicode sTemp
[] =
507 0x0E52, 0x0E52, 0x002F,
508 0x0E51, 0x0E51, 0x002F,
511 sExpected
= OUString(sTemp
, SAL_N_ELEMENTS(sTemp
));
512 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
516 // https://bz.apache.org/ooo/show_bug.cgi?id=116701
517 void Test::testI116701()
519 LanguageType eLang
= LANGUAGE_CHINESE_TRADITIONAL
;
520 OUString sCode
, sExpected
;
521 double fPreviewNumber
= 40573; // equals 30/01/2011
522 SvNumberFormatter
aFormatter(m_xContext
, eLang
);
523 // DateFormatskey25 in i18npool/source/localedata/data/zh_TW.xml
524 sal_Unicode CODE1
[] =
526 0x0047, 0x0047, 0x0047, 0x0045, 0x0045, // GGGEE
527 0x0022, 0x5E74, 0x0022,
529 0x0022, 0x6708, 0x0022,
531 0x0022, 0x65E5, 0x0022
533 sCode
= OUString(CODE1
, SAL_N_ELEMENTS(CODE1
));
534 sal_Unicode EXPECTED
[] =
536 0x4E2D, 0x83EF, 0x6C11, 0x570B,
537 0x0031, 0x0030, 0x0030, // 100
541 0x0033, 0x0030, // 30
544 sExpected
= OUString(EXPECTED
, SAL_N_ELEMENTS(EXPECTED
));
545 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
546 sal_Unicode CODE2
[] =
548 0x0047, 0x0047, 0x0047, 0x0045, // GGGE
549 0x0022, 0x5E74, 0x0022,
551 0x0022, 0x6708, 0x0022,
553 0x0022, 0x65E5, 0x0022
555 sCode
= OUString(CODE2
, SAL_N_ELEMENTS(CODE2
));
556 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
559 void Test::testTdf103060()
561 LanguageType eLang
= LANGUAGE_JAPANESE
;
562 OUString sCode
, sExpected
;
563 double fPreviewNumber
= 42655; // equals 2016-10-12
564 SvNumberFormatter
aFormatter(m_xContext
, eLang
);
566 sExpected
= "H"; // Heisei era
567 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
569 sExpected
= u
"\u5E73"_ustr
;
570 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
572 sExpected
= u
"\u5E73\u6210"_ustr
;
573 checkPreviewString(aFormatter
, sCode
, fPreviewNumber
, eLang
, sExpected
);
576 void Test::testDateInput()
578 const char* aData
[][2] = {
579 { "Europe/Paris", "1938-10-07" }, // i#76623
580 { "Europe/Moscow", "1919-07-01" }, // i#86094
581 { "America/St_Johns", "1935-03-30" }, // i#86094 i#90627
582 { "Europe/Tallinn", "1790-03-01" }, // i#105864
583 { "Australia/Perth", "2004-04-11" }, // i#17222
584 { "America/Sao_Paulo", "1902-04-22" }, // tdf#44286
585 { "Europe/Berlin", "1790-07-27" },
586 { "US/Mountain", "1790-07-26" },
587 { "Asia/Tehran", "1999-03-22" },
589 // Data from https://bugs.documentfoundation.org/show_bug.cgi?id=63230
590 // https://bugs.documentfoundation.org/attachment.cgi?id=79051
591 // https://bugs.documentfoundation.org/show_bug.cgi?id=79663
592 { "Africa/Accra", "1800-01-01" },
593 { "Africa/Accra", "1800-04-10" },
594 { "Africa/Addis_Ababa", "1870-01-01" },
595 { "Africa/Addis_Ababa", "1936-05-05" },
596 { "Africa/Algiers", "1956-01-29" },
597 { "Africa/Algiers", "1981-05-01" },
598 { "Africa/Asmara", "1936-05-05" },
599 { "Africa/Asmera", "1936-05-05" },
600 { "Africa/Bujumbura", "1890-01-01" },
601 { "Africa/Casablanca", "1984-03-16" },
602 { "Africa/Ceuta", "1984-03-16" },
603 { "Africa/Dar_es_Salaam", "1931-01-01" },
604 { "Africa/Dar_es_Salaam", "1961-01-01" },
605 { "Africa/Djibouti", "1911-07-01" },
606 { "Africa/Douala", "1912-01-01" },
607 { "Africa/El_Aaiun", "1934-01-01" },
608 { "Africa/Freetown", "1913-06-01" },
609 { "Africa/Gaborone", "1885-01-01" },
610 { "Africa/Johannesburg", "1903-03-01" },
611 { "Africa/Kampala", "1928-07-01" },
612 { "Africa/Kampala", "1948-01-01" },
613 { "Africa/Kampala", "1957-01-01" },
614 { "Africa/Lagos", "1919-09-01" },
615 { "Africa/Libreville", "1912-01-01" },
616 { "Africa/Luanda", "1911-05-26" },
617 { "Africa/Lubumbashi", "1897-11-09" },
618 { "Africa/Lusaka", "1903-03-01" },
619 { "Africa/Malabo", "1963-12-15" },
620 { "Africa/Maseru", "1903-03-01" },
621 { "Africa/Mogadishu", "1957-01-01" },
622 { "Africa/Monrovia", "1919-03-01" },
623 { "Africa/Nairobi", "1928-07-01" },
624 { "Africa/Nairobi", "1940-01-01" },
625 { "Africa/Nairobi", "1960-01-01" },
626 { "Africa/Niamey", "1960-01-01" },
627 { "Africa/Porto-Novo", "1934-02-26" },
628 { "Africa/Tripoli", "1920-01-01" },
629 { "Africa/Tripoli", "1959-01-01" },
630 { "Africa/Tripoli", "1990-05-04" },
631 { "Africa/Tunis", "1911-03-11" },
632 { "Africa/Windhoek", "1892-02-08" },
633 { "Africa/Windhoek", "1903-03-01" },
634 { "America/Antigua", "1912-03-02" },
635 { "America/Argentina/Buenos_Aires", "1894-10-31" },
636 { "America/Argentina/Catamarca", "1991-10-20" },
637 { "America/Argentina/Catamarca", "2004-06-01" },
638 { "America/Argentina/ComodRivadavia", "1991-10-20" },
639 { "America/Argentina/ComodRivadavia", "2004-06-01" },
640 { "America/Argentina/Cordoba", "1991-10-20" },
641 { "America/Argentina/Jujuy", "1991-10-06" },
642 { "America/Argentina/La_Rioja", "2004-06-01" },
643 { "America/Argentina/Mendoza", "1992-10-18" },
644 { "America/Argentina/Mendoza", "2004-05-23" },
645 { "America/Argentina/Rio_Gallegos", "2004-06-01" },
646 { "America/Argentina/Salta", "1991-10-20" },
647 { "America/Argentina/San_Juan", "2004-05-31" },
648 { "America/Argentina/San_Luis", "2004-05-31" },
649 { "America/Argentina/San_Luis", "2008-01-21" },
650 { "America/Argentina/Tucuman", "1991-10-20" },
651 { "America/Argentina/Tucuman", "2004-06-01" },
652 { "America/Argentina/Ushuaia", "2004-05-30" },
653 { "America/Asuncion", "1931-10-10" },
654 { "America/Asuncion", "1974-04-01" },
655 { "America/Bahia", "1914-01-01" },
656 { "America/Bahia_Banderas", "1930-11-15" },
657 { "America/Bahia_Banderas", "1931-10-01" },
658 { "America/Bahia_Banderas", "1942-04-24" },
659 { "America/Bahia_Banderas", "1949-01-14" },
660 { "America/Barbados", "1932-01-01" },
661 { "America/Belize", "1912-04-01" },
662 { "America/Blanc-Sablon", "1884-01-01" },
663 { "America/Bogota", "1914-11-23" },
664 { "America/Buenos_Aires", "1894-10-31" },
665 { "America/Cambridge_Bay", "2000-11-05" },
666 { "America/Campo_Grande", "1914-01-01" },
667 { "America/Caracas", "1912-02-12" },
668 { "America/Catamarca", "1991-10-20" },
669 { "America/Catamarca", "2004-06-01" },
670 { "America/Cayenne", "1911-07-01" },
671 { "America/Chihuahua", "1930-11-15" },
672 { "America/Chihuahua", "1931-10-01" },
673 { "America/Cordoba", "1991-10-20" },
674 { "America/Costa_Rica", "1921-01-15" },
675 { "America/Cuiaba", "1914-01-01" },
676 { "America/Danmarkshavn", "1916-07-28" },
677 { "America/Detroit", "1905-01-01" },
678 { "America/Eirunepe", "1914-01-01" },
679 { "America/El_Salvador", "1921-01-01" },
680 { "America/Ensenada", "1924-01-01" },
681 { "America/Ensenada", "1930-11-15" },
682 { "America/Fortaleza", "1914-01-01" },
683 { "America/Glace_Bay", "1902-06-15" },
684 { "America/Grand_Turk", "1890-01-01" },
685 { "America/Guyana", "1991-01-01" },
686 { "America/Havana", "1890-01-01" },
687 { "America/Hermosillo", "1930-11-15" },
688 { "America/Hermosillo", "1931-10-01" },
689 { "America/Hermosillo", "1942-04-24" },
690 { "America/Hermosillo", "1949-01-14" },
691 { "America/Jujuy", "1991-10-06" },
692 { "America/Lima", "1890-01-01" },
693 { "America/Maceio", "1914-01-01" },
694 { "America/Managua", "1890-01-01" },
695 { "America/Managua", "1934-06-23" },
696 { "America/Managua", "1975-02-16" },
697 { "America/Managua", "1992-09-24" },
698 { "America/Managua", "1997-01-01" },
699 { "America/Mazatlan", "1930-11-15" },
700 { "America/Mazatlan", "1931-10-01" },
701 { "America/Mazatlan", "1942-04-24" },
702 { "America/Mazatlan", "1949-01-14" },
703 { "America/Mendoza", "1992-10-18" },
704 { "America/Mendoza", "2004-05-23" },
705 { "America/Merida", "1982-12-02" },
706 { "America/Mexico_City", "1930-11-15" },
707 { "America/Mexico_City", "1931-10-01" },
708 { "America/Miquelon", "1911-05-15" },
709 { "America/Moncton", "1883-12-09" },
710 { "America/Montevideo", "1942-12-14" },
711 { "America/Montevideo", "1974-12-22" },
712 { "America/Montreal", "1884-01-01" },
713 { "America/Ojinaga", "1930-11-15" },
714 { "America/Ojinaga", "1931-10-01" },
715 { "America/Panama", "1890-01-01" },
716 { "America/Paramaribo", "1911-01-01" },
717 { "America/Porto_Acre", "1914-01-01" },
718 { "America/Recife", "1914-01-01" },
719 { "America/Regina", "1905-09-01" },
720 { "America/Rio_Branco", "1914-01-01" },
721 { "America/Rosario", "1991-10-20" },
722 { "America/Santa_Isabel", "1924-01-01" },
723 { "America/Santa_Isabel", "1930-11-15" },
724 { "America/Santarem", "1914-01-01" },
725 { "America/Santiago", "1910-01-01" },
726 { "America/Santiago", "1919-07-01" },
727 { "America/Santo_Domingo", "1890-01-01" },
728 { "America/Scoresbysund", "1916-07-28" },
729 { "America/Scoresbysund", "1981-03-29" },
730 { "America/Tegucigalpa", "1921-04-01" },
731 { "America/Thunder_Bay", "1895-01-01" },
732 { "America/Tijuana", "1924-01-01" },
733 { "America/Tijuana", "1930-11-15" },
734 { "Antarctica/Casey", "1969-01-01" },
735 { "Antarctica/Casey", "2009-10-18" },
736 { "Antarctica/Davis", "1957-01-13" },
737 { "Antarctica/Davis", "1969-02-01" },
738 { "Antarctica/Davis", "2010-03-11" },
739 { "Antarctica/DumontDUrville", "1947-01-01" },
740 { "Antarctica/DumontDUrville", "1956-11-01" },
741 { "Antarctica/Macquarie", "1911-01-01" },
742 { "Antarctica/Mawson", "1954-02-13" },
743 { "Antarctica/McMurdo", "1956-01-01" },
744 { "Antarctica/Palmer", "1982-05-01" },
745 { "Antarctica/South_Pole", "1956-01-01" },
746 { "Antarctica/Syowa", "1957-01-29" },
747 { "Antarctica/Vostok", "1957-12-16" },
748 { "Arctic/Longyearbyen", "1895-01-01" },
749 { "Asia/Almaty", "1930-06-21" },
750 { "Asia/Anadyr", "1924-05-02" },
751 { "Asia/Anadyr", "1930-06-21" },
752 { "Asia/Anadyr", "1992-01-19" },
753 { "Asia/Anadyr", "2011-03-27" },
754 { "Asia/Aqtau", "1924-05-02" },
755 { "Asia/Aqtau", "1930-06-21" },
756 { "Asia/Aqtau", "1981-10-01" },
757 { "Asia/Aqtau", "2005-03-15" },
758 { "Asia/Aqtobe", "1924-05-02" },
759 { "Asia/Aqtobe", "1930-06-21" },
760 { "Asia/Ashgabat", "1924-05-02" },
761 { "Asia/Ashgabat", "1930-06-21" },
762 { "Asia/Ashgabat", "1992-01-19" },
763 { "Asia/Ashkhabad", "1924-05-02" },
764 { "Asia/Ashkhabad", "1930-06-21" },
765 { "Asia/Ashkhabad", "1992-01-19" },
766 { "Asia/Baghdad", "1918-01-01" },
767 { "Asia/Bahrain", "1920-01-01" },
768 { "Asia/Baku", "1957-03-01" },
769 { "Asia/Bangkok", "1920-04-01" },
770 { "Asia/Bishkek", "1924-05-02" },
771 { "Asia/Bishkek", "1930-06-21" },
772 { "Asia/Brunei", "1933-01-01" },
773 { "Asia/Calcutta", "1941-10-01" },
774 { "Asia/Choibalsan", "1978-01-01" },
775 { "Asia/Chongqing", "1980-05-01" },
776 { "Asia/Chungking", "1980-05-01" },
777 { "Asia/Colombo", "1880-01-01" },
778 { "Asia/Colombo", "1906-01-01" },
779 { "Asia/Colombo", "1942-09-01" },
780 { "Asia/Colombo", "1996-05-25" },
781 { "Asia/Dacca", "1941-10-01" },
782 { "Asia/Dacca", "1942-09-01" },
783 { "Asia/Dhaka", "1941-10-01" },
784 { "Asia/Dhaka", "1942-09-01" },
785 { "Asia/Dili", "2000-09-17" },
786 { "Asia/Dubai", "1920-01-01" },
787 { "Asia/Dushanbe", "1924-05-02" },
788 { "Asia/Dushanbe", "1930-06-21" },
789 { "Asia/Harbin", "1928-01-01" },
790 { "Asia/Harbin", "1940-01-01" },
791 { "Asia/Ho_Chi_Minh", "1912-05-01" },
792 { "Asia/Hong_Kong", "1904-10-30" },
793 { "Asia/Hong_Kong", "1941-12-25" },
794 { "Asia/Hovd", "1978-01-01" },
795 { "Asia/Irkutsk", "1920-01-25" },
796 { "Asia/Irkutsk", "1930-06-21" },
797 { "Asia/Irkutsk", "1992-01-19" },
798 { "Asia/Irkutsk", "2011-03-27" },
799 { "Asia/Istanbul", "1880-01-01" },
800 { "Asia/Istanbul", "1910-10-01" },
801 { "Asia/Istanbul", "1978-10-15" },
802 { "Asia/Jakarta", "1932-11-01" },
803 { "Asia/Jakarta", "1942-03-23" },
804 { "Asia/Jakarta", "1948-05-01" },
805 { "Asia/Jayapura", "1944-09-01" },
806 { "Asia/Kabul", "1945-01-01" },
807 { "Asia/Kamchatka", "1922-11-10" },
808 { "Asia/Kamchatka", "1930-06-21" },
809 { "Asia/Kamchatka", "1992-01-19" },
810 { "Asia/Kamchatka", "2011-03-27" },
811 { "Asia/Karachi", "1907-01-01" },
812 { "Asia/Kashgar", "1928-01-01" },
813 { "Asia/Kashgar", "1980-05-01" },
814 { "Asia/Kathmandu", "1986-01-01" },
815 { "Asia/Katmandu", "1986-01-01" },
816 { "Asia/Kolkata", "1941-10-01" },
817 { "Asia/Krasnoyarsk", "1930-06-21" },
818 { "Asia/Krasnoyarsk", "1992-01-19" },
819 { "Asia/Krasnoyarsk", "2011-03-27" },
820 { "Asia/Kuala_Lumpur", "1901-01-01" },
821 { "Asia/Kuala_Lumpur", "1905-06-01" },
822 { "Asia/Kuala_Lumpur", "1941-09-01" },
823 { "Asia/Kuala_Lumpur", "1942-02-16" },
824 { "Asia/Kuala_Lumpur", "1982-01-01" },
825 { "Asia/Kuching", "1926-03-01" },
826 { "Asia/Kuching", "1933-01-01" },
827 { "Asia/Kuching", "1942-02-16" },
828 { "Asia/Macao", "1912-01-01" },
829 { "Asia/Macau", "1912-01-01" },
830 { "Asia/Magadan", "1930-06-21" },
831 { "Asia/Magadan", "1992-01-19" },
832 { "Asia/Magadan", "2011-03-27" },
833 { "Asia/Makassar", "1932-11-01" },
834 { "Asia/Makassar", "1942-02-09" },
835 { "Asia/Manila", "1942-05-01" },
836 { "Asia/Muscat", "1920-01-01" },
837 { "Asia/Novokuznetsk", "1920-01-06" },
838 { "Asia/Novokuznetsk", "1930-06-21" },
839 { "Asia/Novokuznetsk", "1992-01-19" },
840 { "Asia/Novokuznetsk", "2011-03-27" },
841 { "Asia/Novosibirsk", "1930-06-21" },
842 { "Asia/Novosibirsk", "1992-01-19" },
843 { "Asia/Novosibirsk", "2011-03-27" },
844 { "Asia/Omsk", "1919-11-14" },
845 { "Asia/Omsk", "1930-06-21" },
846 { "Asia/Omsk", "1992-01-19" },
847 { "Asia/Omsk", "2011-03-27" },
848 { "Asia/Oral", "1924-05-02" },
849 { "Asia/Oral", "1930-06-21" },
850 { "Asia/Oral", "2005-03-15" },
851 { "Asia/Phnom_Penh", "1906-06-09" },
852 { "Asia/Phnom_Penh", "1912-05-01" },
853 { "Asia/Pontianak", "1932-11-01" },
854 { "Asia/Pontianak", "1942-01-29" },
855 { "Asia/Pontianak", "1948-05-01" },
856 { "Asia/Pontianak", "1964-01-01" },
857 { "Asia/Pyongyang", "1890-01-01" },
858 { "Asia/Pyongyang", "1904-12-01" },
859 { "Asia/Pyongyang", "1932-01-01" },
860 { "Asia/Pyongyang", "1961-08-10" },
861 { "Asia/Qatar", "1920-01-01" },
862 { "Asia/Qyzylorda", "1930-06-21" },
863 { "Asia/Qyzylorda", "1992-01-19" },
864 { "Asia/Rangoon", "1920-01-01" },
865 { "Asia/Rangoon", "1942-05-01" },
866 { "Asia/Saigon", "1912-05-01" },
867 { "Asia/Sakhalin", "1945-08-25" },
868 { "Asia/Sakhalin", "1992-01-19" },
869 { "Asia/Sakhalin", "2011-03-27" },
870 { "Asia/Samarkand", "1930-06-21" },
871 { "Asia/Seoul", "1890-01-01" },
872 { "Asia/Seoul", "1904-12-01" },
873 { "Asia/Seoul", "1932-01-01" },
874 { "Asia/Seoul", "1961-08-10" },
875 { "Asia/Seoul", "1968-10-01" },
876 { "Asia/Singapore", "1905-06-01" },
877 { "Asia/Singapore", "1941-09-01" },
878 { "Asia/Singapore", "1942-02-16" },
879 { "Asia/Singapore", "1982-01-01" },
880 { "Asia/Tashkent", "1924-05-02" },
881 { "Asia/Tashkent", "1930-06-21" },
882 { "Asia/Tbilisi", "1924-05-02" },
883 { "Asia/Tbilisi", "1957-03-01" },
884 { "Asia/Tbilisi", "2005-03-27" },
885 { "Asia/Tehran", "1946-01-01" },
886 { "Asia/Tehran", "1977-11-01" },
887 { "Asia/Thimbu", "1987-10-01" },
888 { "Asia/Thimphu", "1987-10-01" },
889 { "Asia/Ujung_Pandang", "1932-11-01" },
890 { "Asia/Ujung_Pandang", "1942-02-09" },
891 { "Asia/Ulaanbaatar", "1978-01-01" },
892 { "Asia/Ulan_Bator", "1978-01-01" },
893 { "Asia/Urumqi", "1928-01-01" },
894 { "Asia/Urumqi", "1980-05-01" },
895 { "Asia/Vientiane", "1906-06-09" },
896 { "Asia/Vientiane", "1912-05-01" },
897 { "Asia/Vladivostok", "1922-11-15" },
898 { "Asia/Vladivostok", "1930-06-21" },
899 { "Asia/Vladivostok", "1992-01-19" },
900 { "Asia/Vladivostok", "2011-03-27" },
901 { "Asia/Yakutsk", "1930-06-21" },
902 { "Asia/Yakutsk", "1992-01-19" },
903 { "Asia/Yakutsk", "2011-03-27" },
904 { "Asia/Yekaterinburg", "1930-06-21" },
905 { "Asia/Yekaterinburg", "1992-01-19" },
906 { "Asia/Yekaterinburg", "2011-03-27" },
907 { "Asia/Yerevan", "1924-05-02" },
908 { "Asia/Yerevan", "1957-03-01" },
909 { "Atlantic/Azores", "1884-01-01" },
910 { "Atlantic/Azores", "1911-05-24" },
911 { "Atlantic/Azores", "1942-04-25" },
912 { "Atlantic/Azores", "1943-04-17" },
913 { "Atlantic/Azores", "1944-04-22" },
914 { "Atlantic/Azores", "1945-04-21" },
915 { "Atlantic/Cape_Verde", "1907-01-01" },
916 { "Atlantic/Jan_Mayen", "1895-01-01" },
917 { "Atlantic/Madeira", "1942-04-25" },
918 { "Atlantic/Madeira", "1943-04-17" },
919 { "Atlantic/Madeira", "1944-04-22" },
920 { "Atlantic/Madeira", "1945-04-21" },
921 { "Atlantic/Reykjavik", "1837-01-01" },
922 { "Atlantic/Stanley", "1912-03-12" },
923 { "Australia/Adelaide", "1899-05-01" },
924 { "Australia/Broken_Hill", "1895-02-01" },
925 { "Australia/Broken_Hill", "1899-05-01" },
926 { "Australia/Currie", "1895-09-01" },
927 { "Australia/Darwin", "1895-02-01" },
928 { "Australia/Darwin", "1899-05-01" },
929 { "Australia/Eucla", "1895-12-01" },
930 { "Australia/Hobart", "1895-09-01" },
931 { "Australia/LHI", "1981-03-01" },
932 { "Australia/Lindeman", "1895-01-01" },
933 { "Australia/Lord_Howe", "1981-03-01" },
934 { "Australia/Melbourne", "1895-02-01" },
935 { "Australia/North", "1895-02-01" },
936 { "Australia/North", "1899-05-01" },
937 { "Australia/Perth", "1895-12-01" },
938 { "Australia/South", "1899-05-01" },
939 { "Australia/Tasmania", "1895-09-01" },
940 { "Australia/Victoria", "1895-02-01" },
941 { "Australia/West", "1895-12-01" },
942 { "Australia/Yancowinna", "1895-02-01" },
943 { "Australia/Yancowinna", "1899-05-01" },
944 { "Brazil/Acre", "1914-01-01" },
945 { "Canada/East-Saskatchewan", "1905-09-01" },
946 { "Canada/Saskatchewan", "1905-09-01" },
947 { "Chile/Continental", "1910-01-01" },
948 { "Chile/Continental", "1919-07-01" },
949 { "Chile/EasterIsland", "1932-09-01" },
950 { "Cuba", "1890-01-01" },
951 { "Eire", "1880-08-02" },
952 { "Europe/Amsterdam", "1937-07-01" },
953 { "Europe/Andorra", "1946-09-30" },
954 { "Europe/Athens", "1916-07-28" },
955 { "Europe/Athens", "1944-04-04" },
956 { "Europe/Berlin", "1893-04-01" },
957 { "Europe/Bratislava", "1891-10-01" },
958 { "Europe/Brussels", "1914-11-08" },
959 { "Europe/Bucharest", "1931-07-24" },
960 { "Europe/Chisinau", "1931-07-24" },
961 { "Europe/Copenhagen", "1894-01-01" },
962 { "Europe/Dublin", "1880-08-02" },
963 { "Europe/Gibraltar", "1941-05-04" },
964 { "Europe/Gibraltar", "1942-04-05" },
965 { "Europe/Gibraltar", "1943-04-04" },
966 { "Europe/Gibraltar", "1944-04-02" },
967 { "Europe/Gibraltar", "1945-04-02" },
968 { "Europe/Gibraltar", "1947-04-13" },
969 { "Europe/Helsinki", "1921-05-01" },
970 { "Europe/Istanbul", "1880-01-01" },
971 { "Europe/Istanbul", "1910-10-01" },
972 { "Europe/Istanbul", "1978-10-15" },
973 { "Europe/Kaliningrad", "1945-01-01" },
974 { "Europe/Kaliningrad", "1946-01-01" },
975 { "Europe/Kaliningrad", "2011-03-27" },
976 { "Europe/Kiev", "1930-06-21" },
977 { "Europe/Kiev", "1943-11-06" },
978 { "Europe/Luxembourg", "1904-06-01" },
979 { "Europe/Madrid", "1942-05-02" },
980 { "Europe/Madrid", "1943-04-17" },
981 { "Europe/Madrid", "1944-04-15" },
982 { "Europe/Madrid", "1945-04-14" },
983 { "Europe/Madrid", "1946-04-13" },
984 { "Europe/Malta", "1893-11-02" },
985 { "Europe/Mariehamn", "1921-05-01" },
986 { "Europe/Minsk", "1924-05-02" },
987 { "Europe/Minsk", "1930-06-21" },
988 { "Europe/Minsk", "2011-03-27" },
989 { "Europe/Monaco", "1941-05-05" },
990 { "Europe/Monaco", "1942-03-09" },
991 { "Europe/Monaco", "1943-03-29" },
992 { "Europe/Monaco", "1944-04-03" },
993 { "Europe/Monaco", "1945-04-02" },
994 { "Europe/Moscow", "1916-07-03" },
995 { "Europe/Moscow", "1919-05-31" },
996 { "Europe/Moscow", "1930-06-21" },
997 { "Europe/Moscow", "1992-01-19" },
998 { "Europe/Moscow", "2011-03-27" },
999 { "Europe/Oslo", "1895-01-01" },
1000 { "Europe/Paris", "1945-04-02" },
1001 { "Europe/Prague", "1891-10-01" },
1002 { "Europe/Riga", "1926-05-11" },
1003 { "Europe/Riga", "1940-08-05" },
1004 { "Europe/Riga", "1944-10-13" },
1005 { "Europe/Rome", "1893-11-01" },
1006 { "Europe/Samara", "1930-06-21" },
1007 { "Europe/Samara", "1991-10-20" },
1008 { "Europe/Samara", "2011-03-27" },
1009 { "Europe/San_Marino", "1893-11-01" },
1010 { "Europe/Simferopol", "1930-06-21" },
1011 { "Europe/Simferopol", "1994-05-01" },
1012 { "Europe/Sofia", "1880-01-01" },
1013 { "Europe/Sofia", "1894-11-30" },
1014 { "Europe/Tallinn", "1919-07-01" },
1015 { "Europe/Tallinn", "1921-05-01" },
1016 { "Europe/Tallinn", "1940-08-06" },
1017 { "Europe/Tiraspol", "1931-07-24" },
1018 { "Europe/Uzhgorod", "1945-06-29" },
1019 { "Europe/Vaduz", "1894-06-01" },
1020 { "Europe/Vatican", "1893-11-01" },
1021 { "Europe/Vilnius", "1917-01-01" },
1022 { "Europe/Vilnius", "1920-07-12" },
1023 { "Europe/Vilnius", "1940-08-03" },
1024 { "Europe/Volgograd", "1920-01-03" },
1025 { "Europe/Volgograd", "1930-06-21" },
1026 { "Europe/Volgograd", "1991-03-31" },
1027 { "Europe/Volgograd", "2011-03-27" },
1028 { "Europe/Zaporozhye", "1930-06-21" },
1029 { "Europe/Zaporozhye", "1943-10-25" },
1030 { "Europe/Zurich", "1894-06-01" },
1031 { "Hongkong", "1904-10-30" },
1032 { "Hongkong", "1941-12-25" },
1033 { "Iceland", "1837-01-01" },
1034 { "Indian/Chagos", "1907-01-01" },
1035 { "Indian/Chagos", "1996-01-01" },
1036 { "Indian/Cocos", "1900-01-01" },
1037 { "Indian/Comoro", "1911-07-01" },
1038 { "Indian/Kerguelen", "1950-01-01" },
1039 { "Indian/Mahe", "1906-06-01" },
1040 { "Indian/Maldives", "1960-01-01" },
1041 { "Indian/Mauritius", "1907-01-01" },
1042 { "Indian/Reunion", "1911-06-01" },
1043 { "Iran", "1946-01-01" },
1044 { "Iran", "1977-11-01" },
1045 { "Libya", "1920-01-01" },
1046 { "Libya", "1959-01-01" },
1047 { "Libya", "1990-05-04" },
1048 { "Mexico/BajaNorte", "1924-01-01" },
1049 { "Mexico/BajaNorte", "1930-11-15" },
1050 { "Mexico/BajaSur", "1930-11-15" },
1051 { "Mexico/BajaSur", "1931-10-01" },
1052 { "Mexico/BajaSur", "1942-04-24" },
1053 { "Mexico/BajaSur", "1949-01-14" },
1054 { "Mexico/General", "1930-11-15" },
1055 { "Mexico/General", "1931-10-01" },
1056 { "NZ-CHAT", "1957-01-01" },
1057 { "Pacific/Apia", "1911-01-01" },
1058 { "Pacific/Apia", "2011-12-30" },
1059 { "Pacific/Chatham", "1957-01-01" },
1060 { "Pacific/Easter", "1932-09-01" },
1061 { "Pacific/Enderbury", "1901-01-01" },
1062 { "Pacific/Enderbury", "1995-01-01" },
1063 { "Pacific/Fakaofo", "2011-12-30" },
1064 { "Pacific/Fiji", "1915-10-26" },
1065 { "Pacific/Funafuti", "1901-01-01" },
1066 { "Pacific/Galapagos", "1986-01-01" },
1067 { "Pacific/Gambier", "1912-10-01" },
1068 { "Pacific/Guadalcanal", "1912-10-01" },
1069 { "Pacific/Guam", "1901-01-01" },
1070 { "Pacific/Kiritimati", "1901-01-01" },
1071 { "Pacific/Kiritimati", "1995-01-01" },
1072 { "Pacific/Kosrae", "1901-01-01" },
1073 { "Pacific/Kosrae", "1969-10-01" },
1074 { "Pacific/Kwajalein", "1993-08-20" },
1075 { "Pacific/Majuro", "1969-10-01" },
1076 { "Pacific/Marquesas", "1912-10-01" },
1077 { "Pacific/Nauru", "1921-01-15" },
1078 { "Pacific/Nauru", "1944-08-15" },
1079 { "Pacific/Nauru", "1979-05-01" },
1080 { "Pacific/Niue", "1901-01-01" },
1081 { "Pacific/Niue", "1951-01-01" },
1082 { "Pacific/Norfolk", "1901-01-01" },
1083 { "Pacific/Norfolk", "1951-01-01" },
1084 { "Pacific/Pago_Pago", "1911-01-01" },
1085 { "Pacific/Palau", "1901-01-01" },
1086 { "Pacific/Pohnpei", "1901-01-01" },
1087 { "Pacific/Ponape", "1901-01-01" },
1088 { "Pacific/Port_Moresby", "1895-01-01" },
1089 { "Pacific/Rarotonga", "1978-11-12" },
1090 { "Pacific/Saipan", "1969-10-01" },
1091 { "Pacific/Samoa", "1911-01-01" },
1092 { "Pacific/Tahiti", "1912-10-01" },
1093 { "Pacific/Tarawa", "1901-01-01" },
1094 { "Pacific/Tongatapu", "1901-01-01" },
1095 { "Pacific/Tongatapu", "1941-01-01" },
1096 { "Pacific/Wake", "1901-01-01" },
1097 { "ROK", "1890-01-01" },
1098 { "ROK", "1904-12-01" },
1099 { "ROK", "1932-01-01" },
1100 { "ROK", "1961-08-10" },
1101 { "ROK", "1968-10-01" },
1102 { "Singapore", "1905-06-01" },
1103 { "Singapore", "1941-09-01" },
1104 { "Singapore", "1942-02-16" },
1105 { "Singapore", "1982-01-01" },
1106 { "Turkey", "1880-01-01" },
1107 { "Turkey", "1910-10-01" },
1108 { "Turkey", "1978-10-15" },
1109 { "US/Michigan", "1905-01-01" },
1110 { "US/Samoa", "1911-01-01" },
1111 { "W-SU", "1916-07-03" },
1112 { "W-SU", "1930-06-21" },
1113 { "W-SU", "1992-01-19" },
1114 { "W-SU", "2011-03-27" }
1117 LanguageType eLang
= LANGUAGE_ENGLISH_US
;
1118 SvNumberFormatter
aFormatter(m_xContext
, eLang
);
1120 for (auto const& aEntry
: aData
)
1122 checkDateInput(aFormatter
, aEntry
[0], aEntry
[1]);
1126 void Test::checkDateInput( SvNumberFormatter
& rFormatter
, const char* pTimezone
, const char* pIsoDate
)
1128 icu::TimeZone::adoptDefault( icu::TimeZone::createTimeZone( pTimezone
));
1129 OUString
aDate( OUString::createFromAscii(pIsoDate
));
1130 sal_uInt32 nIndex
= 0;
1132 bool bVal
= rFormatter
.IsNumberFormat( aDate
, nIndex
, fVal
);
1133 CPPUNIT_ASSERT_MESSAGE( OString(OString::Concat("Date not recognized: ") +
1134 pTimezone
+ " " + pIsoDate
).getStr(), bVal
);
1135 CPPUNIT_ASSERT_MESSAGE("Format parsed is not date.",
1136 (rFormatter
.GetType(nIndex
) & SvNumFormatType::DATE
));
1137 OUString aOutString
;
1138 const Color
*pColor
;
1139 rFormatter
.GetOutputString( fVal
, nIndex
, aOutString
, &pColor
);
1140 CPPUNIT_ASSERT_EQUAL( aDate
, aOutString
);
1143 void Test::testIsNumberFormat()
1145 LanguageType eLang
= LANGUAGE_ENGLISH_US
;
1146 SvNumberFormatter
aFormatter(m_xContext
, eLang
);
1148 static struct NumberFormatData
1150 const char* pFormat
;
1152 } const aTests
[] = {
1156 { "$0.12", true }, // tdf#48706
1157 { "$.12", true }, // tdf#48706
1158 { "1 .", false }, // tdf#131562
1159 { "1 .2", false }, // tdf#131562
1160 { "1 . 2", false }, // tdf#131562
1161 { "1. 2", false }, // tdf#131562
1162 { " . 2", false }, // tdf#131562
1163 { ". 2", false }, // tdf#131562
1164 { " .2", true }, // tdf#131562
1165 { "Jan1", false }, // tdf#34724
1166 { "1Jan", false }, // tdf#34724
1167 { "Jan1 2000", true }, // tdf#91420
1168 { "Jan1, 2000", true }, // tdf#91420
1170 { "Sept 1", true }, //tdf#127363
1171 { "5/d", false }, //tdf#143165
1172 { "Jan 1 2000", true },
1173 { "5-12-14", true }, // tdf#164239
1174 { "005-12-14", true },
1175 { "15-10-30", true },
1176 { "2015-10-30", true },
1177 { "1999-11-23T12:34:56", true },
1178 { "1999-11-23 12:34:56", true },
1179 { "1999-11-23T12:34:56.789", true },
1180 { "1999-11-23T12:34:56,789", true }, // ISO 8601 defines both dot and comma as fractional separator
1181 { "1999-11-23 12:34:56.789", true },
1182 { "1999-11-23 12:34:56,789", false }, // comma not in en-US if 'T' separator is not present,
1183 // debatable, 'T' "may be omitted by mutual consent of those
1184 // interchanging data, if ambiguity can be avoided."
1185 { "1999-11-23T12:34:56/789", false },
1186 { "−1000", true } // unicode minus
1189 for (auto const[pFormat
, bTestIsNumber
] : aTests
)
1191 sal_uInt32 nIndex
= 0;
1193 OUString aString
= OUString::fromUtf8(pFormat
);
1194 bool bIsNumber
= aFormatter
.IsNumberFormat(aString
, nIndex
, nNumber
);
1195 CPPUNIT_ASSERT_EQUAL_MESSAGE(pFormat
, bTestIsNumber
, bIsNumber
);
1199 struct FormatInputOutput
1201 const char* mpInput
;
1202 const bool mbNumber
;
1203 const char* mpOutput
;
1204 const sal_uInt32 mnOutputIndex
;
1207 void checkSpecificNumberFormats( SvNumberFormatter
& rFormatter
,
1208 const std::vector
<FormatInputOutput
>& rVec
, const char* pName
)
1211 for (size_t i
= 0; i
< rVec
.size(); ++i
)
1213 sal_uInt32 nIndex
= 0;
1215 OUString
aString( OUString::fromUtf8( rVec
[i
].mpInput
));
1216 const bool bIsNumber
= rFormatter
.IsNumberFormat( aString
, nIndex
, fNumber
);
1217 CPPUNIT_ASSERT_EQUAL_MESSAGE( OString( pName
+ OString::Concat(" ") + OString::number(i
) +
1218 (rVec
[i
].mbNumber
? " not recognized: " : " should not be recognized: ") +
1219 OUStringToOString( aString
, RTL_TEXTENCODING_UTF8
)).getStr(), rVec
[i
].mbNumber
, bIsNumber
);
1222 if (rVec
[i
].mnOutputIndex
)
1223 nIndex
= rVec
[i
].mnOutputIndex
;
1224 const Color
* pColor
;
1225 rFormatter
.GetOutputString( fNumber
, nIndex
, aString
, &pColor
);
1226 CPPUNIT_ASSERT_EQUAL_MESSAGE( OString( pName
+ OString::Concat(" ") + OString::number(i
) + " mismatch").getStr(),
1227 OUString::fromUtf8( rVec
[i
].mpOutput
), aString
);
1232 void Test::testIsNumberFormatSpecific()
1235 // en-US uses M/D/Y format, test that without Y-M-D pattern an a-b-c
1236 // input with a<=12 leads to ISO a-b-c date output.
1237 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_ENGLISH_US
);
1239 std::vector
<FormatInputOutput
> aIO
= {
1240 { "005-12-14", true, "0005-12-14", 0 },
1241 { "5-12-14", true, "2005-12-14", 0 },
1242 { "32-12-14", true, "1932-12-14", 0 }
1245 checkSpecificNumberFormats( aFormatter
, aIO
, "[en-US] date");
1249 // de-DE uses D.M.Y format, test that without Y-M-D pattern an a-b-c
1250 // input with a<=31 leads to ISO a-b-c date output.
1251 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_GERMAN
);
1253 std::vector
<FormatInputOutput
> aIO
= {
1254 { "005-12-14", true, "0005-12-14", 0 },
1255 { "5-12-14", true, "2005-12-14", 0 },
1256 { "32-12-14", true, "1932-12-14", 0 }
1259 checkSpecificNumberFormats( aFormatter
, aIO
, "[de-DE] date");
1263 // nl-NL uses D-M-Y format, test that D-M-Y input leads to D-M-Y output
1264 // and ISO Y-M-D input leads to Y-M-D output.
1265 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_DUTCH
);
1267 std::vector
<FormatInputOutput
> aIO
= {
1268 { "001-2-11", true, "0001-02-11", 0 },
1269 { "22-11-1999", true, "22-11-99", 0 }, // if default YY changes to YYYY adapt this
1270 { "1999-11-22", true, "1999-11-22", 0 },
1271 { "1-2-11", true, "01-02-11", 0 }, // if default YY changes to YYYY adapt this
1272 { "99-2-11", true, "1999-02-11", 0 }
1275 checkSpecificNumberFormats( aFormatter
, aIO
, "[nl-NL] date");
1279 // en-ZA uses Y-M-D and Y/M/D format, test that either are accepted.
1280 // The default format changed from YY/MM/DD to YYYY-MM-DD.
1281 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_ENGLISH_SAFRICA
);
1283 std::vector
<FormatInputOutput
> aIO
= {
1284 { "1999/11/22", true, "1999-11-22", 0 },
1285 { "1999-11-22", true, "1999-11-22", 0 },
1286 { "11/2/1", true, "2011-02-01", 0 },
1287 { "99-2-11", true, "1999-02-11", 0 },
1288 { "22-2-11", true, "2022-02-11", 0 },
1289 { "02 Mar 2020",true, "2020-03-02", 0 }
1292 checkSpecificNumberFormats( aFormatter
, aIO
, "[en-ZA] date");
1296 // fr-FR uses D/M/Y format with additional D.M.Y and D-M-Y date
1297 // acceptance patterns, test combinations.
1298 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_FRENCH
);
1300 std::vector
<FormatInputOutput
> aIO
= {
1301 { "22/11/1999", true, "22/11/99", 0 }, // if default YY changes to YYYY adapt this
1302 { "1999-11-22", true, "1999-11-22", 0 },
1303 { "1/2/11", true, "01/02/11", 0 }, // if default YY changes to YYYY adapt this
1304 { "99-2-11", true, "1999-02-11", 0 },
1305 { "22-2-11", true, "22/02/11", 0 }, // if default YY changes to YYYY adapt this
1306 { "22.2.11", true, "22/02/11", 0 } // if default YY changes to YYYY adapt this
1309 checkSpecificNumberFormats( aFormatter
, aIO
, "[fr-FR] date");
1313 // Test Spanish "mar" short name ambiguity, day "martes" or month "marzo".
1314 // Day of week names are only parsed away, not evaluated if they actually
1315 // correspond to the date given.
1316 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_SPANISH
);
1318 const sal_uInt32 n
= aFormatter
.GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, LANGUAGE_SPANISH
);
1319 std::vector
<FormatInputOutput
> aIO
= {
1320 { "22/11/1999", true, "22/11/1999", n
},
1321 { "Lun 22/11/1999", true, "22/11/1999", n
},
1322 { "Mar 22/11/1999", true, "22/11/1999", n
},
1323 { "Abr 22/11/1999", false, "", n
}, // month name AND numeric month don't go along
1324 { "Lun Mar 22/11/1999", false, "", n
}, // month name AND numeric month don't go along
1325 { "Mar Mar 22/11/1999", false, "", n
}, // month name AND numeric month don't go along
1326 { "Lun Mar 22 1999", true, "22/03/1999", n
},
1327 { "Mar Mar 22 1999", true, "22/03/1999", n
},
1328 { "Mar Lun 22 1999", false, "", n
} // day name only at the beginning (could change?)
1331 checkSpecificNumberFormats( aFormatter
, aIO
, "[es-ES] date");
1335 // Test that de-DE accepts Januar and Jänner.
1336 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_GERMAN
);
1338 const sal_uInt32 n
= aFormatter
.GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, LANGUAGE_GERMAN
);
1339 std::vector
<FormatInputOutput
> aIO
= {
1340 { "23. Januar 1999", true, "23.01.1999", n
},
1341 { "23. J\xC3\xA4nner 1999", true, "23.01.1999", n
},
1342 { "23. Jan. 1999", true, "23.01.1999", n
},
1343 { "23. J\xC3\xA4n. 1999", true, "23.01.1999", n
},
1346 checkSpecificNumberFormats( aFormatter
, aIO
, "[de-DE] date January month names");
1351 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_GERMAN
);
1353 const sal_uInt32 n
= aFormatter
.GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, LANGUAGE_GERMAN
);
1354 std::vector
<FormatInputOutput
> aIO
= {
1355 { "23. M\u00C4R 1999", true, "23.03.1999", n
},
1356 { "23. M\u00C4RZ 1999", true, "23.03.1999", n
},
1357 { "23. MRZ 1999", true, "23.03.1999", n
},
1360 checkSpecificNumberFormats( aFormatter
, aIO
, "[de-DE] date March month names");
1364 // Test that de-AT accepts Januar and Jänner.
1365 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_GERMAN_AUSTRIAN
);
1367 const sal_uInt32 n
= aFormatter
.GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, LANGUAGE_GERMAN_AUSTRIAN
);
1368 std::vector
<FormatInputOutput
> aIO
= {
1369 { "23. Januar 1999", true, "23.01.1999", n
},
1370 { "23. J\xC3\xA4nner 1999", true, "23.01.1999", n
},
1371 { "23. Jan. 1999", true, "23.01.1999", n
},
1372 { "23. J\xC3\xA4n. 1999", true, "23.01.1999", n
},
1375 checkSpecificNumberFormats( aFormatter
, aIO
, "[de-AT] date January month names");
1379 void Test::testUserDefinedNumberFormats()
1381 LanguageType eLang
= LANGUAGE_ENGLISH_US
;
1382 OUString sCode
, sExpected
;
1383 SvNumberFormatter
aFormatter(m_xContext
, eLang
);
1384 // tdf#158890 replace '?' with figure blank (0x2007)
1385 static constexpr OUString sBlankDigit
= u
" "_ustr
;
1386 { // tdf#97835: suppress decimal separator
1387 sCode
= "0.##\" m\"";
1389 checkPreviewString(aFormatter
, sCode
, 12.0, eLang
, sExpected
);
1391 { // tdf#61996: skip quoted text
1392 sCode
= "0.00\" ;\"";
1393 sExpected
= "-12.00 ;";
1394 checkPreviewString(aFormatter
, sCode
, -12.0, eLang
, sExpected
);
1397 sCode
= "000\" \"000/000";
1398 sExpected
= "003 016/113";
1399 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1402 sCode
= "#\" string \"?/???";
1403 sExpected
= "3 string 16/113";
1404 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1409 checkPreviewString(aFormatter
, sCode
, 2E+306, eLang
, sExpected
);
1412 sCode
= "YYYY-MM-DD";
1414 checkPreviewString(aFormatter
, sCode
, -12662108.0, eLang
, sExpected
);
1417 sCode
= "[HH]:MM:SS";
1418 sExpected
= "08:47:00";
1419 checkPreviewString(aFormatter
, sCode
, 0.365972222222222, eLang
, sExpected
);
1422 checkPreviewString(aFormatter
, sCode
, 0.365972222222222, eLang
, sExpected
);
1427 checkPreviewString(aFormatter
, sCode
, -0.5, eLang
, sExpected
);
1430 sCode
= "_($* #,##0.00_);_($* (#,##0.00);";
1432 checkPreviewString(aFormatter
, sCode
, 0.0, eLang
, sExpected
);
1434 { // tdf#95339: detect SSMM as second minute
1435 sCode
= "SS:MM:HH DD/MM/YY"; // Month not detected by Excel, but we do not follow that.
1436 sExpected
= "53:23:03 02/01/00";
1437 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1439 { // tdf#101147: detect SSMM as second month
1440 sCode
= "HH:MM:SS MM/DD";
1441 sExpected
= "03:23:53 01/02";
1442 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1445 sCode
= "HH:MM:SS.000000";
1446 sExpected
= "12:54:00.000000";
1447 checkPreviewString(aFormatter
, sCode
, 43521.5375, eLang
, sExpected
);
1449 { // tdf#101096: different detection of month/minute with Excel
1450 sCode
= "HH DD MM"; // month detected because of previous DD
1451 sExpected
= "03 02 01";
1452 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1453 sCode
= "HH:MM HH DD/MM"; // month detected because of previous DD
1454 sExpected
= "03:23 03 02/01";
1455 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1456 sCode
= "SS:DD-MM-YY SS:MM"; // 1st is month, because of previous DD; 2nd is minute as SS has not minute
1457 sExpected
= "53:02-01-00 53:23";
1458 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1460 { // tdf#99996: better algorithm for fraction representation
1462 sExpected
= "-575 540/697";
1463 checkPreviewString(aFormatter
, sCode
, -575.774749601315, eLang
, sExpected
);
1465 { // tdf#153887: integer value without integer part displayed
1468 checkPreviewString(aFormatter
, sCode
, 1.95, eLang
, sExpected
);
1469 checkPreviewString(aFormatter
, sCode
, 2.00, eLang
, sExpected
);
1470 checkPreviewString(aFormatter
, sCode
, 2.05, eLang
, sExpected
);
1473 checkPreviewString(aFormatter
, sCode
, 1.95, eLang
, sExpected
);
1474 checkPreviewString(aFormatter
, sCode
, 2.00, eLang
, sExpected
);
1475 checkPreviewString(aFormatter
, sCode
, 2.05, eLang
, sExpected
);
1477 { // tdf#102507: left alignment of denominator
1479 sExpected
= OUString::Concat( u
"3 1/2"_ustr
) + sBlankDigit
+ sBlankDigit
;
1480 checkPreviewString(aFormatter
, sCode
, 3.5, eLang
, sExpected
);
1482 { // tdf#100594: forced denominator
1484 sExpected
= " 6/100";
1485 checkPreviewString(aFormatter
, sCode
, 0.06, eLang
, sExpected
);
1487 { // tdf#100754: forced denominator with text after fraction
1488 sCode
= "# ?/16\" inch\"";
1489 sExpected
= "2 6/16 inch";
1490 checkPreviewString(aFormatter
, sCode
, 2.379, eLang
, sExpected
);
1492 { // tdf#100842: text before/after fraction
1493 sCode
= "\"before \"?/?\" after\"";
1494 sExpected
= "before 11/9 after";
1495 checkPreviewString(aFormatter
, sCode
, 1.2345667, eLang
, sExpected
);
1496 sCode
= "\"before \"# ?/?\" after\"";
1497 sExpected
= "before 1 2/9 after";
1498 checkPreviewString(aFormatter
, sCode
, 1.2345667, eLang
, sExpected
);
1499 sCode
= "\"before \"0.0\"inside\"0E+0\"middle\"0\" after\"";
1500 sExpected
= "before 1.2inside3E+0middle4 after";
1501 checkPreviewString(aFormatter
, sCode
, 12345.667, eLang
, sExpected
);
1503 { // tdf#106190: text after fraction bar
1505 sExpected
= "11/ 9";
1506 checkPreviewString(aFormatter
, sCode
, 1.2345667, eLang
, sExpected
);
1508 sExpected
= "15/ 12";
1509 checkPreviewString(aFormatter
, sCode
, 1.2345667, eLang
, sExpected
);
1510 sCode
= "# ?/\" divisor \"?";
1511 sExpected
= "1 2/ divisor 9";
1512 checkPreviewString(aFormatter
, sCode
, 1.2345667, eLang
, sExpected
);
1513 sCode
= "# ?/\"divided by \"?";
1514 sExpected
= "1 2/divided by 9";
1515 checkPreviewString(aFormatter
, sCode
, 1.2345667, eLang
, sExpected
);
1516 sCode
= "?/\" \"12";
1517 sExpected
= "15/ 12";
1518 checkPreviewString(aFormatter
, sCode
, 1.2345667, eLang
, sExpected
);
1520 sExpected
= "15/ 12";
1521 checkPreviewString(aFormatter
, sCode
, 1.2345667, eLang
, sExpected
);
1523 sExpected
= OUString::Concat( u
"3 1/ 2"_ustr
) + sBlankDigit
+ sBlankDigit
;
1524 checkPreviewString(aFormatter
, sCode
, 3.5, eLang
, sExpected
);
1526 { // Display 1.96 as 2 and not 1 1/1
1528 sExpected
= OUString::Concat( u
"2 "_ustr
) + sBlankDigit
+ u
" "_ustr
+ sBlankDigit
;
1529 checkPreviewString(aFormatter
, sCode
, 1.96, eLang
, sExpected
);
1531 sExpected
= OUString::Concat( u
"2 "_ustr
) + sBlankDigit
+ u
" "_ustr
+ sBlankDigit
;
1532 checkPreviewString(aFormatter
, sCode
, 1.96, eLang
, sExpected
);
1535 checkPreviewString(aFormatter
, sCode
, 1.96, eLang
, sExpected
);
1537 { // tdf#79399 tdf#101462 Native Number Formats
1538 sCode
= "[NatNum5][$-0404]General\\ ";
1539 // Chinese upper case number characters for 120
1540 sExpected
= u
"\u58F9\u4F70\u8CB3\u62FE "_ustr
;
1541 checkPreviewString(aFormatter
, sCode
, 120, eLang
, sExpected
);
1542 sCode
= "[DBNum2][$-0404]General\\ ";
1543 checkPreviewString(aFormatter
, sCode
, 120, eLang
, sExpected
);
1544 // tdf#115007 - cardinal/ordinal number names/indicators
1545 sCode
= "[NatNum12]0";
1546 sExpected
= "one hundred twenty-three";
1547 checkPreviewString(aFormatter
, sCode
, 123, eLang
, sExpected
);
1548 sCode
= "[NatNum12]0.00";
1549 sExpected
= "one hundred twenty-three point four five";
1550 checkPreviewString(aFormatter
, sCode
, 123.45, eLang
, sExpected
);
1551 sCode
= "[NatNum12 ordinal]0";
1552 sExpected
= "one hundred twenty-third";
1553 checkPreviewString(aFormatter
, sCode
, 123, eLang
, sExpected
);
1554 sCode
= "[NatNum12 ordinal-number]0";
1555 sExpected
= "123rd";
1556 checkPreviewString(aFormatter
, sCode
, 123, eLang
, sExpected
);
1557 sCode
= "[NatNum12 capitalize]0";
1558 sExpected
= "One hundred twenty-three";
1559 checkPreviewString(aFormatter
, sCode
, 123, eLang
, sExpected
);
1560 sCode
= "[NatNum12 title ordinal]0";
1561 sExpected
= "One Thousand Two Hundred Thirty-Fourth";
1562 checkPreviewString(aFormatter
, sCode
, 1234, eLang
, sExpected
);
1563 sCode
= "[NatNum12 upper ordinal-number]0";
1564 sExpected
= "12345TH";
1565 checkPreviewString(aFormatter
, sCode
, 12345, eLang
, sExpected
);
1566 sCode
= "[NatNum12 D=ordinal-number]D\" of \"MMMM";
1567 sExpected
= "2nd of January";
1568 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1569 sCode
= "[NatNum12 D=ordinal-number,YYYY=year]D\" of \"MMMM\", \"YYYY";
1570 sExpected
= "2nd of January, nineteen hundred";
1571 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1572 sCode
= "[NatNum12 YYYY=title year, D=capitalize ordinal]D\" of \"MMMM\", \"YYYY";
1573 sExpected
= "Second of January, Nineteen Hundred";
1574 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1575 sCode
= "[NatNum12 MMMM=upper MMM=upper MMMMM=upper]MMMM MMM MMMMM";
1576 sExpected
= "JANUARY JAN J";
1577 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1578 sCode
= "[NatNum12 DDDD=upper DDD=upper]DDDD DDD";
1579 sExpected
= "TUESDAY TUE";
1580 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1581 sCode
= "[NatNum12 NNN=upper NN=upper]NNN NN";
1582 sExpected
= "TUESDAY TUE";
1583 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1584 sCode
= "[NatNum12 MMMM=lower MMM=lower MMMMM=lower]MMMM MMM MMMMM";
1585 sExpected
= "january jan j";
1586 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1587 sCode
= "[NatNum12 DDDD=lower DDD=lower]DDDD DDD";
1588 sExpected
= "tuesday tue";
1589 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1590 sCode
= "[NatNum12 NNN=lower NN=lower]NNN NN";
1591 sExpected
= "tuesday tue";
1592 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1594 { // tdf#130193 tdf#130140 Native Number Formats mapping for Chinese (Traditional), Japanese, Korean
1595 // -- Traditional Chinese: DBNum1 -> NatNum4, DBNum2 -> NatNum5, DBnum3 -> NatNum3
1597 // DBNum1 -> NatNum4: Chinese lower case text for 123456789
1598 // 一億二千三百四十五萬六千七百八十九
1599 sExpected
= u
"\u4e00\u5104\u4e8c\u5343\u4e09\u767e\u56db\u5341\u4e94\u842c\u516d\u5343"
1600 u
"\u4e03\u767e\u516b\u5341\u4e5d "_ustr
;
1601 sCode
= "[NatNum4][$-0404]General\\ ";
1602 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1603 sCode
= "[DBNum1][$-0404]General\\ ";
1604 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1606 // DBNum2 -> NatNum5: Chinese upper case text
1607 // 壹億貳仟參佰肆拾伍萬陸仟柒佰捌拾玖
1608 sExpected
= u
"\u58f9\u5104\u8cb3\u4edf\u53c3\u4f70\u8086\u62fe\u4f0d\u842c\u9678\u4edf"
1609 u
"\u67d2\u4f70\u634c\u62fe\u7396 "_ustr
;
1610 sCode
= "[NatNum5][$-0404]General\\ ";
1611 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1612 sCode
= "[DBNum2][$-0404]General\\ ";
1613 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1615 // DBNum3 -> NatNum3: fullwidth text
1617 sExpected
= u
"\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19 "_ustr
;
1618 sCode
= "[NatNum3][$-0404]General\\ ";
1619 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1620 sCode
= "[DBNum3][$-0404]General\\ ";
1621 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1623 // -- Japanese: DBNum1 -> NatNum4, DBNum2 -> NatNum5, DBnum3 -> NatNum3
1625 // DBNum1 -> NatNum4: Japanese modern long Kanji text for 123456789
1626 // 一億二千三百四十五万六千七百八十九
1627 sExpected
= u
"\u4e00\u5104\u4e8c\u5343\u4e09\u767e\u56db\u5341\u4e94\u4e07\u516d\u5343"
1628 u
"\u4e03\u767e\u516b\u5341\u4e5d "_ustr
;
1629 sCode
= "[NatNum4][$-0411]General\\ ";
1630 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1631 sCode
= "[DBNum1][$-0411]General\\ ";
1632 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1634 // DBNum2 -> NatNum5: traditional long Kanji text
1635 // 壱億弐阡参百四拾伍萬六阡七百八拾九
1636 sExpected
= u
"\u58f1\u5104\u5f10\u9621\u53c2\u767e\u56db\u62fe\u4f0d\u842c\u516d\u9621"
1637 u
"\u4e03\u767e\u516b\u62fe\u4e5d "_ustr
;
1638 sCode
= "[NatNum5][$-0411]General\\ ";
1639 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1640 sCode
= "[DBNum2][$-0411]General\\ ";
1641 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1643 // DBNum3 -> NatNum3: fullwidth Arabic digits
1645 sExpected
= u
"\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19 "_ustr
;
1646 sCode
= "[NatNum3][$-0411]General\\ ";
1647 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1648 sCode
= "[DBNum3][$-0411]General\\ ";
1649 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1651 // -- Korean: DBNum1 -> NatNum4, DBNum2 -> NatNum5, DBNum3 -> NatNum6, DBNum4 -> NatNum10
1653 // DBNum1 -> NatNum4: Korean lower case characters
1654 // 一億二千三百四十五万六千七百八十九
1655 sExpected
= u
"\u4e00\u5104\u4e8c\u5343\u4e09\u767e\u56db\u5341\u4e94\u4e07\u516d\u5343\u4e03\u767e\u516b\u5341\u4e5d "_ustr
;
1656 sCode
= "[NatNum4][$-0412]General\\ ";
1657 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1658 sCode
= "[DBNum1][$-0412]General\\ ";
1659 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1661 // DBNum2 -> NatNum5: Korean upper case characters
1662 // 壹億貳阡參佰四拾伍萬六阡七佰八拾九
1663 sExpected
= u
"\u58f9\u5104\u8cb3\u9621\u53c3\u4f70\u56db\u62fe\u4f0d\u842c\u516d\u9621\u4e03\u4f70\u516b\u62fe\u4e5d "_ustr
;
1664 sCode
= "[NatNum5][$-0412]General\\ ";
1665 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1666 sCode
= "[DBNum2][$-0412]General\\ ";
1667 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1669 // DBNum3 -> NatNum6: fullwidth Arabic digits
1670 // 1억2천3백4십5만6천7백8십9
1671 sExpected
= u
"\uff11\uc5b5\uff12\ucc9c\uff13\ubc31\uff14\uc2ed\uff15\ub9cc\uff16\ucc9c\uff17\ubc31\uff18\uc2ed\uff19 "_ustr
;
1672 sCode
= "[NatNum6][$-0412]General\\ ";
1673 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1674 sCode
= "[DBNum3][$-0412]General\\ ";
1675 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1677 // DBNum4 -> NatNum10: Hangul characters
1678 // 일억이천삼백사십오만육천칠백팔십구
1679 sExpected
= u
"\uc77c\uc5b5\uc774\ucc9c\uc0bc\ubc31\uc0ac\uc2ed\uc624\ub9cc\uc721\ucc9c\uce60\ubc31\ud314\uc2ed\uad6c "_ustr
;
1680 sCode
= "[NatNum10][$-0412]General\\ ";
1681 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1682 sCode
= "[DBNum4][$-0412]General\\ ";
1683 checkPreviewString(aFormatter
, sCode
, 123456789, eLang
, sExpected
);
1685 { // tdf#105968 engineering format with value rounded up to next magnitude
1686 sCode
= "##0.00E+00";
1687 sExpected
= "100.00E+00";
1688 checkPreviewString(aFormatter
, sCode
, 99.995, eLang
, sExpected
);
1689 // test '1'=='1' assumption
1690 checkPreviewString(aFormatter
, sCode
, 100.0, eLang
, sExpected
);
1691 sExpected
= "199.99E+00";
1692 checkPreviewString(aFormatter
, sCode
, 199.99, eLang
, sExpected
);
1693 sExpected
= "1.00E+03";
1694 checkPreviewString(aFormatter
, sCode
, 1000.0, eLang
, sExpected
);
1695 // and another just "normally" rounded value
1696 sExpected
= "894.55E-06";
1697 checkPreviewString(aFormatter
, sCode
, 0.000894549, eLang
, sExpected
);
1698 // not expecting rounding into another magnitude
1699 sExpected
= "999.99E-06";
1700 checkPreviewString(aFormatter
, sCode
, 0.000999991, eLang
, sExpected
);
1701 // expecting rounding into another magnitude
1702 sExpected
= "1.00E-03";
1703 checkPreviewString(aFormatter
, sCode
, 0.000999999, eLang
, sExpected
);
1705 // Now the same all negative values.
1706 sExpected
= "-100.00E+00";
1707 checkPreviewString(aFormatter
, sCode
, -99.995, eLang
, sExpected
);
1708 checkPreviewString(aFormatter
, sCode
, -100.0, eLang
, sExpected
);
1709 sExpected
= "-199.99E+00";
1710 checkPreviewString(aFormatter
, sCode
, -199.99, eLang
, sExpected
);
1711 sExpected
= "-1.00E+03";
1712 checkPreviewString(aFormatter
, sCode
, -1000.0, eLang
, sExpected
);
1713 sExpected
= "-894.55E-06";
1714 checkPreviewString(aFormatter
, sCode
, -0.000894549, eLang
, sExpected
);
1715 sExpected
= "-999.99E-06";
1716 checkPreviewString(aFormatter
, sCode
, -0.000999991, eLang
, sExpected
);
1717 sExpected
= "-1.00E-03";
1718 checkPreviewString(aFormatter
, sCode
, -0.000999999, eLang
, sExpected
);
1720 { // tdf#112933 one decimal seconds fraction
1722 sExpected
= "23:53.6";
1723 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1726 sExpected
= "23:53.61";
1727 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1729 sCode
= "MM:SS.000";
1730 sExpected
= "23:53.605";
1731 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1733 // Same with date+time.
1734 sCode
= "YYYY-MM-DD MM:SS.0";
1735 sExpected
= "1900-01-02 23:53.6";
1736 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1737 sCode
= "YYYY-MM-DD MM:SS.00";
1738 sExpected
= "1900-01-02 23:53.61";
1739 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1740 sCode
= "YYYY-MM-DD MM:SS.000";
1741 sExpected
= "1900-01-02 23:53.605";
1742 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1744 { // tdf#150028 decimals of seconds fraction without truncate on overflow
1746 sExpected
= "271434";
1747 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1750 sExpected
= "271433.6";
1751 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1754 sExpected
= "271433.61";
1755 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1758 sExpected
= "271433.605";
1759 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1761 { // tdf#156449 Use '?' in exponent of scientific number
1763 sExpected
= OUString::Concat( u
"3.14E+"_ustr
) + sBlankDigit
+ u
"0"_ustr
; // before change it was "3.14E+00"
1764 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1765 // There should be at least one '0' in exponent
1767 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1769 { // tdf#33689 use English NfKeywords in non-English language
1770 eLang
= LANGUAGE_DUTCH
;
1771 sExpected
= "Dutch: 1900/01/02 03:23:53";
1772 sCode
= "\"Dutch:\" JJJJ/MM/DD UU:MM:SS";
1773 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1774 sCode
= "\"Dutch: \"YYYY/MM/DD HH:MM:SS";
1775 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1776 eLang
= LANGUAGE_GERMAN
;
1777 sExpected
= "German: 1900/01/02 03:23:53";
1778 sCode
= "\"German: \"JJJJ/MM/TT HH:MM:SS";
1779 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1780 sCode
= "\"German: \"YYYY/MM/DD HH:MM:SS";
1781 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1782 eLang
= LANGUAGE_FRENCH
;
1783 sExpected
= "French: 1900/01/02 03:23:53";
1784 sCode
= "\"French: \"AAAA/MM/JJ HH:MM:SS";
1785 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1786 sCode
= "\"French: \"YYYY/MM/DD HH:MM:SS";
1787 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1788 eLang
= LANGUAGE_ITALIAN
;
1789 sExpected
= "Italian: 1900/01/02 03:23:53";
1790 sCode
= "\"Italian: \"AAAA/MM/GG HH:MM:SS";
1791 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1792 sCode
= "\"Italian: \"YYYY/MM/DD HH:MM:SS";
1793 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1794 eLang
= LANGUAGE_PORTUGUESE
;
1795 sExpected
= "Portuguese: 1900/01/02 03:23:53";
1796 sCode
= "\"Portuguese: \"AAAA/MM/DD HH:MM:SS";
1797 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1798 sCode
= "\"Portuguese: \"YYYY/MM/DD HH:MM:SS";
1799 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1800 eLang
= LANGUAGE_SPANISH_MODERN
;
1801 sExpected
= "Spanish: 1900/01/02 03:23:53";
1802 sCode
= "\"Spanish: \"AAAA/MM/DD HH:MM:SS";
1803 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1804 sCode
= "\"Spanish: \"YYYY/MM/DD HH:MM:SS";
1805 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1806 eLang
= LANGUAGE_DANISH
;
1807 sExpected
= "Danish: 1900/01/02 03:23:53";
1808 sCode
= "\"Danish: \"YYYY/MM/DD TT:MM:SS";
1809 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1810 sCode
= "\"Danish: \"YYYY/MM/DD HH:MM:SS";
1811 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1812 eLang
= LANGUAGE_FINNISH
;
1813 sExpected
= "Finnish: 1900/01/02 03:23:53";
1814 sCode
= "\"Finnish: \"VVVV/KK/PP TT:MM:SS";
1815 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1816 sCode
= "\"Finnish: \"YYYY/MM/DD HH:MM:SS";
1817 checkPreviewString(aFormatter
, sCode
, M_PI
, eLang
, sExpected
);
1819 { // tdf#117819 wrong separator positions when displaying integers with
1820 // more decimals than rtl::math::doubleToUString delivers.
1821 sCode
= "#,##0.00000000000000000000";
1822 sExpected
= "117,669,030,460,994.00000000000000000000";
1823 checkPreviewString(aFormatter
, sCode
, 117669030460994.0, LANGUAGE_ENGLISH_US
, sExpected
);
1825 { // tdf#117575 treat thousand separator with '?' in integer part
1826 sCode
= "\"Value= \"?,??0.00";
1827 sExpected
= OUString::Concat( u
"Value= "_ustr
) + sBlankDigit
+ u
" "_ustr
+ sBlankDigit
+ sBlankDigit
+ u
"3.14"_ustr
;
1828 checkPreviewString(aFormatter
, sCode
, M_PI
, LANGUAGE_ENGLISH_US
, sExpected
);
1829 sExpected
= OUString::Concat( u
"Value= "_ustr
) + sBlankDigit
+ u
" "_ustr
+ sBlankDigit
+ u
"12.00"_ustr
;
1830 checkPreviewString(aFormatter
, sCode
, 12, LANGUAGE_ENGLISH_US
, sExpected
);
1831 sExpected
= OUString::Concat( u
"Value= "_ustr
) + sBlankDigit
+ u
" 123.00"_ustr
;
1832 checkPreviewString(aFormatter
, sCode
, 123, LANGUAGE_ENGLISH_US
, sExpected
);
1833 sExpected
= "Value= 1,234.00";
1834 checkPreviewString(aFormatter
, sCode
, 1234, LANGUAGE_ENGLISH_US
, sExpected
);
1835 sExpected
= "Value= 12,345.00";
1836 checkPreviewString(aFormatter
, sCode
, 12345, LANGUAGE_ENGLISH_US
, sExpected
);
1838 { // tdf#159930 no digit in integer part
1839 sCode
= "+.000;-.000";
1840 sExpected
= "+3.142"; // without the patch is would display "3+.142"
1841 checkPreviewString(aFormatter
, sCode
, M_PI
, LANGUAGE_ENGLISH_US
, sExpected
);
1845 void Test::testNfEnglishKeywordsIntegrity()
1847 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_ENGLISH_US
);
1848 const NfKeywordTable
& rEnglishKeywords
= SvNumberFormatter::GetEnglishKeywords();
1849 const NfKeywordTable
& sKeywords
= aFormatter
.GetKeywords(0);
1850 CPPUNIT_ASSERT_EQUAL( size_t(NF_KEYWORD_ENTRIES_COUNT
), rEnglishKeywords
.size() );
1851 for (size_t i
= 0; i
< size_t(NF_KEYWORD_ENTRIES_COUNT
); ++i
)
1853 CPPUNIT_ASSERT_EQUAL( sKeywords
[i
], rEnglishKeywords
[i
] );
1855 // Check the order of sEnglishKeyword
1856 CPPUNIT_ASSERT_EQUAL( u
"E"_ustr
, rEnglishKeywords
[NF_KEY_E
] );
1857 CPPUNIT_ASSERT_EQUAL( u
"AM/PM"_ustr
, rEnglishKeywords
[NF_KEY_AMPM
] );
1858 CPPUNIT_ASSERT_EQUAL( u
"A/P"_ustr
, rEnglishKeywords
[NF_KEY_AP
] );
1859 CPPUNIT_ASSERT_EQUAL( u
"M"_ustr
, rEnglishKeywords
[NF_KEY_MI
] );
1860 CPPUNIT_ASSERT_EQUAL( u
"MM"_ustr
, rEnglishKeywords
[NF_KEY_MMI
] );
1861 CPPUNIT_ASSERT_EQUAL( u
"M"_ustr
, rEnglishKeywords
[NF_KEY_M
] );
1862 CPPUNIT_ASSERT_EQUAL( u
"MM"_ustr
, rEnglishKeywords
[NF_KEY_MM
] );
1863 CPPUNIT_ASSERT_EQUAL( u
"MMM"_ustr
, rEnglishKeywords
[NF_KEY_MMM
] );
1864 CPPUNIT_ASSERT_EQUAL( u
"MMMM"_ustr
, rEnglishKeywords
[NF_KEY_MMMM
] );
1865 CPPUNIT_ASSERT_EQUAL( u
"H"_ustr
, rEnglishKeywords
[NF_KEY_H
] );
1866 CPPUNIT_ASSERT_EQUAL( u
"HH"_ustr
, rEnglishKeywords
[NF_KEY_HH
] );
1867 CPPUNIT_ASSERT_EQUAL( u
"S"_ustr
, rEnglishKeywords
[NF_KEY_S
] );
1868 CPPUNIT_ASSERT_EQUAL( u
"SS"_ustr
, rEnglishKeywords
[NF_KEY_SS
] );
1869 CPPUNIT_ASSERT_EQUAL( u
"Q"_ustr
, rEnglishKeywords
[NF_KEY_Q
] );
1870 CPPUNIT_ASSERT_EQUAL( u
"QQ"_ustr
, rEnglishKeywords
[NF_KEY_QQ
] );
1871 CPPUNIT_ASSERT_EQUAL( u
"D"_ustr
, rEnglishKeywords
[NF_KEY_D
] );
1872 CPPUNIT_ASSERT_EQUAL( u
"DD"_ustr
, rEnglishKeywords
[NF_KEY_DD
] );
1873 CPPUNIT_ASSERT_EQUAL( u
"DDD"_ustr
, rEnglishKeywords
[NF_KEY_DDD
] );
1874 CPPUNIT_ASSERT_EQUAL( u
"DDDD"_ustr
, rEnglishKeywords
[NF_KEY_DDDD
] );
1875 CPPUNIT_ASSERT_EQUAL( u
"YY"_ustr
, rEnglishKeywords
[NF_KEY_YY
] );
1876 CPPUNIT_ASSERT_EQUAL( u
"YYYY"_ustr
, rEnglishKeywords
[NF_KEY_YYYY
] );
1877 CPPUNIT_ASSERT_EQUAL( u
"NN"_ustr
, rEnglishKeywords
[NF_KEY_NN
] );
1878 CPPUNIT_ASSERT_EQUAL( u
"NNNN"_ustr
, rEnglishKeywords
[NF_KEY_NNNN
] );
1879 CPPUNIT_ASSERT_EQUAL( u
"CCC"_ustr
, rEnglishKeywords
[NF_KEY_CCC
] );
1880 CPPUNIT_ASSERT_EQUAL( u
"GENERAL"_ustr
, rEnglishKeywords
[NF_KEY_GENERAL
] );
1881 CPPUNIT_ASSERT_EQUAL( u
"NNN"_ustr
, rEnglishKeywords
[NF_KEY_NNN
] );
1882 CPPUNIT_ASSERT_EQUAL( u
"WW"_ustr
, rEnglishKeywords
[NF_KEY_WW
] );
1883 CPPUNIT_ASSERT_EQUAL( u
"MMMMM"_ustr
, rEnglishKeywords
[NF_KEY_MMMMM
] );
1884 CPPUNIT_ASSERT_EQUAL( u
"TRUE"_ustr
, rEnglishKeywords
[NF_KEY_TRUE
] );
1885 CPPUNIT_ASSERT_EQUAL( u
"FALSE"_ustr
, rEnglishKeywords
[NF_KEY_FALSE
] );
1886 CPPUNIT_ASSERT_EQUAL( u
"BOOLEAN"_ustr
, rEnglishKeywords
[NF_KEY_BOOLEAN
] );
1887 CPPUNIT_ASSERT_EQUAL( u
"COLOR"_ustr
, rEnglishKeywords
[NF_KEY_COLOR
] );
1888 CPPUNIT_ASSERT_EQUAL( u
"BLACK"_ustr
, rEnglishKeywords
[NF_KEY_BLACK
] );
1889 CPPUNIT_ASSERT_EQUAL( u
"BLUE"_ustr
, rEnglishKeywords
[NF_KEY_BLUE
] );
1890 CPPUNIT_ASSERT_EQUAL( u
"GREEN"_ustr
, rEnglishKeywords
[NF_KEY_GREEN
] );
1891 CPPUNIT_ASSERT_EQUAL( u
"CYAN"_ustr
, rEnglishKeywords
[NF_KEY_CYAN
] );
1892 CPPUNIT_ASSERT_EQUAL( u
"RED"_ustr
, rEnglishKeywords
[NF_KEY_RED
] );
1893 CPPUNIT_ASSERT_EQUAL( u
"MAGENTA"_ustr
, rEnglishKeywords
[NF_KEY_MAGENTA
] );
1894 CPPUNIT_ASSERT_EQUAL( u
"BROWN"_ustr
, rEnglishKeywords
[NF_KEY_BROWN
] );
1895 CPPUNIT_ASSERT_EQUAL( u
"GREY"_ustr
, rEnglishKeywords
[NF_KEY_GREY
] );
1896 CPPUNIT_ASSERT_EQUAL( u
"YELLOW"_ustr
, rEnglishKeywords
[NF_KEY_YELLOW
] );
1897 CPPUNIT_ASSERT_EQUAL( u
"WHITE"_ustr
, rEnglishKeywords
[NF_KEY_WHITE
] );
1898 CPPUNIT_ASSERT_EQUAL( u
"AAA"_ustr
, rEnglishKeywords
[NF_KEY_AAA
]);
1899 CPPUNIT_ASSERT_EQUAL( u
"AAAA"_ustr
, rEnglishKeywords
[NF_KEY_AAAA
] );
1900 CPPUNIT_ASSERT_EQUAL( u
"E"_ustr
, rEnglishKeywords
[NF_KEY_EC
] );
1901 CPPUNIT_ASSERT_EQUAL( u
"EE"_ustr
, rEnglishKeywords
[NF_KEY_EEC
] );
1902 CPPUNIT_ASSERT_EQUAL( u
"G"_ustr
, rEnglishKeywords
[NF_KEY_G
] );
1903 CPPUNIT_ASSERT_EQUAL( u
"GG"_ustr
, rEnglishKeywords
[NF_KEY_GG
] );
1904 CPPUNIT_ASSERT_EQUAL( u
"GGG"_ustr
, rEnglishKeywords
[NF_KEY_GGG
] );
1905 CPPUNIT_ASSERT_EQUAL( u
"R"_ustr
, rEnglishKeywords
[NF_KEY_R
] );
1906 CPPUNIT_ASSERT_EQUAL( u
"RR"_ustr
, rEnglishKeywords
[NF_KEY_RR
] );
1907 CPPUNIT_ASSERT_EQUAL( u
"t"_ustr
, rEnglishKeywords
[NF_KEY_THAI_T
] );
1910 void Test::testStandardColorIntegrity()
1912 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_ENGLISH_US
);
1913 const ::std::vector
<Color
> & rStandardColors
= SvNumberFormatter::GetStandardColors();
1914 const size_t nMaxDefaultColors
= SvNumberFormatter::GetMaxDefaultColors();
1915 CPPUNIT_ASSERT_EQUAL( size_t(NF_KEY_LASTCOLOR
) - size_t(NF_KEY_FIRSTCOLOR
) + 1, nMaxDefaultColors
);
1916 CPPUNIT_ASSERT_EQUAL( nMaxDefaultColors
, rStandardColors
.size() );
1917 // Colors must follow same order as in sEnglishKeyword
1918 CPPUNIT_ASSERT_EQUAL( COL_BLACK
, rStandardColors
[0] );
1919 CPPUNIT_ASSERT_EQUAL( COL_LIGHTBLUE
, rStandardColors
[1] );
1920 CPPUNIT_ASSERT_EQUAL( COL_LIGHTGREEN
, rStandardColors
[2] );
1921 CPPUNIT_ASSERT_EQUAL( COL_LIGHTCYAN
, rStandardColors
[3] );
1922 CPPUNIT_ASSERT_EQUAL( COL_LIGHTRED
, rStandardColors
[4] );
1923 CPPUNIT_ASSERT_EQUAL( COL_LIGHTMAGENTA
, rStandardColors
[5] );
1924 CPPUNIT_ASSERT_EQUAL( COL_BROWN
, rStandardColors
[6] );
1925 CPPUNIT_ASSERT_EQUAL( COL_GRAY
, rStandardColors
[7] );
1926 CPPUNIT_ASSERT_EQUAL( COL_YELLOW
, rStandardColors
[8] );
1927 CPPUNIT_ASSERT_EQUAL( COL_WHITE
, rStandardColors
[9] );
1930 void Test::testColorNamesConversion()
1932 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_GERMAN
);
1933 const NfKeywordTable
& rEnglishKeywords
= SvNumberFormatter::GetEnglishKeywords();
1934 const NfKeywordTable
& rKeywords
= aFormatter
.GetKeywords(0);
1936 // Holding a reference to the NfKeywordTable doesn't help if we switch
1937 // locales internally, so copy the relevant parts in advance.
1938 std::vector
<OUString
> aGermanKeywords(NF_KEYWORD_ENTRIES_COUNT
);
1939 for (size_t i
= NF_KEY_COLOR
; i
<= NF_KEY_WHITE
; ++i
)
1940 aGermanKeywords
[i
] = rKeywords
[i
];
1942 // Check that we actually have German and English keywords.
1943 CPPUNIT_ASSERT_EQUAL( u
"FARBE"_ustr
, aGermanKeywords
[NF_KEY_COLOR
]);
1944 CPPUNIT_ASSERT_EQUAL( u
"COLOR"_ustr
, rEnglishKeywords
[NF_KEY_COLOR
]);
1946 // Test each color conversion.
1947 // [FARBE1] -> [COLOR1] can't be tested because we have no color table link
1948 // set, so the scanner returns nCheckPos error.
1949 sal_Int32 nCheckPos
;
1950 SvNumFormatType nType
;
1952 OUString aFormatCode
;
1954 for (size_t i
= NF_KEY_BLACK
; i
<= NF_KEY_WHITE
; ++i
)
1956 aFormatCode
= "[" + aGermanKeywords
[i
] + "]0";
1957 aFormatter
.PutandConvertEntry( aFormatCode
, nCheckPos
, nType
, nKey
, LANGUAGE_GERMAN
, LANGUAGE_ENGLISH_US
, false);
1958 CPPUNIT_ASSERT_EQUAL_MESSAGE("CheckPos should be 0.", sal_Int32(0), nCheckPos
);
1959 CPPUNIT_ASSERT_EQUAL_MESSAGE("Type should be NUMBER.", SvNumFormatType::NUMBER
, nType
);
1960 CPPUNIT_ASSERT_EQUAL( OUString("[" + rEnglishKeywords
[i
] + "]0"), aFormatCode
);
1964 void Test::testExcelExportFormats()
1966 // Create a formatter with "system" locale other than the specific formats'
1967 // locale, and different from the en-US export locale.
1968 SvNumberFormatter
aFormatter( m_xContext
, LANGUAGE_ENGLISH_UK
);
1971 sal_Int32 nCheckPos
;
1972 SvNumFormatType eType
;
1973 sal_uInt32 nKey1
, nKey2
;
1976 aFormatter
.PutandConvertEntry( aCode
, nCheckPos
, eType
, nKey1
,
1977 LANGUAGE_ENGLISH_US
, LANGUAGE_ENGLISH_SAFRICA
, false);
1978 CPPUNIT_ASSERT_EQUAL_MESSAGE("CheckPos should be 0.", sal_Int32(0), nCheckPos
);
1979 CPPUNIT_ASSERT_MESSAGE("Key should be greater than system locale's keys.",
1980 nKey1
> SV_COUNTRY_LANGUAGE_OFFSET
);
1982 aCode
= "[$R-1C09] #,##0.0;[$R-1C09]-#,##0.0";
1983 aFormatter
.PutandConvertEntry( aCode
, nCheckPos
, eType
, nKey2
,
1984 LANGUAGE_ENGLISH_US
, LANGUAGE_ENGLISH_SAFRICA
, false);
1985 CPPUNIT_ASSERT_EQUAL_MESSAGE("CheckPos should be 0.", sal_Int32(0), nCheckPos
);
1986 CPPUNIT_ASSERT_MESSAGE("Key should be greater than system locale's keys.",
1987 nKey2
> SV_COUNTRY_LANGUAGE_OFFSET
);
1989 // The export formatter.
1990 SvNumberFormatter
aTempFormatter( m_xContext
, LANGUAGE_ENGLISH_US
);
1991 NfKeywordTable aKeywords
;
1992 aTempFormatter
.FillKeywordTableForExcel( aKeywords
);
1994 aCode
= aFormatter
.GetFormatStringForExcel( nKey1
, aKeywords
, aTempFormatter
);
1995 // Test that LCID is prepended.
1996 CPPUNIT_ASSERT_EQUAL( u
"[$-1C09]00.00"_ustr
, aCode
);
1998 aCode
= aFormatter
.GetFormatStringForExcel( nKey2
, aKeywords
, aTempFormatter
);
1999 // Test that LCID is not prepended. Note that literal characters are escaped.
2000 CPPUNIT_ASSERT_EQUAL( u
"[$R-1C09]\\ #,##0.0;[$R-1C09]\\-#,##0.0"_ustr
, aCode
);
2003 CPPUNIT_TEST_FIXTURE(Test
, testLanguageNone
)
2005 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_ENGLISH_US
);
2006 NfKeywordTable keywords
;
2007 aFormatter
.FillKeywordTableForExcel(keywords
);
2008 OUString
code(u
"TT.MM.JJJJ"_ustr
);
2009 sal_uInt32 nKey
= aFormatter
.GetEntryKey(code
, LANGUAGE_GERMAN
);
2010 CPPUNIT_ASSERT(nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
2011 SvNumberformat
const*const pFormat
= aFormatter
.GetEntry(nKey
);
2012 LocaleDataWrapper
ldw(m_xContext
, LanguageTag(pFormat
->GetLanguage()));
2013 CPPUNIT_ASSERT_EQUAL(u
"dd.mm.yyyy"_ustr
, pFormat
->GetMappedFormatstring(keywords
, ldw
));
2016 CPPUNIT_TEST_FIXTURE(Test
, testTdf160306
)
2018 // Check some cases, where the output of ROUND and of number formatter differed
2019 SvNumberFormatter
aFormatter(m_xContext
, LANGUAGE_ENGLISH_US
);
2020 sal_uInt32 format
= aFormatter
.GetEntryKey(u
"0.00", LANGUAGE_ENGLISH_US
);
2021 CPPUNIT_ASSERT(format
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
2024 aFormatter
.GetOutputString(2697.0649999999996, format
, output
, &color
);
2025 // Without the fix in place, this would fail with
2026 // - Expected: 2697.07
2027 // - Actual : 2697.06
2028 CPPUNIT_ASSERT_EQUAL(u
"2697.07"_ustr
, output
);
2029 aFormatter
.GetOutputString(57.374999999999993, format
, output
, &color
);
2030 // Without the fix in place, this would fail with
2031 // - Expected: 57.38
2033 CPPUNIT_ASSERT_EQUAL(u
"57.38"_ustr
, output
);
2036 CPPUNIT_TEST_SUITE_REGISTRATION(Test
);
2040 CPPUNIT_PLUGIN_IMPLEMENT();
2042 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */