From f2e4031b0cae25ccfe06ed3b99bae02131926d3f Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Sun, 25 May 2003 07:12:19 +0000 Subject: [PATCH] ICU-2436 Japanese Calendar implementation, other fixes (multi calendar) X-SVN-Rev: 12105 --- icu4c/source/data/locales/ja.txt | 253 ++++++++++ .../source/data/locales/ja_JP_TRADITIONAL.txt | 14 + icu4c/source/data/locales/resfiles.mk | 2 +- icu4c/source/data/locales/root.txt | 27 ++ icu4c/source/i18n/buddhcal.cpp | 12 +- icu4c/source/i18n/buddhcal.h | 3 +- icu4c/source/i18n/calendar.cpp | 85 ++-- icu4c/source/i18n/gregocal.cpp | 95 +++- icu4c/source/i18n/japancal.cpp | 455 +++++++++++++++++- icu4c/source/i18n/japancal.h | 85 +++- icu4c/source/i18n/smpdtfmt.cpp | 142 ++---- icu4c/source/i18n/unicode/calendar.h | 21 +- icu4c/source/i18n/unicode/dtfmtsym.h | 25 +- icu4c/source/i18n/unicode/gregocal.h | 85 +++- icu4c/source/test/intltest/incaltst.cpp | 168 +++++-- icu4c/source/test/intltest/incaltst.h | 10 +- 16 files changed, 1265 insertions(+), 217 deletions(-) create mode 100644 icu4c/source/data/locales/ja_JP_TRADITIONAL.txt diff --git a/icu4c/source/data/locales/ja.txt b/icu4c/source/data/locales/ja.txt index c9a4634cb3a..26d1de2d52e 100644 --- a/icu4c/source/data/locales/ja.txt +++ b/icu4c/source/data/locales/ja.txt @@ -2543,4 +2543,257 @@ ja { ZAR { "ZAR", "\u30E9\u30F3\u30C9" } // Rand ZWD { "ZWD", "\u30B8\u30F3\u30D0\u30D6\u30A8 \u30C9\u30EB" } // Zimbabwe Dollar } + + // (ICU 2.6) International Calendar Data. Note, THE FORMAT OF THIS DATA WILL CHANGE IN FUTURE RELEASES. + Eras_japanese { + "\u5927\u5316", // 645 Taika + "\u767D\u96C9", // 650 Hakuchi + "\u767D\u9CEF", // 672 Hakuho + "\u6731\u9CE5", // 686 Shucho + "\u5927\u5B9D", // 701 Taiho + "\u6176\u96F2", // 704 Keiun + "\u548C\u9285", // 708 Wado + "\u970A\u4E80", // 715 Reiki + "\u990A\u8001", // 717 Yoro + "\u795E\u4E80", // 724 Jinki + "\u5929\u5E73", // 729 Tempyo + "\u5929\u5E73\u611F\u5B9D", // 749 Tempyo-kampo + "\u5929\u5E73\u52DD\u5B9D", // 749 Tempyo-shoho + "\u5929\u5E73\u5B9D\u5B57", // 757 Tempyo-hoji + "\u5929\u5E73\u795E\u8B77", // 765 Tempho-jingo + "\u795E\u8B77\u666F\u96F2", // 767 Jingo-keiun + "\u5B9D\u4E80", // 770 Hoki + "\u5929\u5FDC", // 781 Ten-o + "\u5EF6\u66A6", // 782 Enryaku + "\u5927\u540C", // 806 Daido + "\u5F18\u4EC1", // 810 Konin + "\u5929\u9577", // 824 Tencho + "\u627F\u548C", // 834 Showa + "\u5609\u7965", // 848 Kajo + "\u4EC1\u5BFF", // 851 Ninju + "\u6589\u8861", // 854 Saiko + "\u5929\u5B89", // 857 Tennan + "\u8C9E\u89B3", // 859 Jogan + "\u5143\u6176", // 877 Genkei + "\u4EC1\u548C", // 885 Ninna + "\u5BDB\u5E73", // 889 Kampyo + "\u660C\u6CF0", // 898 Shotai + "\u5EF6\u559C", // 901 Engi + "\u5EF6\u9577", // 923 Encho + "\u627F\u5E73", // 931 Shohei + "\u5929\u6176", // 938 Tengyo + "\u5929\u66A6", // 947 Tenryaku + "\u5929\u5FB3", // 957 Tentoku + "\u5FDC\u548C", // 961 Owa + "\u5EB7\u4FDD", // 964 Koho + "\u5B89\u548C", // 968 Anna + "\u5929\u7984", // 970 Tenroku + "\u5929\u5EF6", // 973 Ten-en + "\u8C9E\u5143", // 976 Jogen + "\u5929\u5143", // 978 Tengen + "\u6C38\u89B3", // 983 Eikan + "\u5BDB\u548C", // 985 Kanna + "\u6C38\u5EF6", // 987 Ei-en + "\u6C38\u795A", // 989 Eiso + "\u6B63\u66A6", // 990 Shoryaku + "\u9577\u5FB3", // 995 Chotoku + "\u9577\u4FDD", // 999 Choho + "\u5BDB\u5F18", // 1004 Kanko + "\u9577\u548C", // 1012 Chowa + "\u5BDB\u4EC1", // 1017 Kannin + "\u6CBB\u5B89", // 1021 Jian + "\u4E07\u5BFF", // 1024 Manju + "\u9577\u5143", // 1028 Chogen + "\u9577\u66A6", // 1037 Choryaku + "\u9577\u4E45", // 1040 Chokyu + "\u5BDB\u5FB3", // 1044 Kantoku + "\u6C38\u627F", // 1046 Eisho + "\u5929\u559C", // 1053 Tengi + "\u5EB7\u5E73", // 1058 Kohei + "\u6CBB\u66A6", // 1065 Jiryaku + "\u5EF6\u4E45", // 1069 Enkyu + "\u627F\u4FDD", // 1074 Shoho + "\u627F\u66A6", // 1077 Shoryaku + "\u6C38\u4FDD", // 1081 Eiho + "\u5FDC\u5FB3", // 1084 Otoku + "\u5BDB\u6CBB", // 1087 Kanji + "\u5609\u4FDD", // 1094 Kaho + "\u6C38\u9577", // 1096 Eicho + "\u627F\u5FB3", // 1097 Shotoku + "\u5EB7\u548C", // 1099 Kowa + "\u9577\u6CBB", // 1104 Choji + "\u5609\u627F", // 1106 Kasho + "\u5929\u4EC1", // 1108 Tennin + "\u5929\u6C38", // 1110 Ten-ei + "\u6C38\u4E45", // 1113 Eikyu + "\u5143\u6C38", // 1118 Gen-ei + "\u4FDD\u5B89", // 1120 Hoan + "\u5929\u6CBB", // 1124 Tenji + "\u5927\u6CBB", // 1126 Daiji + "\u5929\u627F", // 1131 Tensho + "\u9577\u627F", // 1132 Chosho + "\u4FDD\u5EF6", // 1135 Hoen + "\u6C38\u6CBB", // 1141 Eiji + "\u5EB7\u6CBB", // 1142 Koji + "\u5929\u990A", // 1144 Tenyo + "\u4E45\u5B89", // 1145 Kyuan + "\u4EC1\u5E73", // 1151 Ninpei + "\u4E45\u5BFF", // 1154 Kyuju + "\u4FDD\u5143", // 1156 Hogen + "\u5E73\u6CBB", // 1159 Heiji + "\u6C38\u66A6", // 1160 Eiryaku + "\u5FDC\u4FDD", // 1161 Oho + "\u9577\u5BDB", // 1163 Chokan + "\u6C38\u4E07", // 1165 Eiman + "\u4EC1\u5B89", // 1166 Nin-an + "\u5609\u5FDC", // 1169 Kao + "\u627F\u5B89", // 1171 Shoan + "\u5B89\u5143", // 1175 Angen + "\u6CBB\u627F", // 1177 Jisho + "\u990A\u548C", // 1181 Yowa + "\u5BFF\u6C38", // 1182 Juei + "\u5143\u66A6", // 1184 Genryuku + "\u6587\u6CBB", // 1185 Bunji + "\u5EFA\u4E45", // 1190 Kenkyu + "\u6B63\u6CBB", // 1199 Shoji + "\u5EFA\u4EC1", // 1201 Kennin + "\u5143\u4E45", // 1204 Genkyu + "\u5EFA\u6C38", // 1206 Ken-ei + "\u627F\u5143", // 1207 Shogen + "\u5EFA\u66A6", // 1211 Kenryaku + "\u5EFA\u4FDD", // 1213 Kenpo + "\u627F\u4E45", // 1219 Shokyu + "\u8C9E\u5FDC", // 1222 Joo + "\u5143\u4EC1", // 1224 Gennin + "\u5609\u7984", // 1225 Karoku + "\u5B89\u8C9E", // 1227 Antei + "\u5BDB\u559C", // 1229 Kanki + "\u8C9E\u6C38", // 1232 Joei + "\u5929\u798F", // 1233 Tempuku + "\u6587\u66A6", // 1234 Bunryaku + "\u5609\u798E", // 1235 Katei + "\u66A6\u4EC1", // 1238 Ryakunin + "\u5EF6\u5FDC", // 1239 En-o + "\u4EC1\u6CBB", // 1240 Ninji + "\u5BDB\u5143", // 1243 Kangen + "\u5B9D\u6CBB", // 1247 Hoji + "\u5EFA\u9577", // 1249 Kencho + "\u5EB7\u5143", // 1256 Kogen + "\u6B63\u5609", // 1257 Shoka + "\u6B63\u5143", // 1259 Shogen + "\u6587\u5FDC", // 1260 Bun-o + "\u5F18\u9577", // 1261 Kocho + "\u6587\u6C38", // 1264 Bun-ei + "\u5EFA\u6CBB", // 1275 Kenji + "\u5F18\u5B89", // 1278 Koan + "\u6B63\u5FDC", // 1288 Shoo + "\u6C38\u4EC1", // 1293 Einin + "\u6B63\u5B89", // 1299 Shoan + "\u4E7E\u5143", // 1302 Kengen + "\u5609\u5143", // 1303 Kagen + "\u5FB3\u6CBB", // 1306 Tokuji + "\u5EF6\u6176", // 1308 Enkei + "\u5FDC\u9577", // 1311 Ocho + "\u6B63\u548C", // 1312 Showa + "\u6587\u4FDD", // 1317 Bunpo + "\u5143\u5FDC", // 1319 Geno + "\u5143\u4EA8", // 1321 Genkyo + "\u6B63\u4E2D", // 1324 Shochu + "\u5609\u66A6", // 1326 Kareki + "\u5143\u5FB3", // 1329 Gentoku + "\u5143\u5F18", // 1331 Genko + "\u5EFA\u6B66", // 1334 Kemmu + "\u5EF6\u5143", // 1336 Engen + "\u8208\u56FD", // 1340 Kokoku + "\u6B63\u5E73", // 1346 Shohei + "\u5EFA\u5FB3", // 1370 Kentoku + "\u6587\u4E2D", // 1372 Bunchu + "\u5929\u6388", // 1375 Tenju + "\u5F18\u548C", // 1381 Kowa + "\u5143\u4E2D", // 1384 Genchu + "\u81F3\u5FB3", // 1384 Meitoku + "\u5EB7\u66A6", // 1379 Koryaku + "\u5609\u6176", // 1387 Kakei + "\u5EB7\u5FDC", // 1389 Koo + "\u660E\u5FB3", // 1390 Meitoku + "\u5FDC\u6C38", // 1394 Oei + "\u6B63\u9577", // 1428 Shocho + "\u6C38\u4EAB", // 1429 Eikyo + "\u5609\u5409", // 1441 Kakitsu + "\u6587\u5B89", // 1444 Bun-an + "\u5B9D\u5FB3", // 1449 Hotoku + "\u4EAB\u5FB3", // 1452 Kyotoku + "\u5EB7\u6B63", // 1455 Kosho + "\u9577\u7984", // 1457 Choroku + "\u5BDB\u6B63", // 1460 Kansho + "\u6587\u6B63", // 1466 Bunsho + "\u5FDC\u4EC1", // 1467 Onin + "\u6587\u660E", // 1469 Bunmei + "\u9577\u4EAB", // 1487 Chokyo + "\u5EF6\u5FB3", // 1489 Entoku + "\u660E\u5FDC", // 1492 Meio + "\u6587\u4E80", // 1501 Bunki + "\u6C38\u6B63", // 1504 Eisho + "\u5927\u6C38", // 1521 Taiei + "\u4EAB\u7984", // 1528 Kyoroku + "\u5929\u6587", // 1532 Tenmon + "\u5F18\u6CBB", // 1555 Koji + "\u6C38\u7984", // 1558 Eiroku + "\u5143\u4E80", // 1570 Genki + "\u5929\u6B63", // 1573 Tensho + "\u6587\u7984", // 1592 Bunroku + "\u6176\u9577", // 1596 Keicho + "\u5143\u548C", // 1615 Genwa + "\u5BDB\u6C38", // 1624 Kan-ei + "\u6B63\u4FDD", // 1644 Shoho + "\u6176\u5B89", // 1648 Keian + "\u627F\u5FDC", // 1652 Shoo + "\u660E\u66A6", // 1655 Meiryaku + "\u4E07\u6CBB", // 1658 Manji + "\u5BDB\u6587", // 1661 Kanbun + "\u5EF6\u5B9D", // 1673 Enpo + "\u5929\u548C", // 1681 Tenwa + "\u8C9E\u4EAB", // 1684 Jokyo + "\u5143\u7984", // 1688 Genroku + "\u5B9D\u6C38", // 1704 Hoei + "\u6B63\u5FB3", // 1711 Shotoku + "\u4EAB\u4FDD", // 1716 Kyoho + "\u5143\u6587", // 1736 Genbun + "\u5BDB\u4FDD", // 1741 Kanpo + "\u5EF6\u4EAB", // 1744 Enkyo + "\u5BDB\u5EF6", // 1748 Kan-en + "\u5B9D\u66A6", // 1751 Horyaku + "\u660E\u548C", // 1764 Meiwa + "\u5B89\u6C38", // 1772 An-ei + "\u5929\u660E", // 1781 Tenmei + "\u5BDB\u653F", // 1789 Kansei + "\u4EAB\u548C", // 1801 Kyowa + "\u6587\u5316", // 1804 Bunka + "\u6587\u653F", // 1818 Bunsei + "\u5929\u4FDD", // 1830 Tenpo + "\u5F18\u5316", // 1844 Koka + "\u5609\u6C38", // 1848 Kaei + "\u5B89\u653F", // 1854 Ansei + "\u4E07\u5EF6", // 1860 Man-en + "\u6587\u4E45", // 1861 Bunkyu + "\u5143\u6CBB", // 1864 Genji + "\u6176\u5FDC", // 1865 Keio + "\u660E\u6CBB", // 1868 Meiji + "\u5927\u6B63", // 1912 Taisho + "\u662D\u548C", // 1926 Showa + "\u5E73\u6210" // 1989 Heisei + } + + DateTimePatterns_japanese { + "H'\u6642'mm'\u5206'ss'\u79D2'z", + "H:mm:ss:z", + "H:mm:ss", + "H:mm", + "yyyy G'\u5E74'M'\u6708'd'\u65E5'", + "yyyy G/MM/dd", + "yyyy G/MM/dd", + "yyyy G/MM/dd", + "{1} {0}", + } + } diff --git a/icu4c/source/data/locales/ja_JP_TRADITIONAL.txt b/icu4c/source/data/locales/ja_JP_TRADITIONAL.txt new file mode 100644 index 00000000000..d4fcea29cd0 --- /dev/null +++ b/icu4c/source/data/locales/ja_JP_TRADITIONAL.txt @@ -0,0 +1,14 @@ +// *************************************************************************** +// * +// * Copyright (C) 1997-2003, International Business Machines +// * Corporation and others. All Rights Reserved. +// * +// *************************************************************************** + + +ja_JP_TRADITIONAL { + Version { "1.0" } + // International Calendars Data. + // NOTE (ICU 2.6) - the format of this data WILL CHANGE in future releases. + DefaultCalendar { "japanese" } +} diff --git a/icu4c/source/data/locales/resfiles.mk b/icu4c/source/data/locales/resfiles.mk index f9acebf484c..ca9826b0f7b 100644 --- a/icu4c/source/data/locales/resfiles.mk +++ b/icu4c/source/data/locales/resfiles.mk @@ -76,7 +76,7 @@ hy.txt hy_AM.txt hy_AM_REVISED.txt\ id.txt id_ID.txt\ is.txt is_IS.txt\ it.txt it_CH.txt it_IT.txt it_IT_PREEURO.txt\ -ja.txt ja_JP.txt\ +ja.txt ja_JP.txt ja_JP_TRADITIONAL.txt\ kl.txt kl_GL.txt\ ko.txt ko_KR.txt\ kok.txt kok_IN.txt\ diff --git a/icu4c/source/data/locales/root.txt b/icu4c/source/data/locales/root.txt index 9d9c48101d8..f8e89d55072 100644 --- a/icu4c/source/data/locales/root.txt +++ b/icu4c/source/data/locales/root.txt @@ -8,6 +8,8 @@ // 11/17/99 aliu Added support for transliterators. // 01/15/2002 grhoten Synchronized the language and contry codes with ISO standards +// *** Note: do NOT translate or modify (customize) this root locale. +// Instead, put translations in sub locales. root { Version { "3.2" } @@ -1606,9 +1608,34 @@ root { "Heisei", // 1989 } + DateTimePatterns_japanese:array { + "h:mm:ss a z", // full time pattern + "h:mm:ss a z", // long time pattern + "h:mm:ss a", // medium time pattern + "h:mm a", // short time pattern + "EEEE, MMMM d, y G", // full date pattern + "MMMM d, y G", // long date pattern + "MMM d, y G", // medium date pattern + "M/d/yy", // short date pattern + "{1} {0}" // date-time pattern + } + // Buddhist calendar data Eras_buddhist:array { "BE" // Buddhist Era = 543 BC Gregorian } + + DateTimePatterns_buddhist { // shorten year, use Era + "h:mm:ss a z", + "h:mm:ss a z", + "h:mm:ss a", + "h:mm a", + "EEEE, MMMM d, y G", + "MMMM d, y G", + "MMM d, y G", + "M/d/y", + "{1} {0}", + } + } diff --git a/icu4c/source/i18n/buddhcal.cpp b/icu4c/source/i18n/buddhcal.cpp index f44e6c574cc..bb084f70caa 100644 --- a/icu4c/source/i18n/buddhcal.cpp +++ b/icu4c/source/i18n/buddhcal.cpp @@ -27,6 +27,8 @@ static const int32_t kMaxEra = 0; // only 1 era static const int32_t kBuddhistEraStart = -543; // 544 BC (Gregorian) +static const int32_t kGregorianEpoch = 1970; + BuddhistCalendar::BuddhistCalendar(const Locale& aLocale, UErrorCode& success) : GregorianCalendar(aLocale, success) { @@ -108,15 +110,15 @@ int32_t BuddhistCalendar::internalGetEra() const } int32_t -BuddhistCalendar::getGregorianYear(UErrorCode &status) +BuddhistCalendar::getGregorianYear(UErrorCode &status) const { - int32_t year = (fStamp[UCAL_YEAR] != kUnset) ? internalGet(UCAL_YEAR) : 1970+kBuddhistEraStart; + int32_t year = (fStamp[UCAL_YEAR] != kUnset) ? internalGet(UCAL_YEAR) : kGregorianEpoch+kBuddhistEraStart; int32_t era = BE; if (fStamp[UCAL_ERA] != kUnset) { era = internalGet(UCAL_ERA); if (era != BE) { status = U_ILLEGAL_ARGUMENT_ERROR; - return 1970 + kBuddhistEraStart; + return kGregorianEpoch + kBuddhistEraStart; } } return year + kBuddhistEraStart; @@ -144,6 +146,10 @@ void BuddhistCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& stat internalSet(UCAL_YEAR, year); } +UBool BuddhistCalendar::haveDefaultCentury() const +{ + return FALSE; +} U_NAMESPACE_END diff --git a/icu4c/source/i18n/buddhcal.h b/icu4c/source/i18n/buddhcal.h index 7c2ea69a8e6..67f3e51c2ae 100644 --- a/icu4c/source/i18n/buddhcal.h +++ b/icu4c/source/i18n/buddhcal.h @@ -137,11 +137,12 @@ private: protected: virtual int32_t monthLength(int32_t month) const; virtual int32_t monthLength(int32_t month, int32_t year) const; - int32_t getGregorianYear(UErrorCode& status); + int32_t getGregorianYear(UErrorCode& status) const; int32_t getMaximum(UCalendarDateFields field) const; int32_t getLeastMaximum(UCalendarDateFields field) const; virtual int32_t internalGetEra() const; virtual void timeToFields(UDate theTime, UBool quick, UErrorCode& status); + virtual UBool haveDefaultCentury() const; }; inline UClassID diff --git a/icu4c/source/i18n/calendar.cpp b/icu4c/source/i18n/calendar.cpp index 487cf9137f2..7dff14f4f47 100644 --- a/icu4c/source/i18n/calendar.cpp +++ b/icu4c/source/i18n/calendar.cpp @@ -36,6 +36,7 @@ #include "cpputils.h" #include "iculserv.h" #include "ucln_in.h" +#include "cstring.h" U_NAMESPACE_BEGIN @@ -51,10 +52,6 @@ U_NAMESPACE_BEGIN #include #endif -// do NOT force a 'getService' (and thus, registration). -// Define this if you do NOT want automatic registration. -//#define U_DEBUG_CALSVC_NO_GETSVC 1 - static ICULocaleService* gService = NULL; // ------------------------------------- @@ -113,11 +110,11 @@ protected: fflush(stderr); #endif - if(!fType || !*fType || !strcmp(fType,"gregorian")) { // Gregorian (default) + if(!fType || !*fType || !uprv_strcmp(fType,"gregorian")) { // Gregorian (default) return new GregorianCalendar(canLoc, status); - } else if(!strcmp(fType, "japanese")) { + } else if(!uprv_strcmp(fType, "japanese")) { return new JapaneseCalendar(canLoc, status); - } else if(!strcmp(fType, "buddhist")) { + } else if(!uprv_strcmp(fType, "buddhist")) { return new BuddhistCalendar(canLoc, status); } else { status = U_UNSUPPORTED_ERROR; @@ -169,9 +166,12 @@ protected: int32_t len = 0; - const UChar *defCal = ures_getStringByKey(rb, Calendar::kDefaultCalendar, &len, &status); + UnicodeString myString = ures_getUnicodeStringByKey(rb, Calendar::kDefaultCalendar, &status); + #ifdef U_DEBUG_CALSVC - fprintf(stderr, "... get string(%d) -> %s\n", len, u_errorName(status)); + UErrorCode debugStatus = U_ZERO_ERROR; + const UChar *defCal = ures_getStringByKey(rb, Calendar::kDefaultCalendar, &len, &debugStatus); + fprintf(stderr, "... get string(%d) -> %s\n", len, u_errorName(debugStatus)); #endif ures_close(rb); @@ -180,18 +180,20 @@ protected: return NULL; } - char defCalStr[200]; - if(len > 199) { - len = 199; - } - u_UCharsToChars(defCal, defCalStr, len); - defCalStr[len]=0; #ifdef U_DEBUG_CALSVC - fprintf(stderr, "DefaultCalendarFactory: looked up %s, got DefaultCalendar= %s\n", (const char*)loc.getName(), defCalStr); + { + char defCalStr[200]; + if(len > 199) { + len = 199; + } + u_UCharsToChars(defCal, defCalStr, len); + defCalStr[len]=0; + fprintf(stderr, "DefaultCalendarFactory: looked up %s, got DefaultCalendar= %s\n", (const char*)loc.getName(), defCalStr); + } #endif - return new UnicodeString(defCalStr,""); // Return indirection string + return myString.clone(); } }; @@ -483,12 +485,14 @@ Calendar::createInstance(const Locale& aLocale, UErrorCode& success) Calendar* Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& success) { - // to do - put back non-service code. UObject* u = getService()->get(aLocale, LocaleKey::KIND_ANY, success); Calendar* c = NULL; - + if(U_FAILURE(success) || !u) { delete zone; + if(U_SUCCESS(success)) { // Propagate some kind of err + success = U_INTERNAL_PROGRAM_ERROR; + } return NULL; } @@ -496,11 +500,10 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ // It's a unicode string telling us what type of calendar to load ("gregorian", etc) char tmp[200]; const UnicodeString& str = *(UnicodeString*)u; - // Extract a char* out of it.. int32_t len = str.length(); - if(len > 198) { - len = 198; + if(len > sizeof(tmp)-1) { + len = sizeof(tmp)-1; } str.extract(0,len,tmp); tmp[len]=0; @@ -509,24 +512,27 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ // fprintf(stderr, "createInstance(%s) told to look at %s..\n", (const char*)aLocale.getName(), tmp); #endif - // Create a Locale - Locale l(tmp,""); + // Create a Locale over this string + Locale l(tmp); delete u; u = NULL; c = (Calendar*)getService()->get(l, LocaleKey::KIND_ANY, success); + if(U_FAILURE(success) || !c) { delete zone; - //delete u; + if(U_SUCCESS(success)) { + success = U_INTERNAL_PROGRAM_ERROR; // Propagate some err + } return NULL; } if(c->getDynamicClassID() == UnicodeString::getStaticClassID()) { - // recursed! + // recursed! Second lookup returned a UnicodeString. + // Perhaps DefaultCalendar{} was set to another locale. success = U_MISSING_RESOURCE_ERROR; // requested a calendar type which could NOT be found. delete c; - //delete u; delete zone; return NULL; } @@ -535,7 +541,7 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ #endif c->setWeekCountData(aLocale, success); // set the correct locale (this was an indirected calendar) } else { - // calendar was returned + // a calendar was returned - we assume the factory did the right thing. c = (Calendar*)u; } c->adoptTimeZone(zone); // Set the correct time zone @@ -547,26 +553,11 @@ Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& succ Calendar* Calendar::createInstance(const TimeZone& zone, const Locale& aLocale, UErrorCode& success) { -#ifndef U_DEBUG_CALSVC_NO_GETSVC - getService(); -#endif - if(gService != NULL) { - Calendar* c = createInstance(aLocale, success); - if(U_SUCCESS(success) && c) { - c->setTimeZone(zone); - } - return c; - } else { - // non service code - Calendar* c = new GregorianCalendar(zone, aLocale, success); - /* test for NULL */ - if (c == 0) { - success = U_MEMORY_ALLOCATION_ERROR; - return 0; - } - if (U_FAILURE(success)) { delete c; c = 0; } - return c; + Calendar* c = createInstance(aLocale, success); + if(U_SUCCESS(success) && c) { + c->setTimeZone(zone); } + return c; } // ------------------------------------- diff --git a/icu4c/source/i18n/gregocal.cpp b/icu4c/source/i18n/gregocal.cpp index 11ab3c71bd2..73100d774aa 100644 --- a/icu4c/source/i18n/gregocal.cpp +++ b/icu4c/source/i18n/gregocal.cpp @@ -38,10 +38,12 @@ */ #include "unicode/utypes.h" +#include #if !UCONFIG_NO_FORMATTING #include "unicode/gregocal.h" +#include "unicode/smpdtfmt.h" /* for the public field (!) SimpleDateFormat::fgSystemDefaultCentury */ // ***************************************************************************** // class GregorianCalendar @@ -780,7 +782,7 @@ GregorianCalendar::getEpochDay(UErrorCode& status) // ------------------------------------- int32_t -GregorianCalendar::getGregorianYear(UErrorCode &status) +GregorianCalendar::getGregorianYear(UErrorCode &status) const { int32_t year = (fStamp[UCAL_YEAR] != kUnset) ? internalGet(UCAL_YEAR) : kEpochYear; int32_t era = AD; @@ -1171,7 +1173,7 @@ GregorianCalendar::computeJulianDay(UBool isGregorian, int32_t year) // predominates. This set of computations must be done BEFORE // using the year, since the year value may be adjusted here. UBool useMonth = FALSE; - int32_t month = 0; + int32_t month = 0; // SRL getDefaultMonth ? if (bestStamp != kUnset && (bestStamp == monthStamp || bestStamp == domStamp || @@ -1180,7 +1182,7 @@ GregorianCalendar::computeJulianDay(UBool isGregorian, int32_t year) useMonth = TRUE; // We have the month specified. Make it 0-based for the algorithm. - month = (monthStamp != kUnset) ? internalGet(UCAL_MONTH) - UCAL_JANUARY : 0; + month = (monthStamp != kUnset) ? internalGet(UCAL_MONTH) - UCAL_JANUARY : getDefaultMonthInYear(); // If the month is out of range, adjust it into range if (month < 0 || month > 11) { @@ -1205,7 +1207,7 @@ GregorianCalendar::computeJulianDay(UBool isGregorian, int32_t year) if (bestStamp == domStamp || bestStamp == monthStamp) { - date = (domStamp != kUnset) ? internalGet(UCAL_DATE) : 1; + date = (domStamp != kUnset) ? internalGet(UCAL_DATE) : getDefaultDayInMonth(month); } else { // assert(bestStamp == womStamp || bestStamp == dowimStamp) // Compute from day of week plus week number or from the day of @@ -1267,8 +1269,13 @@ GregorianCalendar::computeJulianDay(UBool isGregorian, int32_t year) UBool doCutoverAdjustment = TRUE; if (bestStamp == kUnset) { - doy = 1; // Advance to January 1 - doCutoverAdjustment = FALSE; + //doy = 1; + // For Gregorian the following will always be 1: kNumDays[UCAL_JANUARY] + 1 + int32_t defMonth = getDefaultMonthInYear(); // 0 for gregorian + int32_t defDay = getDefaultDayInMonth(month); // 1 for gregorian + + doy = defDay + (isLeap ? kLeapNumDays[defMonth] : kNumDays[defMonth]); + doCutoverAdjustment = FALSE; } else if (bestStamp == doyStamp) { doy = internalGet(UCAL_DAY_OF_YEAR); @@ -2075,6 +2082,82 @@ GregorianCalendar::getType() const { return "gregorian"; } +// ------ Default Century functions moved here from SimpleDateFormat + +// uncomment in 2.8 +//const UDate GregorianCalendar::fgSystemDefaultCentury = DBL_MIN; +const int32_t GregorianCalendar::fgSystemDefaultCenturyYear = -1; + +UDate GregorianCalendar::fgSystemDefaultCenturyStart = DBL_MIN; +int32_t GregorianCalendar::fgSystemDefaultCenturyStartYear = -1; + + +UBool GregorianCalendar::haveDefaultCentury() const +{ + return TRUE; +} + +UDate GregorianCalendar::defaultCenturyStart() const +{ + return internalGetDefaultCenturyStart(); +} + +int32_t GregorianCalendar::defaultCenturyStartYear() const +{ + return internalGetDefaultCenturyStartYear(); +} + +UDate +GregorianCalendar::internalGetDefaultCenturyStart() const +{ + // lazy-evaluate systemDefaultCenturyStart + if (fgSystemDefaultCenturyStart == SimpleDateFormat::fgSystemDefaultCentury) + initializeSystemDefaultCentury(); + + // use defaultCenturyStart unless it's the flag value; + // then use systemDefaultCenturyStart + + return fgSystemDefaultCenturyStart; +} + +int32_t +GregorianCalendar::internalGetDefaultCenturyStartYear() const +{ + // lazy-evaluate systemDefaultCenturyStartYear + if (fgSystemDefaultCenturyStart == SimpleDateFormat::fgSystemDefaultCentury) + initializeSystemDefaultCentury(); + + // use defaultCenturyStart unless it's the flag value; + // then use systemDefaultCenturyStartYear + + return fgSystemDefaultCenturyStartYear; +} + +void +GregorianCalendar::initializeSystemDefaultCentury() +{ + // initialize systemDefaultCentury and systemDefaultCenturyYear based + // on the current time. They'll be set to 80 years before + // the current time. + // No point in locking as it should be idempotent. + if (fgSystemDefaultCenturyStart == SimpleDateFormat::fgSystemDefaultCentury) + { + UErrorCode status = U_ZERO_ERROR; + Calendar *calendar = new GregorianCalendar(status); + if (calendar != NULL && U_SUCCESS(status)) + { + calendar->setTime(Calendar::getNow(), status); + calendar->add(UCAL_YEAR, -80, status); + fgSystemDefaultCenturyStart = calendar->getTime(status); + fgSystemDefaultCenturyStartYear = calendar->get(UCAL_YEAR, status); + delete calendar; + } + // We have no recourse upon failure unless we want to propagate the failure + // out. + } +} + + U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/japancal.cpp b/icu4c/source/i18n/japancal.cpp index 30742dd6594..7136b46c259 100644 --- a/icu4c/source/i18n/japancal.cpp +++ b/icu4c/source/i18n/japancal.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2003, International Business Machines Corporation and * +* Copyright (C) 2003, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -18,17 +18,269 @@ #include "japancal.h" #include "unicode/gregocal.h" +//#define U_DEBUG_JCAL + +#ifdef U_DEBUG_JCAL +#include +#endif U_NAMESPACE_BEGIN - const char JapaneseCalendar::fgClassID = 0; // Value is irrelevant +// Gregorian date of each emperor's ascension +// Years are AD, months are 1-based. +static const struct { + int16_t year; + int8_t month; + int8_t day; +} kEraInfo[] = { + // Year Month Day + { 645, 6, 19 }, // Taika 0 + { 650, 2, 15 }, // Hakuchi 1 + { 672, 1, 1 }, // Hakuho 2 + { 686, 7, 20 }, // Shucho 3 + { 701, 3, 21 }, // Taiho 4 + { 704, 5, 10 }, // Keiun 5 + { 708, 1, 11 }, // Wado 6 + { 715, 9, 2 }, // Reiki 7 + { 717, 11, 17 }, // Yoro 8 + { 724, 2, 4 }, // Jinki 9 + { 729, 8, 5 }, // Tempyo 10 + { 749, 4, 14 }, // Tempyo-kampo 11 + { 749, 7, 2 }, // Tempyo-shoho 12 + { 757, 8, 18 }, // Tempyo-hoji 13 + { 765, 1, 7 }, // Tempho-jingo 14 + { 767, 8, 16 }, // Jingo-keiun 15 + { 770, 10, 1 }, // Hoki 16 + { 781, 1, 1 }, // Ten-o 17 + { 782, 8, 19 }, // Enryaku 18 + { 806, 5, 18 }, // Daido 19 + { 810, 9, 19 }, // Konin 20 + { 824, 1, 5 }, // Tencho + { 834, 1, 3 }, // Showa + { 848, 6, 13 }, // Kajo + { 851, 4, 28 }, // Ninju + { 854, 11, 30 }, // Saiko + { 857, 2, 21 }, // Tennan + { 859, 4, 15 }, // Jogan + { 877, 4, 16 }, // Genkei + { 885, 2, 21 }, // Ninna + { 889, 4, 27 }, // Kampyo 30 + { 898, 4, 26 }, // Shotai + { 901, 7, 15 }, // Engi + { 923, 4, 11 }, // Encho + { 931, 4, 26 }, // Shohei + { 938, 5, 22 }, // Tengyo + { 947, 4, 22 }, // Tenryaku + { 957, 10, 27 }, // Tentoku + { 961, 2, 16 }, // Owa + { 964, 7, 10 }, // Koho + { 968, 8, 13 }, // Anna 40 + { 970, 3, 25 }, // Tenroku + { 973, 12, 20 }, // Ten-en + { 976, 7, 13 }, // Jogen + { 978, 11, 29 }, // Tengen + { 983, 4, 15 }, // Eikan + { 985, 4, 27 }, // Kanna + { 987, 4, 5 }, // Ei-en + { 989, 8, 8 }, // Eiso + { 990, 11, 7 }, // Shoryaku + { 995, 2, 22 }, // Chotoku 50 + { 999, 1, 13 }, // Choho + { 1004, 7, 20 }, // Kanko + { 1012, 12, 25 }, // Chowa + { 1017, 4, 23 }, // Kannin + { 1021, 2, 2 }, // Jian + { 1024, 7, 13 }, // Manju + { 1028, 7, 25 }, // Chogen + { 1037, 4, 21 }, // Choryaku + { 1040, 11, 10 }, // Chokyu + { 1044, 11, 24 }, // Kantoku 60 + { 1046, 4, 14 }, // Eisho + { 1053, 1, 11 }, // Tengi + { 1058, 8, 29 }, // Kohei + { 1065, 8, 2 }, // Jiryaku + { 1069, 4, 13 }, // Enkyu + { 1074, 8, 23 }, // Shoho + { 1077, 11, 17 }, // Shoryaku + { 1081, 2, 10 }, // Eiho + { 1084, 2, 7 }, // Otoku + { 1087, 4, 7 }, // Kanji 70 + { 1094, 12, 15 }, // Kaho + { 1096, 12, 17 }, // Eicho + { 1097, 11, 21 }, // Shotoku + { 1099, 8, 28 }, // Kowa + { 1104, 2, 10 }, // Choji + { 1106, 4, 9 }, // Kasho + { 1108, 8, 3 }, // Tennin + { 1110, 7, 13 }, // Ten-ei + { 1113, 7, 13 }, // Eikyu + { 1118, 4, 3 }, // Gen-ei 80 + { 1120, 4, 10 }, // Hoan + { 1124, 4, 3 }, // Tenji + { 1126, 1, 22 }, // Daiji + { 1131, 1, 29 }, // Tensho + { 1132, 8, 11 }, // Chosho + { 1135, 4, 27 }, // Hoen + { 1141, 7, 10 }, // Eiji + { 1142, 4, 28 }, // Koji + { 1144, 2, 23 }, // Tenyo + { 1145, 7, 22 }, // Kyuan 90 + { 1151, 1, 26 }, // Ninpei + { 1154, 10, 28 }, // Kyuju + { 1156, 4, 27 }, // Hogen + { 1159, 4, 20 }, // Heiji + { 1160, 1, 10 }, // Eiryaku + { 1161, 9, 4 }, // Oho + { 1163, 3, 29 }, // Chokan + { 1165, 6, 5 }, // Eiman + { 1166, 8, 27 }, // Nin-an + { 1169, 4, 8 }, // Kao 100 + { 1171, 4, 21 }, // Shoan + { 1175, 7, 28 }, // Angen + { 1177, 8, 4 }, // Jisho + { 1181, 7, 14 }, // Yowa + { 1182, 5, 27 }, // Juei + { 1184, 4, 16 }, // Genryuku + { 1185, 8, 14 }, // Bunji + { 1190, 4, 11 }, // Kenkyu + { 1199, 4, 27 }, // Shoji + { 1201, 2, 13 }, // Kennin 110 + { 1204, 2, 20 }, // Genkyu + { 1206, 4, 27 }, // Ken-ei + { 1207, 10, 25 }, // Shogen + { 1211, 3, 9 }, // Kenryaku + { 1213, 12, 6 }, // Kenpo + { 1219, 4, 12 }, // Shokyu + { 1222, 4, 13 }, // Joo + { 1224, 11, 20 }, // Gennin + { 1225, 4, 20 }, // Karoku + { 1227, 12, 10 }, // Antei 120 + { 1229, 3, 5 }, // Kanki + { 1232, 4, 2 }, // Joei + { 1233, 4, 15 }, // Tempuku + { 1234, 11, 5 }, // Bunryaku + { 1235, 9, 19 }, // Katei + { 1238, 11, 23 }, // Ryakunin + { 1239, 2, 7 }, // En-o + { 1240, 7, 16 }, // Ninji + { 1243, 2, 26 }, // Kangen + { 1247, 2, 28 }, // Hoji 130 + { 1249, 3, 18 }, // Kencho + { 1256, 10, 5 }, // Kogen + { 1257, 3, 14 }, // Shoka + { 1259, 3, 26 }, // Shogen + { 1260, 4, 13 }, // Bun-o + { 1261, 2, 20 }, // Kocho + { 1264, 2, 28 }, // Bun-ei + { 1275, 4, 25 }, // Kenji + { 1278, 2, 29 }, // Koan + { 1288, 4, 28 }, // Shoo 140 + { 1293, 8, 55 }, // Einin + { 1299, 4, 25 }, // Shoan + { 1302, 11, 21 }, // Kengen + { 1303, 8, 5 }, // Kagen + { 1306, 12, 14 }, // Tokuji + { 1308, 10, 9 }, // Enkei + { 1311, 4, 28 }, // Ocho + { 1312, 3, 20 }, // Showa + { 1317, 2, 3 }, // Bunpo + { 1319, 4, 28 }, // Geno 150 + { 1321, 2, 23 }, // Genkyo + { 1324, 12, 9 }, // Shochu + { 1326, 4, 26 }, // Kareki + { 1329, 8, 29 }, // Gentoku + { 1331, 8, 9 }, // Genko + { 1334, 1, 29 }, // Kemmu + { 1336, 2, 29 }, // Engen + { 1340, 4, 28 }, // Kokoku + { 1346, 12, 8 }, // Shohei + { 1370, 7, 24 }, // Kentoku 160 + { 1372, 4, 1 }, // Bunch\u0169 + { 1375, 5, 27 }, // Tenju + { 1381, 2, 10 }, // Kowa + { 1384, 4, 28 }, // Gench\u0169 + { 1384, 2, 27 }, // Meitoku + { 1379, 3, 22 }, // Koryaku + { 1387, 8, 23 }, // Kakei + { 1389, 2, 9 }, // Koo + { 1390, 3, 26 }, // Meitoku + { 1394, 7, 5 }, // Oei 170 + { 1428, 4, 27 }, // Shocho + { 1429, 9, 5 }, // Eikyo + { 1441, 2, 17 }, // Kakitsu + { 1444, 2, 5 }, // Bun-an + { 1449, 7, 28 }, // Hotoku + { 1452, 7, 25 }, // Kyotoku + { 1455, 7, 25 }, // Kosho + { 1457, 9, 28 }, // Choroku + { 1460, 12, 21 }, // Kansho + { 1466, 2, 28 }, // Bunsho 180 + { 1467, 3, 3 }, // Onin + { 1469, 4, 28 }, // Bunmei + { 1487, 7, 29 }, // Chokyo + { 1489, 8, 21 }, // Entoku + { 1492, 7, 19 }, // Meio + { 1501, 2, 29 }, // Bunki + { 1504, 2, 30 }, // Eisho + { 1521, 8, 23 }, // Taiei + { 1528, 8, 20 }, // Kyoroku + { 1532, 7, 29 }, // Tenmon 190 + { 1555, 10, 23 }, // Koji + { 1558, 2, 28 }, // Eiroku + { 1570, 4, 23 }, // Genki + { 1573, 7, 28 }, // Tensho + { 1592, 12, 8 }, // Bunroku + { 1596, 10, 27 }, // Keicho + { 1615, 7, 13 }, // Genwa + { 1624, 2, 30 }, // Kan-ei + { 1644, 12, 16 }, // Shoho + { 1648, 2, 15 }, // Keian 200 + { 1652, 9, 18 }, // Shoo + { 1655, 4, 13 }, // Meiryaku + { 1658, 7, 23 }, // Manji + { 1661, 4, 25 }, // Kanbun + { 1673, 9, 21 }, // Enpo + { 1681, 9, 29 }, // Tenwa + { 1684, 2, 21 }, // Jokyo + { 1688, 9, 30 }, // Genroku + { 1704, 3, 13 }, // Hoei + { 1711, 4, 25 }, // Shotoku 210 + { 1716, 6, 22 }, // Kyoho + { 1736, 4, 28 }, // Genbun + { 1741, 2, 27 }, // Kanpo + { 1744, 2, 21 }, // Enkyo + { 1748, 7, 12 }, // Kan-en + { 1751, 10, 27 }, // Horyaku + { 1764, 6, 2 }, // Meiwa + { 1772, 11, 16 }, // An-ei + { 1781, 4, 2 }, // Tenmei + { 1789, 1, 25 }, // Kansei 220 + { 1801, 2, 5 }, // Kyowa + { 1804, 2, 11 }, // Bunka + { 1818, 4, 22 }, // Bunsei + { 1830, 12, 10 }, // Tenpo + { 1844, 12, 2 }, // Koka + { 1848, 2, 28 }, // Kaei + { 1854, 11, 27 }, // Ansei + { 1860, 3, 18 }, // Man-en + { 1861, 2, 19 }, // Bunkyu + { 1864, 2, 20 }, // Genji 230 + { 1865, 4, 7 }, // Keio 231 + { 1868, 9, 8 }, // Meiji 232 + { 1912, 7, 30 }, // Taisho 233 + { 1926, 12, 25 }, // Showa 234 + { 1989, 1, 8 } // Heisei 235 + }; + +#define kEraCount (sizeof(kEraInfo)/sizeof(kEraInfo[0])) + +const uint32_t JapaneseCalendar::kCurrentEra = (kEraCount-1); JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success) : GregorianCalendar(aLocale, success) { - success = U_UNSUPPORTED_ERROR; // Just a stub for now. } JapaneseCalendar::~JapaneseCalendar() @@ -57,6 +309,203 @@ const char *JapaneseCalendar::getType() const } +int32_t +JapaneseCalendar::getMaximum(UCalendarDateFields field) const +{ + if(field == UCAL_ERA) { + return kCurrentEra; + } else { + return GregorianCalendar::getMaximum(field); + } +} + +int32_t +JapaneseCalendar::getLeastMaximum(UCalendarDateFields field) const +{ + if(field == UCAL_ERA) { + return kCurrentEra; + } else { + return GregorianCalendar::getLeastMaximum(field); + } +} + +int32_t +JapaneseCalendar::monthLength(int32_t month, int32_t year) const +{ + return GregorianCalendar::monthLength(month,year); +} + + +int32_t +JapaneseCalendar::monthLength(int32_t month) const +{ + int32_t year = internalGet(UCAL_YEAR); + // ignore era + return monthLength(month, year); +} + +int32_t JapaneseCalendar::getDefaultMonthInYear() const +{ + UErrorCode status = U_ZERO_ERROR; + int32_t era = internalGetEra(); + int32_t year = getGregorianYear(status); + // TODO do we assume we can trust 'era'? What if it is denormalized? + + int32_t month = GregorianCalendar::getDefaultMonthInYear(); + + // Find out if we are at the edge of an era + + if(year == kEraInfo[era].year) { + // Yes, we're in the first year of this era. + return kEraInfo[era].month; + } + + if(era < kCurrentEra) { + // if we're not in the current era, + // fail_here; + } + + return month; +} + +int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t month) const +{ + UErrorCode status = U_ZERO_ERROR; + int32_t era = internalGetEra(); + int32_t year = getGregorianYear(status); + int32_t day = GregorianCalendar::getDefaultDayInMonth(month); + + if(year == kEraInfo[era].year) { + if(month == kEraInfo[era].month) { + return kEraInfo[era].day; + } + } + + return day; +} + + +int32_t JapaneseCalendar::internalGetEra() const +{ + return isSet(UCAL_ERA) ? internalGet(UCAL_ERA) : kCurrentEra; +} + +int32_t +JapaneseCalendar::getGregorianYear(UErrorCode &status) const +{ + int32_t year = (fStamp[UCAL_YEAR] != kUnset) ? internalGet(UCAL_YEAR) : 0; + int32_t era = kCurrentEra; + if (fStamp[UCAL_ERA] != kUnset) { + era = internalGet(UCAL_ERA); + } + + if ((era<0)||(era>kCurrentEra)) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return 0 ; + } + return year + kEraInfo[era].year - 1; +} + +void JapaneseCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& status) +{ + GregorianCalendar::timeToFields(theTime, quick, status); + + // these are the gregorian era and year + int32_t era = internalGet(UCAL_ERA); + int32_t year = internalGet(UCAL_YEAR); + if(era == GregorianCalendar::BC) { + year = 1 - year; + } + + // grego [e+y] -> e+y + int32_t low = 0; + + // Short circuit for recent years. Most modern computations will + // occur in the current era and won't require the binary search. + // Note that if the year is == the current era year, then we use + // the binary search to handle the month/dom comparison. +#ifdef U_DEBUG_JCAL + fprintf(stderr, "== %d:%d \n", era, year); +#endif + + if (year > kEraInfo[kCurrentEra].year) { + low = kCurrentEra; +#ifdef U_DEBUG_JCAL + fprintf(stderr, " low=%d (special)\n", low); +#endif + } else { + // Binary search + int32_t high = kEraCount; + +#ifdef U_DEBUG_JCAL + fprintf(stderr, " high=%d\n", high); +#endif + while (low < high - 1) { + int32_t i = (low + high) / 2; + int32_t diff = year - kEraInfo[i].year; + +#ifdef U_DEBUG_JCAL + fprintf(stderr, " d=%d low=%d, high=%d. Considering %d:M%d D%d Y%d. { we are ?:M%d D%d Y%d }\n", + diff,low, high, i, kEraInfo[i].month-1, kEraInfo[i].day, kEraInfo[i].year, internalGet(UCAL_MONTH), internalGet(UCAL_DATE),year); +#endif + + // If years are the same, then compare the months, and if those + // are the same, compare days of month. In the ERAS array + // months are 1-based for easier maintenance. + if (diff == 0) { + diff = internalGet(UCAL_MONTH) - (kEraInfo[i].month - 1); +#ifdef U_DEBUG_JCAL + fprintf(stderr, "diff now %d (M) = %d - %d - 1\n", diff, internalGet(UCAL_MONTH), kEraInfo[i].month); +#endif + if (diff == 0) { + diff = internalGet(UCAL_DATE) - kEraInfo[i].day; +#ifdef U_DEBUG_JCAL + fprintf(stderr, "diff now %d (D)\n", diff); +#endif + } + } + if (diff >= 0) { + low = i; + } else { + high = i; + } +#ifdef U_DEBUG_JCAL + fprintf(stderr, ". low=%d, high=%d, i=%d, diff=%d.. %d\n", low, high, i, diff, year); +#endif + + } + } + +#ifdef U_DEBUG_JCAL + fprintf(stderr, " low=%d,.. %d\n", low, year); +#endif + // Now we've found the last era that starts before this date, so + // adjust the year to count from the start of that era. Note that + // all dates before the first era will fall into the first era by + // the algorithm. + + internalSet(UCAL_ERA, low); + internalSet(UCAL_YEAR, year - kEraInfo[low].year + 1); +} + +/* + Disable pivoting +*/ +UBool JapaneseCalendar::haveDefaultCentury() const +{ + return FALSE; +} + +UDate JapaneseCalendar::defaultCenturyStart() const +{ + return 0;// WRONG +} + +int32_t JapaneseCalendar::defaultCenturyStartYear() const +{ + return 0; +} + U_NAMESPACE_END diff --git a/icu4c/source/i18n/japancal.h b/icu4c/source/i18n/japancal.h index df6838b8872..bf141a076e7 100644 --- a/icu4c/source/i18n/japancal.h +++ b/icu4c/source/i18n/japancal.h @@ -7,7 +7,7 @@ * Modification History: * * Date Name Description -* 05/13/2003 srl copied from gregocal.h +* 05/13/2003 srl copied from gregocal.h ******************************************************************************** */ @@ -26,7 +26,28 @@ U_NAMESPACE_BEGIN /** * Concrete class which provides the Japanese calendar. *

- * (stuff pasted here from java) + * JapaneseCalendar is a subclass of GregorianCalendar + * that numbers years and eras based on the reigns of the Japanese emperors. + * The Japanese calendar is identical to the Gregorian calendar in all respects + * except for the year and era. The ascension of each emperor to the throne + * begins a new era, and the years of that era are numbered starting with the + * year of ascension as year 1. + *

+ * Note that in the year of an imperial ascension, there are two possible sets + * of year and era values: that for the old era and for the new. For example, a + * new era began on January 7, 1989 AD. Strictly speaking, the first six days + * of that year were in the Showa era, e.g. "January 6, 64 Showa", while the rest + * of the year was in the Heisei era, e.g. "January 7, 1 Heisei". This class + * handles this distinction correctly when computing dates. However, in lenient + * mode either form of date is acceptable as input. + *

+ * In modern times, eras have started on January 8, 1868 AD, Gregorian (Meiji), + * July 30, 1912 (Taisho), December 25, 1926 (Showa), and January 7, 1989 (Heisei). Constants + * for these eras, suitable for use in the UCAL_ERA field, are provided + * in this class. Note that the number used for each era is more or + * less arbitrary. Currently, the era starting in 1053 AD is era #0; however this + * may change in the future as we add more historical data. Use the predefined + * constants rather than using actual, absolute numbers. *

* @internal */ @@ -34,12 +55,10 @@ class U_I18N_API JapaneseCalendar : public GregorianCalendar { public: /** - * Useful constants for JapaneseCalendar. Only one Era. + * Useful constants for JapaneseCalendar. * @internal */ - // enum EEras { - // BE - // }; + static const uint32_t kCurrentEra; // the current era /** * Constructs a JapaneseCalendar based on the current time in the default time zone @@ -110,26 +129,60 @@ public: static inline UClassID getStaticClassID(void); /** - * return the calendar type, "gregorian". + * return the calendar type, "japanese". * * @return calendar type - * @internal + * @draft ICU 2.6 */ virtual const char * getType() const; + /** + * @internal + * @return TRUE if this calendar has the notion of a default century + */ + virtual UBool haveDefaultCentury() const; + virtual UDate defaultCenturyStart() const; + virtual int32_t defaultCenturyStartYear() const; + private: JapaneseCalendar(); // default constructor not implemented static const char fgClassID; - protected: - // virtual int32_t monthLength(int32_t month) const; - // virtual int32_t monthLength(int32_t month, int32_t year) const; - // int32_t getGregorianYear(UErrorCode& status); - // int32_t getMaximum(UCalendarDateFields field) const; - // int32_t getLeastMaximum(UCalendarDateFields field) const; - // virtual int32_t internalGetEra() const; - // virtual void timeToFields(UDate theTime, UBool quick, UErrorCode& status); +protected: + virtual int32_t monthLength(int32_t month) const; + virtual int32_t monthLength(int32_t month, int32_t year) const; + int32_t getGregorianYear(UErrorCode& status) const; + int32_t getMaximum(UCalendarDateFields field) const; + int32_t getLeastMaximum(UCalendarDateFields field) const; + virtual int32_t internalGetEra() const; + virtual void timeToFields(UDate theTime, UBool quick, UErrorCode& status); + + /** + * (Overrides Calendar) Converts Calendar's time field values to GMT as + * milliseconds. In this case, we have to be concerned with filling in inconsistent + * information. For example, if the year and era only are set, need to make sure + * month & date are set correctly. Ex, 'Heisei 1' starts Jan 8th, not Jan 1st. + * Default month and date values will end up giving the wrong Era. + * + * @param status Output param set to success/failure code on exit. If any value + * previously set in the time field is invalid, this will be set to + * an error status. + * @stable ICU 2.0 + */ + + /*** + * Called by computeJulianDay. Returns the default month (0-based) for the year, + * taking year and era into account. Defaults to 0 for Gregorian, which doesn't care. + */ + virtual int32_t getDefaultMonthInYear() const; + + + /*** + * Called by computeJulianDay. Returns the default day (1-based) for the month, + * taking currently-set year and era into account. Defaults to 1 for Gregorian, which doesn't care. + */ + virtual int32_t getDefaultDayInMonth(int32_t month) const; }; inline UClassID diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp index 31b9ead2698..1985b6c3dc9 100644 --- a/icu4c/source/i18n/smpdtfmt.cpp +++ b/icu4c/source/i18n/smpdtfmt.cpp @@ -77,13 +77,9 @@ const char SimpleDateFormat::fgClassID = 0; // Value is irrelevant /** * This value of defaultCenturyStart indicates that the system default is to be - * used. + * used. To be removed in 2.8 */ const UDate SimpleDateFormat::fgSystemDefaultCentury = DBL_MIN; -const int32_t SimpleDateFormat::fgSystemDefaultCenturyYear = -1; - -UDate SimpleDateFormat::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t SimpleDateFormat::fgSystemDefaultCenturyStartYear = -1; static const UChar QUOTE = 0x27; // Single quote @@ -97,11 +93,10 @@ SimpleDateFormat::~SimpleDateFormat() //---------------------------------------------------------------------- SimpleDateFormat::SimpleDateFormat(UErrorCode& status) - : fSymbols(NULL),fLocale(Locale::getDefault()), - fDefaultCenturyStart(fgSystemDefaultCentury), - fDefaultCenturyStartYear(fgSystemDefaultCenturyYear) + : fSymbols(NULL),fLocale(Locale::getDefault()) { construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status); + initializeDefaultCentury(); } //---------------------------------------------------------------------- @@ -110,12 +105,11 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, UErrorCode &status) : fPattern(pattern), fSymbols(NULL), - fLocale(Locale::getDefault()), - fDefaultCenturyStart(fgSystemDefaultCentury), - fDefaultCenturyStartYear(fgSystemDefaultCenturyYear) + fLocale(Locale::getDefault()) { initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); initialize(fLocale, status); + initializeDefaultCentury(); } //---------------------------------------------------------------------- @@ -124,12 +118,11 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, const Locale& locale, UErrorCode& status) : fPattern(pattern), - fLocale(locale), - fDefaultCenturyStart(fgSystemDefaultCentury), - fDefaultCenturyStartYear(fgSystemDefaultCenturyYear) + fLocale(locale) { initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); initialize(fLocale, status); + initializeDefaultCentury(); } //---------------------------------------------------------------------- @@ -139,12 +132,11 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, UErrorCode& status) : fPattern(pattern), fSymbols(symbolsToAdopt), - fLocale(Locale::getDefault()), - fDefaultCenturyStart(fgSystemDefaultCentury), - fDefaultCenturyStartYear(fgSystemDefaultCenturyYear) + fLocale(Locale::getDefault()) { initializeCalendar(NULL,fLocale,status); initialize(fLocale, status); + initializeDefaultCentury(); } //---------------------------------------------------------------------- @@ -154,12 +146,11 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, UErrorCode& status) : fPattern(pattern), fSymbols(new DateFormatSymbols(symbols)), - fDefaultCenturyStart(fgSystemDefaultCentury), - fDefaultCenturyStartYear(fgSystemDefaultCenturyYear), fLocale(Locale::getDefault()) { initializeCalendar(NULL, fLocale, status); initialize(fLocale, status); + initializeDefaultCentury(); } //---------------------------------------------------------------------- @@ -170,11 +161,10 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle, const Locale& locale, UErrorCode& status) : fSymbols(NULL), - fDefaultCenturyStart(fgSystemDefaultCentury), - fDefaultCenturyStartYear(fgSystemDefaultCenturyYear), fLocale(locale) { construct(timeStyle, dateStyle, fLocale, status); + initializeDefaultCentury(); } //---------------------------------------------------------------------- @@ -188,9 +178,7 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale, UErrorCode& status) : fPattern(fgDefaultPattern), fSymbols(NULL), - fLocale(locale), - fDefaultCenturyStart(fgSystemDefaultCentury), - fDefaultCenturyStartYear(fgSystemDefaultCenturyYear) + fLocale(locale) { if (U_FAILURE(status)) return; initializeSymbols(fLocale, initializeCalendar(NULL, fLocale, status),status); @@ -208,15 +196,14 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale, } initialize(fLocale, status); + initializeDefaultCentury(); } //---------------------------------------------------------------------- SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other) : DateFormat(other), - fSymbols(NULL), - fDefaultCenturyStart(fgSystemDefaultCentury), - fDefaultCenturyStartYear(fgSystemDefaultCenturyYear) + fSymbols(NULL) { *this = other; } @@ -235,6 +222,7 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other) fDefaultCenturyStart = other.fDefaultCenturyStart; fDefaultCenturyStartYear = other.fDefaultCenturyStartYear; + fHaveDefaultCentury = other.fHaveDefaultCentury; fPattern = other.fPattern; @@ -262,6 +250,7 @@ SimpleDateFormat::operator==(const Format& other) const fSymbols != NULL && // Check for pathological object that->fSymbols != NULL && // Check for pathological object *fSymbols == *that->fSymbols && + fHaveDefaultCentury == that->fHaveDefaultCentury && fDefaultCenturyStart == that->fDefaultCenturyStart); } return FALSE; @@ -278,12 +267,16 @@ void SimpleDateFormat::construct(EStyle timeStyle, if (U_FAILURE(status)) return; - // load up the DateTimePatters resource from the appropriate locale (throw + // load up the DateTimePatterns resource from the appropriate locale (throw // an error if for some weird reason the resource is malformed) ResourceBundle resources((char *)0, locale, status); - ResourceBundle dateTimePatterns = resources.get(fgDateTimePatternsTag, status); + // We will need the calendar to know what type of symbols to load. + initializeCalendar(NULL, locale, status); + + // use Date Format Symbols' helper function to do the actual load. + ResourceBundle dateTimePatterns = DateFormatSymbols::getData(resources, fgDateTimePatternsTag, fCalendar?fCalendar->getType():NULL, status); if (U_FAILURE(status)) return; if (dateTimePatterns.getSize() <= kDateTime) @@ -292,8 +285,8 @@ void SimpleDateFormat::construct(EStyle timeStyle, return; } - initializeSymbols(locale, initializeCalendar(NULL, locale, status), status); // create a symbols object from the locale + initializeSymbols(locale,fCalendar, status); if (U_FAILURE(status)) return; /* test for NULL */ if (fSymbols == 0) { @@ -401,8 +394,6 @@ SimpleDateFormat::initialize(const Locale& locale, ((DecimalFormat*)fNumberFormat)->setDecimalSeparatorAlwaysShown(FALSE); fNumberFormat->setParseIntegerOnly(TRUE); fNumberFormat->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00" - - initializeDefaultCentury(); } else if (U_SUCCESS(status)) { @@ -415,12 +406,14 @@ SimpleDateFormat::initialize(const Locale& locale, */ void SimpleDateFormat::initializeDefaultCentury() { - fDefaultCenturyStart = internalGetDefaultCenturyStart(); - fDefaultCenturyStartYear = internalGetDefaultCenturyStartYear(); - - UErrorCode status = U_ZERO_ERROR; - fCalendar->setTime(fDefaultCenturyStart, status); - // {sfb} throw away error + fHaveDefaultCentury = fCalendar->haveDefaultCentury(); + if(fHaveDefaultCentury) { + fDefaultCenturyStart = fCalendar->defaultCenturyStart(); + fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear(); + } else { + fDefaultCenturyStart = DBL_MIN; + fDefaultCenturyStartYear = -1; + } } /* Define one-century window into which to disambiguate dates using @@ -433,6 +426,7 @@ void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& s fCalendar->setTime(startDate, status); if(U_SUCCESS(status)) { + fHaveDefaultCentury = TRUE; fDefaultCenturyStart = startDate; fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status); } @@ -589,6 +583,8 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, zeroPaddingNumber(appendTo, value, 4, maxIntCount); else zeroPaddingNumber(appendTo, value, 2, 2); + + // SRL TODO: add 'y', unpadded value break; // for "MMMM", write out the whole month name, for "MMM", write out the month @@ -952,10 +948,10 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& Calendar *copy = cal.clone(); UDate parsedDate = copy->getTime(status); // {sfb} check internalGetDefaultCenturyStart - if (parsedDate < internalGetDefaultCenturyStart()) + if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) { // We can't use add here because that does a complete() first. - cal.set(UCAL_YEAR, internalGetDefaultCenturyStartYear() + 100); + cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100); } delete copy; } @@ -1137,18 +1133,21 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC // other fields specify a date before 6/18, or 1903 if they specify a // date afterwards. As a result, 03 is an ambiguous year. All other // two-digit years are unambiguous. - int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100; - ambiguousYear[0] = (value == ambiguousTwoDigitYear); - value += (fDefaultCenturyStartYear/100)*100 + + if(fHaveDefaultCentury) { // check if this formatter even has a pivot year + int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100; + ambiguousYear[0] = (value == ambiguousTwoDigitYear); + value += (fDefaultCenturyStartYear/100)*100 + (value < ambiguousTwoDigitYear ? 100 : 0); + } } cal.set(UCAL_YEAR, value); return pos.getIndex(); case kYearWOYField: - // Comment is the same as for kYearFiels - look above + // Comment is the same as for kYearFields - look above if (count <= 2 && (pos.getIndex() - start) == 2 && u_isdigit(text.charAt(start)) - && u_isdigit(text.charAt(start+1))) + && u_isdigit(text.charAt(start+1)) + && fHaveDefaultCentury ) { int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100; ambiguousYear[0] = (value == ambiguousTwoDigitYear); @@ -1527,56 +1526,6 @@ SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols //---------------------------------------------------------------------- -UDate -SimpleDateFormat::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) - initializeSystemDefaultCentury(); - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - return (fDefaultCenturyStart == fgSystemDefaultCentury) ? - fgSystemDefaultCenturyStart : fDefaultCenturyStart; -} - -int32_t -SimpleDateFormat::internalGetDefaultCenturyStartYear() const -{ - // lazy-evaluate systemDefaultCenturyStartYear - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) - initializeSystemDefaultCentury(); - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - //return (fDefaultCenturyStart == fgSystemDefaultCentury) ? - return (fDefaultCenturyStartYear == fgSystemDefaultCenturyYear) ? - fgSystemDefaultCenturyStartYear : fDefaultCenturyStartYear; -} - -void -SimpleDateFormat::initializeSystemDefaultCentury() -{ - // initialize systemDefaultCentury and systemDefaultCenturyYear based - // on the current time. They'll be set to 80 years before - // the current time. - // No point in locking as it should be idempotent. - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) - { - UErrorCode status = U_ZERO_ERROR; - Calendar *calendar = Calendar::createInstance(status); - if (calendar != NULL && U_SUCCESS(status)) - { - calendar->setTime(Calendar::getNow(), status); - calendar->add(UCAL_YEAR, -80, status); - fgSystemDefaultCenturyStart = calendar->getTime(status); - fgSystemDefaultCenturyStartYear = calendar->get(UCAL_YEAR, status); - delete calendar; - } - // We have no recourse upon failure unless we want to propagate the failure - // out. - } -} void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt) { @@ -1584,7 +1533,8 @@ void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt) DateFormat::adoptCalendar(calendarToAdopt); delete fSymbols; fSymbols=NULL; - initializeSymbols(fLocale, fCalendar, status); + initializeSymbols(fLocale, fCalendar, status); // we need new symbols + initializeDefaultCentury(); // we need a new century (possibly) } diff --git a/icu4c/source/i18n/unicode/calendar.h b/icu4c/source/i18n/unicode/calendar.h index 7da6feb56aa..a31d4614fca 100644 --- a/icu4c/source/i18n/unicode/calendar.h +++ b/icu4c/source/i18n/unicode/calendar.h @@ -38,7 +38,7 @@ U_NAMESPACE_BEGIN class ICUServiceFactory; /** - * @draft ICU 2.6 + * @internal */ typedef const void* URegistryKey; @@ -1139,7 +1139,7 @@ public: * or "Eras_gregorian". * * @returns static string, for example, "gregorian" or "japanese" - * @draft ICU 2.6 + * @internal */ virtual const char * getType() const = 0; @@ -1465,6 +1465,23 @@ private: friend class CalendarFactory; friend class CalendarService; friend class DefaultCalendarFactory; + + /** + * @internal + * @return TRUE if this calendar has the notion of a default century + */ + virtual UBool haveDefaultCentury() const = 0; + /** + * @internal + * @return the start of the default century + */ + virtual UDate defaultCenturyStart() const = 0; + /** + * @internal + * @return the beginning year of the default century + */ + virtual int32_t defaultCenturyStartYear() const = 0; + }; // ------------------------------------- diff --git a/icu4c/source/i18n/unicode/dtfmtsym.h b/icu4c/source/i18n/unicode/dtfmtsym.h index 7266c02fad1..e0158256731 100644 --- a/icu4c/source/i18n/unicode/dtfmtsym.h +++ b/icu4c/source/i18n/unicode/dtfmtsym.h @@ -58,8 +58,15 @@ class SimpleDateFormat; * they feel easy to remember. Or they can change the representative cities * originally picked by default to using their favorite ones. *

- * New DateFormatSymbols sub-classes may be added to support SimpleDateFormat - * for date-time formatting for additional locales. + * DateFormatSymbols are not expected to be subclassed. Data for a calendar is + * loaded out of resource bundles. The 'type' parameter indicates the type of + * calendar, for example, "gregorian" or "japanese". If the type is not gregorian + * (or NULL, or an empty string) then the type is appended to the resource name, + * for example, 'Eras_japanese' instead of 'Eras'. If the resource 'Eras_japanese' did + * not exist (even in root), then this class will fall back to just 'Eras', that is, + * Gregorian data. Therefore, the calendar implementor MUST ensure that the root + * locale at least contains any resources that are to be particularized for the + * calendar type. */ class U_I18N_API DateFormatSymbols : public UObject { public: @@ -71,7 +78,7 @@ public: * data for the default locale, it will return a last-resort object * based on hard-coded strings. * - * @param status Output param set to success of failure. Failure + * @param status Status code. Failure * results if the resources for the default cannot be * found or cannot be loaded * @stable ICU 2.0 @@ -83,7 +90,7 @@ public: * resources for the given locale, in the default calendar (Gregorian). * * @param locale Locale to load format data from. - * @param status Output param set to success of failure. Failure + * @param status Status code. Failure * results if the resources for the locale cannot be * found or cannot be loaded * @stable ICU 2.0 @@ -102,10 +109,10 @@ public: * @param type Type of calendar (as returned by Calendar::getType). * Will be used to access the correct set of strings. * (NULL or empty string defaults to "gregorian".) - * @param status Output param set to success of failure. Failure + * @param status Status code. Failure * results if the resources for the default cannot be * found or cannot be loaded - * @draft ICU 2.6 + * @internal */ DateFormatSymbols(const char *type, UErrorCode& status); @@ -117,10 +124,10 @@ public: * @param type Type of calendar (as returned by Calendar::getType). * Will be used to access the correct set of strings. * (NULL or empty string defaults to "gregorian".) - * @param status Output param set to success of failure. Failure + * @param status Status code. Failure * results if the resources for the locale cannot be * found or cannot be loaded - * @draft ICU 2.6 + * @internal */ DateFormatSymbols(const Locale& locale, const char *type, @@ -422,7 +429,7 @@ private: * @param status Error Status * @internal */ - ResourceBundle + static ResourceBundle getData(ResourceBundle &rb, const char *tag, const char *type, UErrorCode& status); diff --git a/icu4c/source/i18n/unicode/gregocal.h b/icu4c/source/i18n/unicode/gregocal.h index b565fa04ea8..4f3ddab2ad4 100644 --- a/icu4c/source/i18n/unicode/gregocal.h +++ b/icu4c/source/i18n/unicode/gregocal.h @@ -550,7 +550,7 @@ public: * Get the calendar type, "gregorian", for use in DateFormatSymbols. * * @return calendar type - * @draft ICU 2.6 + * @internal */ virtual const char * getType() const; @@ -560,7 +560,22 @@ protected: * Called by computeFields. Converts calendar's year into Gregorian Extended Year (where negative = BC) * @internal */ - virtual int32_t getGregorianYear(UErrorCode &status); + virtual int32_t getGregorianYear(UErrorCode &status) const; + + /*** + * Called by computeJulianDay. Returns the default month (0-based) for the year, + * taking year and era into account. Defaults to 0 for Gregorian, which doesn't care. + */ + virtual int32_t getDefaultMonthInYear() const { return 0; } + + + /*** + * Called by computeJulianDay. Returns the default day (1-based) for the month, + * taking currently-set year and era into account. Defaults to 1 for Gregorian, which doesn't care. + */ + virtual int32_t getDefaultDayInMonth(int32_t month) const { return 1; } + + /** * (Overrides Calendar) Converts GMT as milliseconds to time field values. @@ -850,6 +865,72 @@ protected: */ static int32_t floorDivide(double numerator, int32_t denominator, int32_t remainder[]); + public: // internal implementation + + /** + * @internal + * @return TRUE if this calendar has the notion of a default century + */ + virtual UBool haveDefaultCentury() const; + + /** + * @internal + * @return the start of the default century + */ + virtual UDate defaultCenturyStart() const; + + /** + * @internal + * @return the beginning year of the default century + */ + virtual int32_t defaultCenturyStartYear() const; + + private: + /** + * The system maintains a static default century start date. This is initialized + * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to + * indicate an uninitialized state. Once the system default century date and year + * are set, they do not change. + */ + static UDate fgSystemDefaultCenturyStart; + + /** + * See documentation for systemDefaultCenturyStart. + */ + static int32_t fgSystemDefaultCenturyStartYear; + + /** + * Default value that indicates the defaultCenturyStartYear is unitialized + */ + static const int32_t fgSystemDefaultCenturyYear; + + /** + * TODO: (ICU 2.8) use this value instead of SimpleDateFormat::fgSystemDefaultCentury + */ + //static const UDate fgSystemDefaultCentury; + + /** + * Returns the beginning date of the 100-year window that dates with 2-digit years + * are considered to fall within. + * @return the beginning date of the 100-year window that dates with 2-digit years + * are considered to fall within. + */ + UDate internalGetDefaultCenturyStart(void) const; + + /** + * Returns the first year of the 100-year window that dates with 2-digit years + * are considered to fall within. + * @return the first year of the 100-year window that dates with 2-digit years + * are considered to fall within. + */ + int32_t internalGetDefaultCenturyStartYear(void) const; + + /** + * Initializes the 100-year window that dates with 2-digit years are considered + * to fall within so that its start date is 80 years before the current time. + */ + static void initializeSystemDefaultCentury(void); + }; inline UClassID diff --git a/icu4c/source/test/intltest/incaltst.cpp b/icu4c/source/test/intltest/incaltst.cpp index 32b399ea2d4..ced7f65834f 100644 --- a/icu4c/source/test/intltest/incaltst.cpp +++ b/icu4c/source/test/intltest/incaltst.cpp @@ -14,7 +14,7 @@ #define CHECK(status, msg) \ if (U_FAILURE(status)) { \ - errln((UnicodeString(u_errorName(status)) + UnicodeString("err " ) )+ msg); \ + errln((UnicodeString(u_errorName(status)) + UnicodeString(" : " ) )+ msg); \ return; \ } @@ -30,6 +30,9 @@ static UnicodeString fieldName(UCalendarDateFields f); +// Turn this on to dump the calendar fields +#define U_DEBUG_DUMPCALS + static UnicodeString calToStr(const Calendar & cal) { @@ -41,7 +44,7 @@ static UnicodeString calToStr(const Calendar & cal) } out += UnicodeString(cal.getType()); - out += cal.inDaylightTime(status)?UnicodeString("DAYLIGHT"):UnicodeString("NORMAL"); + out += cal.inDaylightTime(status)?UnicodeString("- DAYLIGHT"):UnicodeString("- NORMAL"); UnicodeString str2; out += cal.getTimeZone().getDisplayName(str2); @@ -49,28 +52,25 @@ static UnicodeString calToStr(const Calendar & cal) return out; } +#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break + + void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) { if (exec) logln("TestSuite IntlCalendarTest"); switch (index) { - case 0: - name = "TestTypes"; - if (exec) { - logln("TestTypes---"); logln(""); - TestTypes(); - } - break; - case 1: - name = "TestBuddhist"; - if (exec) { - logln("TestBuddhist---"); logln(""); - TestBuddhist(); - } - break; + CASE(0,TestTypes); + CASE(1,TestGregorian); + CASE(2,TestBuddhist); + CASE(3,TestJapanese); + CASE(4,TestBuddhistFormat); + CASE(5,TestJapaneseFormat); default: name = ""; break; } } +#undef CASE + // --------------------------------------------------------------------------------- static UnicodeString fieldName(UCalendarDateFields f) { @@ -110,15 +110,11 @@ IntlCalendarTest::TestTypes() UErrorCode status = U_ZERO_ERROR; int j; const char *locs [40] = { "en_US_VALLEYGIRL", -#if 0 "ja_JP_TRADITIONAL", -#endif "th_TH_TRADITIONAL", "en_US", NULL }; const char *types[40] = { "gregorian", -#if 0 "japanese", -#endif "buddhist", "gregorian", NULL }; @@ -175,13 +171,15 @@ void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, cons cal.set(UCAL_ERA, era); cal.set(year, month, dayOfMonth); UDate d = cal.getTime(status); - // logln((UnicodeString)"cal : " + calToStr(cal)); - // logln((UnicodeString)"grego: " + calToStr(*grego)); +#ifdef U_DEBUG_DUMPCALS + logln((UnicodeString)"cal : " + calToStr(cal)); + logln((UnicodeString)"grego: " + calToStr(*grego)); +#endif if (d == D) { logln(UnicodeString("OK: ") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth + - " => " + d + " (" + UnicodeString(cal.getType())); + " => " + d + " (" + UnicodeString(cal.getType()) + ")"); } else { - errln(UnicodeString("Fail: ") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth + + errln(UnicodeString("Fail: (fields to millis)") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth + " => " + d + ", expected " + D + " (" + UnicodeString(cal.getType()) + "Off by: " + (d-D)); } @@ -190,14 +188,16 @@ void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, cons cal.setTime(D, status); int e = cal.get(UCAL_ERA, status); int y = cal.get(UCAL_YEAR, status); - //logln((UnicodeString)"cal : " + calToStr(cal)); - //logln((UnicodeString)"grego: " + calToStr(*grego)); +#ifdef U_DEBUG_DUMPCALS + logln((UnicodeString)"cal : " + calToStr(cal)); + logln((UnicodeString)"grego: " + calToStr(*grego)); +#endif if (y == year && e == era) { logln((UnicodeString)"OK: " + D + " => " + cal.get(UCAL_ERA, status) + ":" + cal.get(UCAL_YEAR, status) + "/" + - (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + " (" + UnicodeString(cal.getType())); + (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + " (" + UnicodeString(cal.getType()) + ")"); } else { - errln((UnicodeString)"Fail: " + D + " => " + cal.get(UCAL_ERA, status) + ":" + + errln((UnicodeString)"Fail: (millis to fields)" + D + " => " + cal.get(UCAL_ERA, status) + ":" + cal.get(UCAL_YEAR, status) + "/" + (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + ", expected " + era + ":" + year + "/" + (month+1) + "/" + @@ -208,6 +208,26 @@ void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, cons CHECK(status, "err during quasiGregorianTest()"); } +// Verify that Gregorian works like Gregorian +void IntlCalendarTest::TestGregorian() { + int32_t data[] = { + GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 8, + GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 9, + GregorianCalendar::AD, 1869, 1869, UCAL_JUNE, 4, + GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 29, + GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 30, + GregorianCalendar::AD, 1912, 1912, UCAL_AUGUST, 1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; + + Calendar *cal; + UErrorCode status = U_ZERO_ERROR; + cal = Calendar::createInstance("de_DE", status); + CHECK(status, UnicodeString("Creating de_CH calendar")); + quasiGregorianTest(*cal,Locale("fr_FR"),data); + delete cal; +} + /** * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise * behaves like GregorianCalendar. @@ -231,6 +251,50 @@ void IntlCalendarTest::TestBuddhist() { cal = Calendar::createInstance("th_TH_TRADITIONAL", status); CHECK(status, UnicodeString("Creating th_TH_TRADITIONAL calendar")); quasiGregorianTest(*cal,Locale("th_TH"),data); +} + +/** + * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise + * behaves like GregorianCalendar. + */ +void IntlCalendarTest::TestJapanese() { + +/* Sorry.. japancal.h is private! */ +#define JapaneseCalendar_MEIJI 232 +#define JapaneseCalendar_TAISHO 233 +#define JapaneseCalendar_SHOWA 234 +#define JapaneseCalendar_HEISEI 235 + + // BE 2542 == 1999 CE + int32_t data[] = { + // Jera Jyr Gyear m d + JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 8, + JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 9, + JapaneseCalendar_MEIJI, 2, 1869, UCAL_JUNE, 4, + JapaneseCalendar_MEIJI, 45, 1912, UCAL_JULY, 29, + JapaneseCalendar_TAISHO, 1, 1912, UCAL_JULY, 30, + JapaneseCalendar_TAISHO, 1, 1912, UCAL_AUGUST, 1, + + // new tests (not in java) + JapaneseCalendar_SHOWA, 64, 1989, UCAL_JANUARY, 7, + JapaneseCalendar_HEISEI, 1, 1989, UCAL_JANUARY, 8, + JapaneseCalendar_HEISEI, 1, 1989, UCAL_JANUARY, 9, + JapaneseCalendar_HEISEI, 1, 1989, UCAL_DECEMBER, 20, + JapaneseCalendar_HEISEI, 15, 2003, UCAL_MAY, 22, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; + + Calendar *cal; + UErrorCode status = U_ZERO_ERROR; + cal = Calendar::createInstance("ja_JP_TRADITIONAL", status); + CHECK(status, UnicodeString("Creating ja_JP_TRADITIONAL calendar")); + quasiGregorianTest(*cal,Locale("ja_JP"),data); +} + +void IntlCalendarTest::TestBuddhistFormat() { + Calendar *cal; + UErrorCode status = U_ZERO_ERROR; + cal = Calendar::createInstance("th_TH_TRADITIONAL", status); + CHECK(status, UnicodeString("Creating th_TH_TRADITIONAL calendar")); // Test simple parse/format with adopt @@ -262,6 +326,54 @@ void IntlCalendarTest::TestBuddhist() { } delete fmt; } + delete cal; + CHECK(status, "Error occured"); +} + + +void IntlCalendarTest::TestJapaneseFormat() { + Calendar *cal; + UErrorCode status = U_ZERO_ERROR; + cal = Calendar::createInstance("ja_JP_TRADITIONAL", status); + CHECK(status, UnicodeString("Creating ja_JP_TRADITIONAL calendar")); + + Calendar *cal2 = cal->clone(); + + // Test simple parse/format with adopt + + UDate aDate = 999932400000.0; + SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yy G"), Locale("en_US"), status); + CHECK(status, "creating date format instance"); + if(!fmt) { + errln("Coudln't create en_US instance"); + } else { + UnicodeString str; + fmt->format(aDate, str); + logln(UnicodeString() + "Test Date: " + str); + str.remove(); + fmt->adoptCalendar(cal); + cal = NULL; + fmt->format(aDate, str); + logln(UnicodeString() + "as Japanese Calendar: " + str); + UnicodeString expected("September 8, 13 Heisei"); + if(str != expected) { + errln("Expected " + expected + " but got " + str); + } + UDate otherDate = fmt->parse(expected, status); + if(otherDate != aDate) { + UnicodeString str3; + ParsePosition pp; + fmt->parse(expected, *cal2, pp); + fmt->format(otherDate, str3); + errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " + " = " + otherDate + ", " + str3 + " = " + calToStr(*cal2) ); + + } else { + logln("Parsed OK: " + expected); + } + delete fmt; + } + delete cal; + delete cal2; CHECK(status, "Error occured"); } diff --git a/icu4c/source/test/intltest/incaltst.h b/icu4c/source/test/intltest/incaltst.h index 7c55c9351f1..447073b0c97 100644 --- a/icu4c/source/test/intltest/incaltst.h +++ b/icu4c/source/test/intltest/incaltst.h @@ -20,14 +20,18 @@ public: // IntlTest override void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par ); public: - /** - * Confirm that the registered calendars have the correct type. - */ void TestTypes(void); + void TestGregorian(void); + void TestBuddhist(void); + void TestBuddhistFormat(void); + + void TestJapanese(void); + void TestJapaneseFormat(void); protected: + // Test a Gregorian-Like calendar void quasiGregorianTest(Calendar& cal, const Locale& gregoLocale, const int32_t *data); public: // package