* Updated era data format in supplementalData.
* Include tentative era names in data. Implemented Japanese era loaded from CLDR data in ICU4J.
* ICU4C implementation, ICU4C refactoring. WIP.
* VS project updates and some bug fixes
Also added API comments.
* Review feedback and bug fixes
- NULL to nullptr
- use of LocalUResourceBundlePointer
- TYPO "name" to "named"
- env var checking stricmp() == 0
* API comment correction based on feedback
* Duplicate the comment in ucal.h to calendar.h
* Fixed spelling errors in API comment
"تيشو",
"شووا",
"هيسي",
+ "Qqqq",
}
}
}
"Taishō",
"e. Shōwa",
"Heisei",
+ "Qqqq",
}
narrow{
"Taika",
"T",
"S",
"H",
+ "Q",
}
wide{
"Taika (645–650)",
"Taishō",
"era Shōwa",
"Heisei",
+ "Qqqq",
}
}
intervalFormats{
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
narrow{
"Taika (645–650)",
"T",
"S",
"H",
+ "Q",
}
wide{
"Taika (645–650)",
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
intervalFormats{
"Таишо",
"Шова",
"Хаисеи",
+ "Qqqq",
}
}
}
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
narrow{
"Taika (645–650)",
"T",
"S",
"H",
+ "Q",
}
wide{
"Taika (645–650)",
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
intervalFormats{
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
}
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
}
"ताईशो",
"शोवा",
"हेईसेई",
+ "Qqqq",
}
}
}
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
}
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
}
"大正",
"昭和",
"平成",
+ "QQ",
}
narrow{
"大化",
"T",
"S",
"H",
+ "Q",
}
}
}
"다이쇼",
"쇼와",
"헤이세이",
+ "Qqqq",
}
}
}
"ໄຕໂຊ",
"ໂຊວາ",
"ຮີຊີ",
+ "Qqqq",
}
}
}
"Taišo",
"Šova",
"Heisei",
+ "Qqqq",
}
}
}
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
narrow{
"Taika (645–650)",
"T",
"S",
"H",
+ "Q",
}
wide{
"Taika (645–650)",
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
intervalFormats{
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
narrow{
"Taika (645–650)",
"T",
"S",
"H",
+ "Q",
}
wide{
"Taika (645–650)",
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
}
"Taishō",
"Shōwa",
"Heisei",
+ "QQ",
}
narrow{
"Taika (645–650)",
"T",
"S",
"H",
+ "Q",
}
wide:alias{"/LOCALE/calendar/japanese/eras/abbreviated"}
}
"Эпоха Тайсьо",
"Сьова",
"Эпоха Хэйсэй",
+ "Qqqq",
}
}
}
"Таишо",
"Шова",
"Хаисеи",
+ "Qqqq",
}
}
}
"Taišo",
"Šova",
"Haisei",
+ "Qqqq",
}
}
}
"Taishō",
"Shōwa",
"Heisei",
+ "Qqqq",
}
}
}
"ทะอิโช",
"โชวะ",
"เฮเซ",
+ "Qqqq",
}
}
}
"大正",
"昭和",
"平成",
+ "Qqqq",
}
}
}
"大正",
"昭和",
"平成",
+ "Qqqq",
}
}
}
"大正",
"昭和",
"平成",
+ "Qqqq",
}
narrow{
"大化(645–650)",
"T",
"S",
"H",
+ "Q",
}
wide{
"大化 (645–650)",
"大正",
"昭和",
"平成",
+ "Qqqq",
}
}
}
"大正",
"昭和",
"平成",
+ "Qqqq",
}
narrow{
"大化",
"大正",
"昭和",
"平成",
+ "Q",
}
wide{
"大化",
"大正",
"昭和",
"平成",
+ "Qqqq",
}
}
intervalFormats{
eras{
0{
start:intvector{
- -18457,
- 643382272,
+ -542,
+ 1,
+ 1,
}
}
}
eras{
0{
start:intvector{
- -33843,
- 1352598528,
+ -2636,
+ 1,
+ 1,
}
}
}
eras{
0{
end:intvector{
- -12383,
- 368826367,
+ 284,
+ 8,
+ 28,
}
}
1{
start:intvector{
- -12383,
- 368826368,
+ 284,
+ 8,
+ 29,
}
}
}
eras{
0{
start:intvector{
- -31610,
- -93940736,
+ -2332,
+ 1,
+ 1,
}
}
}
eras{
0{
end:intvector{
- -14411,
- 664902655,
+ 8,
+ 8,
+ 28,
}
}
1{
start:intvector{
- -14411,
- 664902656,
+ 8,
+ 8,
+ 29,
}
}
}
eras{
0{
end:intvector{
- -54823,
- -2125298689,
+ -5492,
+ 8,
+ 29,
}
}
}
eras{
0{
end:intvector{
- -14468,
- -477728769,
+ 0,
+ 12,
+ 31,
}
}
1{
start:intvector{
- -14468,
- -477728768,
+ 1,
+ 1,
+ 1,
}
}
}
eras{
0{
start:intvector{
- -42096,
- 1167292416,
+ -3760,
+ 10,
+ 7,
}
}
}
eras{
0{
start:intvector{
- -13895,
- -44389376,
+ 79,
+ 1,
+ 1,
}
}
}
eras{
0{
start:intvector{
- -9901,
- -1497369600,
+ 622,
+ 7,
+ 15,
}
}
}
eras{
0{
start:intvector{
- -9901,
- -1410969600,
+ 622,
+ 7,
+ 16,
}
}
}
eras{
0{
start:intvector{
- -9901,
- -1497369600,
+ 622,
+ 7,
+ 15,
}
}
}
eras{
0{
start:intvector{
- -9901,
- -1497369600,
+ 622,
+ 7,
+ 15,
}
}
}
eras{
0{
start:intvector{
- -9901,
- -1497369600,
+ 622,
+ 7,
+ 15,
}
}
}
eras{
0{
start:intvector{
- -9732,
- 548124672,
+ 645,
+ 6,
+ 19,
}
}
1{
start:intvector{
- -9698,
- 1572036608,
+ 650,
+ 2,
+ 15,
}
}
10{
start:intvector{
- -9114,
- 1157535744,
+ 729,
+ 8,
+ 5,
}
}
100{
start:intvector{
- -5884,
- -819397632,
+ 1169,
+ 4,
+ 8,
}
}
101{
start:intvector{
- -5869,
- -1048707072,
+ 1171,
+ 4,
+ 21,
}
}
102{
start:intvector{
- -5837,
- 504906752,
+ 1175,
+ 7,
+ 28,
}
}
103{
start:intvector{
- -5823,
- -156402688,
+ 1177,
+ 8,
+ 4,
}
}
104{
start:intvector{
- -5794,
- -294454272,
+ 1181,
+ 7,
+ 14,
}
}
105{
start:intvector{
- -5787,
- 1324541952,
+ 1182,
+ 5,
+ 27,
}
}
106{
start:intvector{
- -5773,
- 810999808,
+ 1184,
+ 4,
+ 16,
}
}
107{
start:intvector{
- -5764,
- -234673152,
+ 1185,
+ 8,
+ 14,
}
}
108{
start:intvector{
- -5729,
- 702838784,
+ 1190,
+ 4,
+ 11,
}
}
109{
start:intvector{
- -5663,
- -1680770048,
+ 1199,
+ 4,
+ 27,
}
}
11{
start:intvector{
- -8970,
- -223922176,
+ 749,
+ 4,
+ 14,
}
}
110{
start:intvector{
- -5650,
- -664144896,
+ 1201,
+ 2,
+ 13,
}
}
111{
start:intvector{
- -5627,
- 59374592,
+ 1204,
+ 2,
+ 20,
}
}
112{
start:intvector{
- -5611,
- 200697856,
+ 1206,
+ 4,
+ 27,
}
}
113{
start:intvector{
- -5600,
- 130457600,
+ 1207,
+ 10,
+ 25,
}
}
114{
start:intvector{
- -5576,
- -885324800,
+ 1211,
+ 3,
+ 9,
}
}
115{
start:intvector{
- -5556,
- -125470720,
+ 1213,
+ 12,
+ 6,
}
}
116{
start:intvector{
- -5516,
- 1110004736,
+ 1219,
+ 4,
+ 12,
}
}
117{
start:intvector{
- -5494,
- 1401524224,
+ 1222,
+ 4,
+ 13,
}
}
118{
start:intvector{
- -5475,
- 2049945600,
+ 1224,
+ 11,
+ 20,
}
}
119{
start:intvector{
- -5472,
- -2083523584,
+ 1225,
+ 4,
+ 20,
}
}
12{
start:intvector{
- -8968,
- -1988256768,
+ 749,
+ 7,
+ 2,
}
}
120{
start:intvector{
- -5453,
- -398302208,
+ 1227,
+ 12,
+ 10,
}
}
121{
start:intvector{
- -5444,
- -86607872,
+ 1229,
+ 3,
+ 5,
}
}
122{
start:intvector{
- -5421,
- -1757255680,
+ 1232,
+ 4,
+ 2,
}
}
123{
start:intvector{
- -5413,
- 837173248,
+ 1233,
+ 4,
+ 15,
}
}
124{
start:intvector{
- -5402,
- -1540834304,
+ 1234,
+ 11,
+ 5,
}
}
125{
start:intvector{
- -5395,
- 164561920,
+ 1235,
+ 9,
+ 19,
}
}
126{
start:intvector{
- -5372,
- 1690714112,
+ 1238,
+ 11,
+ 23,
}
}
127{
start:intvector{
- -5371,
- -332820480,
+ 1239,
+ 2,
+ 7,
}
}
128{
start:intvector{
- -5360,
- 2077506560,
+ 1240,
+ 7,
+ 16,
}
}
129{
start:intvector{
- -5341,
- -1309839360,
+ 1243,
+ 2,
+ 26,
}
}
13{
start:intvector{
- -8908,
- 1130272768,
+ 757,
+ 8,
+ 18,
}
}
130{
start:intvector{
- -5311,
- 539309056,
+ 1247,
+ 2,
+ 28,
}
}
131{
start:intvector{
- -5296,
- 828399616,
+ 1249,
+ 3,
+ 18,
}
}
132{
start:intvector{
- -5241,
- -1398568960,
+ 1256,
+ 10,
+ 5,
}
}
133{
start:intvector{
- -5238,
- -459470848,
+ 1257,
+ 3,
+ 14,
}
}
134{
start:intvector{
- -5223,
- -775180288,
+ 1259,
+ 3,
+ 26,
}
}
135{
start:intvector{
- -5215,
- -1957318656,
+ 1260,
+ 4,
+ 13,
}
}
136{
start:intvector{
- -5209,
- -683922432,
+ 1261,
+ 2,
+ 20,
}
}
137{
start:intvector{
- -5186,
- 125997056,
+ 1264,
+ 2,
+ 28,
}
}
138{
start:intvector{
- -5105,
- -67721216,
+ 1275,
+ 4,
+ 25,
}
}
139{
start:intvector{
- -5084,
- -319634432,
+ 1278,
+ 2,
+ 29,
}
}
14{
start:intvector{
- -8854,
- -1899328512,
+ 765,
+ 1,
+ 7,
}
}
140{
start:intvector{
- -5009,
- -1811781632,
+ 1288,
+ 4,
+ 28,
}
}
141{
start:intvector{
- -4969,
- 1324493824,
+ 1293,
+ 8,
+ 5,
}
}
142{
start:intvector{
- -4928,
- 1400434688,
+ 1299,
+ 4,
+ 25,
}
}
143{
start:intvector{
- -4902,
- -1725282304,
+ 1302,
+ 11,
+ 21,
}
}
144{
start:intvector{
- -4897,
- -995318784,
+ 1303,
+ 8,
+ 5,
}
}
145{
start:intvector{
- -4872,
- 1938266112,
+ 1306,
+ 12,
+ 14,
}
}
146{
start:intvector{
- -4859,
- -735276032,
+ 1308,
+ 10,
+ 9,
}
}
147{
start:intvector{
- -4840,
- -1901254656,
+ 1311,
+ 4,
+ 28,
}
}
148{
start:intvector{
- -4833,
- 581741568,
+ 1312,
+ 3,
+ 20,
}
}
149{
start:intvector{
- -4798,
- -158681088,
+ 1317,
+ 2,
+ 3,
}
}
15{
start:intvector{
- -8835,
- -1337307136,
+ 767,
+ 8,
+ 16,
}
}
150{
start:intvector{
- -4781,
- 1451442176,
+ 1319,
+ 4,
+ 28,
}
}
151{
start:intvector{
- -4768,
- -1049299968,
+ 1321,
+ 2,
+ 23,
}
}
152{
start:intvector{
- -4740,
- -1644384256,
+ 1324,
+ 12,
+ 9,
}
}
153{
start:intvector{
- -4730,
- -1134857216,
+ 1326,
+ 4,
+ 26,
}
}
154{
start:intvector{
- -4705,
- 1280327680,
+ 1329,
+ 8,
+ 29,
}
}
155{
start:intvector{
- -4691,
- -1800181760,
+ 1331,
+ 8,
+ 9,
}
}
156{
start:intvector{
- -4673,
- -1003993088,
+ 1334,
+ 1,
+ 29,
}
}
157{
start:intvector{
- -4657,
- 321897472,
+ 1336,
+ 2,
+ 29,
}
}
158{
start:intvector{
- -4627,
- -1494088704,
+ 1340,
+ 4,
+ 28,
}
}
159{
start:intvector{
- -4578,
- 1003481088,
+ 1346,
+ 12,
+ 8,
}
}
16{
start:intvector{
- -8812,
- -1452754944,
+ 770,
+ 10,
+ 1,
}
}
160{
start:intvector{
- -4405,
- -775228416,
+ 1370,
+ 7,
+ 24,
}
}
161{
start:intvector{
- -4392,
- 993964032,
+ 1372,
+ 4,
+ 1,
}
}
162{
start:intvector{
- -4369,
- 1656116224,
+ 1375,
+ 5,
+ 27,
}
}
163{
start:intvector{
- -4341,
- 1925031936,
+ 1379,
+ 3,
+ 22,
}
}
164{
start:intvector{
- -4327,
- 1497889792,
+ 1381,
+ 2,
+ 10,
}
}
165{
start:intvector{
- -4304,
- -234125312,
+ 1384,
+ 4,
+ 28,
}
}
166{
start:intvector{
- -4305,
- -1209558016,
+ 1387,
+ 8,
+ 22,
}
}
167{
start:intvector{
- -4279,
- 1403459584,
+ 1387,
+ 8,
+ 23,
}
}
168{
start:intvector{
- -4268,
- 469219328,
+ 1389,
+ 2,
+ 9,
}
}
169{
start:intvector{
- -4260,
- 1533480960,
+ 1390,
+ 3,
+ 26,
}
}
17{
start:intvector{
- -8737,
- -7302144,
+ 781,
+ 1,
+ 1,
}
}
170{
start:intvector{
- -4229,
- -948672512,
+ 1394,
+ 7,
+ 5,
}
}
171{
start:intvector{
- -3980,
- 939438080,
+ 1428,
+ 4,
+ 27,
}
}
172{
start:intvector{
- -3970,
- 844165120,
+ 1429,
+ 9,
+ 5,
}
}
173{
start:intvector{
- -3886,
- 1478112256,
+ 1441,
+ 2,
+ 17,
}
}
174{
start:intvector{
- -3864,
- 560031744,
+ 1444,
+ 2,
+ 5,
}
}
175{
start:intvector{
- -3824,
- 1561339904,
+ 1449,
+ 7,
+ 28,
}
}
176{
start:intvector{
- -3802,
- 1507259392,
+ 1452,
+ 7,
+ 25,
}
}
177{
start:intvector{
- -3780,
- 1625978880,
+ 1455,
+ 7,
+ 25,
}
}
178{
start:intvector{
- -3764,
- 1680902144,
+ 1457,
+ 9,
+ 28,
}
}
179{
start:intvector{
- -3740,
- 553687040,
+ 1460,
+ 12,
+ 21,
}
}
18{
start:intvector{
- -8725,
- -138909696,
+ 782,
+ 8,
+ 19,
}
}
180{
start:intvector{
- -3702,
- 1072929792,
+ 1466,
+ 2,
+ 28,
}
}
181{
start:intvector{
- -3695,
- -1491608576,
+ 1467,
+ 3,
+ 3,
}
}
182{
start:intvector{
- -3679,
- 2080681984,
+ 1469,
+ 4,
+ 28,
}
}
183{
start:intvector{
- -3545,
- -1797502976,
+ 1487,
+ 7,
+ 29,
}
}
184{
start:intvector{
- -3530,
- -1076412416,
+ 1489,
+ 8,
+ 21,
}
}
185{
start:intvector{
- -3508,
- 572474368,
+ 1492,
+ 7,
+ 19,
}
}
186{
start:intvector{
- -3445,
- 1890334720,
+ 1501,
+ 2,
+ 29,
}
}
187{
start:intvector{
- -3423,
- 2095454208,
+ 1504,
+ 2,
+ 30,
}
}
188{
start:intvector{
- -3295,
- -377726976,
+ 1521,
+ 8,
+ 23,
}
}
189{
start:intvector{
- -3243,
- 1244540928,
+ 1528,
+ 8,
+ 20,
}
}
19{
start:intvector{
- -8550,
- 1883980800,
+ 806,
+ 5,
+ 18,
}
}
190{
start:intvector{
- -3214,
- 1020089344,
+ 1532,
+ 7,
+ 29,
}
}
191{
start:intvector{
- -3044,
- -228918272,
+ 1555,
+ 10,
+ 23,
}
}
192{
start:intvector{
- -3026,
- 974237696,
+ 1558,
+ 2,
+ 28,
}
}
193{
start:intvector{
- -2937,
- 2078948352,
+ 1570,
+ 4,
+ 23,
}
}
194{
start:intvector{
- -2913,
- 1988533248,
+ 1573,
+ 7,
+ 28,
}
}
195{
start:intvector{
- -2771,
- -1948590080,
+ 1592,
+ 12,
+ 8,
}
}
196{
start:intvector{
- -2742,
- 393925632,
+ 1596,
+ 10,
+ 27,
}
}
197{
start:intvector{
- -2605,
- -1940361216,
+ 1615,
+ 7,
+ 13,
}
}
198{
start:intvector{
- -2542,
- -17700864,
+ 1624,
+ 2,
+ 30,
}
}
199{
start:intvector{
- -2389,
- -939697152,
+ 1644,
+ 12,
+ 16,
}
}
2{
start:intvector{
- -9537,
- 418301952,
+ 672,
+ 1,
+ 1,
}
}
20{
start:intvector{
- -8518,
- 1389027328,
+ 810,
+ 9,
+ 19,
}
}
200{
start:intvector{
- -2365,
- 154455040,
+ 1648,
+ 2,
+ 15,
}
}
201{
start:intvector{
- -2332,
- -981633024,
+ 1652,
+ 9,
+ 18,
}
}
202{
start:intvector{
- -2313,
- -1629211648,
+ 1655,
+ 4,
+ 13,
}
}
203{
start:intvector{
- -2289,
- -1287626752,
+ 1658,
+ 7,
+ 23,
}
}
204{
start:intvector{
- -2269,
- -182172672,
+ 1661,
+ 4,
+ 25,
}
}
205{
start:intvector{
- -2177,
- 540603392,
+ 1673,
+ 9,
+ 21,
}
}
206{
start:intvector{
- -2118,
- 289532928,
+ 1681,
+ 9,
+ 29,
}
}
207{
start:intvector{
- -2101,
- -1419878400,
+ 1684,
+ 2,
+ 21,
}
}
208{
start:intvector{
- -2067,
- -2037566464,
+ 1688,
+ 9,
+ 30,
}
}
209{
start:intvector{
- -1953,
- 99929088,
+ 1704,
+ 3,
+ 13,
}
}
21{
start:intvector{
- -8420,
- 40632320,
+ 824,
+ 1,
+ 5,
}
}
210{
start:intvector{
- -1901,
- 1315229696,
+ 1711,
+ 4,
+ 25,
}
}
211{
start:intvector{
- -1863,
- 970472448,
+ 1716,
+ 6,
+ 22,
}
}
212{
start:intvector{
- -1717,
- 305247232,
+ 1736,
+ 4,
+ 28,
}
}
213{
start:intvector{
- -1682,
- -1731175424,
+ 1741,
+ 2,
+ 27,
}
}
214{
start:intvector{
- -1660,
- -2130855936,
+ 1744,
+ 2,
+ 21,
}
}
215{
start:intvector{
- -1628,
- -1070609408,
+ 1748,
+ 7,
+ 12,
}
}
216{
start:intvector{
- -1604,
- -297024512,
+ 1751,
+ 10,
+ 27,
}
}
217{
start:intvector{
- -1511,
- -2116183040,
+ 1764,
+ 6,
+ 2,
}
}
218{
start:intvector{
- -1449,
- -1514555392,
+ 1772,
+ 11,
+ 16,
}
}
219{
start:intvector{
- -1387,
- 790039552,
+ 1781,
+ 4,
+ 2,
}
}
22{
start:intvector{
- -8347,
- 1954419712,
+ 834,
+ 1,
+ 3,
}
}
220{
start:intvector{
- -1330,
- -1646063616,
+ 1789,
+ 1,
+ 25,
}
}
221{
start:intvector{
- -1242,
- -47985664,
+ 1801,
+ 2,
+ 5,
}
}
222{
start:intvector{
- -1219,
- 589133824,
+ 1804,
+ 2,
+ 11,
}
}
223{
start:intvector{
- -1115,
- 1810135040,
+ 1818,
+ 4,
+ 22,
}
}
224{
start:intvector{
- -1022,
- 1114176512,
+ 1830,
+ 12,
+ 10,
}
}
225{
start:intvector{
- -920,
- -109054976,
+ 1844,
+ 12,
+ 2,
}
}
226{
start:intvector{
- -896,
- -977070080,
+ 1848,
+ 2,
+ 28,
}
}
227{
start:intvector{
- -846,
- 1459132416,
+ 1854,
+ 11,
+ 27,
}
}
228{
start:intvector{
- -807,
- 1398607872,
+ 1860,
+ 3,
+ 18,
}
}
229{
start:intvector{
- -800,
- 537036800,
+ 1861,
+ 2,
+ 19,
}
}
23{
start:intvector{
- -8241,
- -1847080960,
+ 848,
+ 6,
+ 13,
}
}
230{
start:intvector{
- -778,
- 742156288,
+ 1864,
+ 2,
+ 20,
}
}
231{
start:intvector{
- -770,
- 1979217920,
+ 1865,
+ 4,
+ 7,
}
}
232{
start:intvector{
- -745,
- -1689931776,
+ 1868,
+ 9,
+ 8,
}
}
233{
start:intvector{
- -422,
- 322598912,
+ 1912,
+ 7,
+ 30,
}
}
234{
start:intvector{
- -317,
- -393534464,
+ 1926,
+ 12,
+ 25,
}
}
235{
start:intvector{
- 139,
- -1074621440,
+ 1989,
+ 1,
+ 8,
+ }
+ }
+ 236{
+ named{"false"}
+ start:intvector{
+ 2019,
+ 5,
+ 1,
}
}
24{
start:intvector{
- -8220,
- -1407794176,
+ 851,
+ 4,
+ 28,
}
}
25{
start:intvector{
- -8193,
- 279856128,
+ 854,
+ 11,
+ 30,
}
}
26{
start:intvector{
- -8177,
- 1889979392,
+ 857,
+ 2,
+ 21,
}
}
27{
start:intvector{
- -8161,
- 821702656,
+ 859,
+ 4,
+ 15,
}
}
28{
start:intvector{
- -8029,
- 2052419584,
+ 877,
+ 4,
+ 16,
}
}
29{
start:intvector{
- -7971,
- 739516416,
+ 885,
+ 2,
+ 21,
}
}
3{
start:intvector{
- -9431,
- -13598720,
+ 686,
+ 7,
+ 20,
}
}
30{
start:intvector{
- -7941,
- -558069760,
+ 889,
+ 4,
+ 27,
}
}
31{
start:intvector{
- -7875,
- -115511296,
+ 898,
+ 4,
+ 26,
}
}
32{
start:intvector{
- -7851,
- -1588326400,
+ 901,
+ 7,
+ 15,
}
}
33{
start:intvector{
- -7691,
- 1527873536,
+ 923,
+ 4,
+ 11,
}
}
34{
start:intvector{
- -7632,
- 1881603072,
+ 931,
+ 4,
+ 26,
}
}
35{
start:intvector{
- -7580,
- 1714503680,
+ 938,
+ 5,
+ 22,
}
}
36{
start:intvector{
- -7515,
- -348537856,
+ 947,
+ 4,
+ 22,
}
}
37{
start:intvector{
- -7437,
- 801380352,
+ 957,
+ 10,
+ 27,
}
}
38{
start:intvector{
- -7413,
- 2093365248,
+ 961,
+ 2,
+ 16,
}
}
39{
start:intvector{
- -7388,
- 1855182848,
+ 964,
+ 7,
+ 10,
}
}
4{
start:intvector{
- -9323,
- -938866688,
+ 701,
+ 3,
+ 21,
}
}
40{
start:intvector{
- -7358,
- -2120803328,
+ 968,
+ 8,
+ 13,
}
}
41{
start:intvector{
- -7346,
- 1524156416,
+ 970,
+ 3,
+ 25,
}
}
42{
start:intvector{
- -7319,
- -712527872,
+ 973,
+ 12,
+ 20,
}
}
43{
start:intvector{
- -7300,
- -1446506496,
+ 976,
+ 7,
+ 13,
}
}
44{
start:intvector{
- -7282,
- 620649472,
+ 978,
+ 11,
+ 29,
}
}
45{
start:intvector{
- -7250,
- 1248896000,
+ 983,
+ 4,
+ 15,
}
}
46{
start:intvector{
- -7235,
- 1019586560,
+ 985,
+ 4,
+ 27,
}
}
47{
start:intvector{
- -7221,
- 2061244416,
+ 987,
+ 4,
+ 5,
}
}
48{
start:intvector{
- -7204,
- -1289766912,
+ 989,
+ 8,
+ 8,
}
}
49{
start:intvector{
- -7195,
- -546072576,
+ 990,
+ 11,
+ 7,
}
}
5{
start:intvector{
- -9300,
- -708714496,
+ 704,
+ 5,
+ 10,
}
}
50{
start:intvector{
- -7163,
- 1785141248,
+ 995,
+ 2,
+ 22,
}
}
51{
start:intvector{
- -7134,
- 5489664,
+ 999,
+ 1,
+ 13,
}
}
52{
start:intvector{
- -7094,
- -1992169472,
+ 1004,
+ 7,
+ 20,
}
}
53{
start:intvector{
- -7032,
- 2126825472,
+ 1012,
+ 12,
+ 25,
}
}
54{
start:intvector{
- -7000,
- 1199872000,
+ 1017,
+ 4,
+ 23,
}
}
55{
start:intvector{
- -6972,
- 259187712,
+ 1021,
+ 2,
+ 2,
}
}
56{
start:intvector{
- -6947,
- 1489805312,
+ 1024,
+ 7,
+ 13,
}
}
57{
start:intvector{
- -6918,
- -92013568,
+ 1028,
+ 7,
+ 25,
}
}
58{
start:intvector{
- -6853,
- 818879488,
+ 1037,
+ 4,
+ 21,
}
}
59{
start:intvector{
- -6827,
- 1383329792,
+ 1040,
+ 11,
+ 10,
}
}
6{
start:intvector{
- -9273,
- -810431488,
+ 708,
+ 1,
+ 11,
}
}
60{
start:intvector{
- -6798,
- -25689088,
+ 1044,
+ 11,
+ 24,
}
}
61{
start:intvector{
- -6787,
- 743037952,
+ 1046,
+ 4,
+ 14,
}
}
62{
start:intvector{
- -6738,
- -1115726848,
+ 1053,
+ 1,
+ 11,
}
}
63{
start:intvector{
- -6696,
- 429014016,
+ 1058,
+ 8,
+ 29,
}
}
64{
start:intvector{
- -6646,
- -22318080,
+ 1065,
+ 8,
+ 2,
}
}
65{
start:intvector{
- -6618,
- 653564928,
+ 1069,
+ 4,
+ 13,
}
}
66{
start:intvector{
- -6579,
- -1973926912,
+ 1074,
+ 8,
+ 23,
}
}
67{
start:intvector{
- -6555,
- 1366625280,
+ 1077,
+ 11,
+ 17,
}
}
68{
start:intvector{
- -6531,
- 325810176,
+ 1081,
+ 2,
+ 10,
}
}
69{
start:intvector{
- -6509,
- 185329664,
+ 1084,
+ 2,
+ 7,
}
}
7{
start:intvector{
- -9217,
- -186200064,
+ 715,
+ 9,
+ 2,
}
}
70{
start:intvector{
- -6486,
- 1193081856,
+ 1087,
+ 4,
+ 7,
}
}
71{
start:intvector{
- -6430,
- -922454016,
+ 1094,
+ 12,
+ 15,
}
}
72{
start:intvector{
- -6415,
- -2015763456,
+ 1096,
+ 12,
+ 17,
}
}
73{
start:intvector{
- -6408,
- 1504032768,
+ 1097,
+ 11,
+ 21,
}
}
74{
start:intvector{
- -6395,
- 1397457920,
+ 1099,
+ 8,
+ 28,
}
}
75{
start:intvector{
- -6362,
- 236337152,
+ 1104,
+ 2,
+ 10,
}
}
76{
start:intvector{
- -6347,
- -313539584,
+ 1106,
+ 4,
+ 9,
}
}
77{
start:intvector{
- -6330,
- -147183616,
+ 1108,
+ 8,
+ 3,
}
}
78{
start:intvector{
- -6315,
- 980874240,
+ 1110,
+ 7,
+ 13,
}
}
79{
start:intvector{
- -6293,
- 1185993728,
+ 1113,
+ 7,
+ 13,
}
}
8{
start:intvector{
- -9200,
- 819123200,
+ 717,
+ 11,
+ 17,
}
}
80{
start:intvector{
- -6259,
- -97861632,
+ 1118,
+ 4,
+ 3,
}
}
81{
start:intvector{
- -6244,
- -759171072,
+ 1120,
+ 4,
+ 10,
}
}
82{
start:intvector{
- -6214,
- 312377344,
+ 1124,
+ 4,
+ 3,
}
}
83{
start:intvector{
- -6201,
- 1415402496,
+ 1126,
+ 1,
+ 22,
}
}
84{
start:intvector{
- -6164,
- 872812544,
+ 1131,
+ 1,
+ 29,
}
}
85{
start:intvector{
- -6153,
- 2012172288,
+ 1132,
+ 8,
+ 11,
}
}
86{
start:intvector{
- -6133,
- 1562426368,
+ 1135,
+ 4,
+ 27,
}
}
87{
start:intvector{
- -6088,
- -223669248,
+ 1141,
+ 7,
+ 10,
}
}
88{
start:intvector{
- -6082,
- -764673024,
+ 1142,
+ 4,
+ 28,
}
}
89{
start:intvector{
- -6068,
- 943152128,
+ 1144,
+ 2,
+ 23,
}
}
9{
start:intvector{
- -9155,
- -621372416,
+ 724,
+ 2,
+ 4,
}
}
90{
start:intvector{
- -6058,
- -1805488128,
+ 1145,
+ 7,
+ 22,
}
}
91{
start:intvector{
- -6017,
- 405420032,
+ 1151,
+ 1,
+ 26,
}
}
92{
start:intvector{
- -5990,
- -1399264256,
+ 1154,
+ 10,
+ 28,
}
}
93{
start:intvector{
- -5979,
- -1383104512,
+ 1156,
+ 4,
+ 27,
}
}
94{
start:intvector{
- -5957,
- -1869185024,
+ 1159,
+ 4,
+ 20,
}
}
95{
start:intvector{
- -5952,
- -448021504,
+ 1160,
+ 1,
+ 10,
}
}
96{
start:intvector{
- -5939,
- 111570944,
+ 1161,
+ 9,
+ 4,
}
}
97{
start:intvector{
- -5928,
- -2093636608,
+ 1163,
+ 3,
+ 29,
}
}
98{
start:intvector{
- -5912,
- -1779513344,
+ 1165,
+ 6,
+ 5,
}
}
99{
start:intvector{
- -5903,
- -1727019008,
+ 1166,
+ 8,
+ 27,
}
}
}
eras{
0{
start:intvector{
- -9905,
- -1165500416,
+ 622,
+ 1,
+ 1,
}
}
}
eras{
0{
end:intvector{
- -427,
- -727931905,
+ 1911,
+ 12,
+ 31,
}
}
1{
start:intvector{
- -427,
- -727931904,
+ 1912,
+ 1,
+ 1,
}
}
}
numparse_stringsegment.o numparse_parsednumber.o numparse_impl.o \
numparse_symbols.o numparse_decimal.o numparse_scientific.o numparse_currency.o \
numparse_affixes.o numparse_compositions.o numparse_validators.o \
+erarules.o
## Header files to install
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include <stdlib.h>
+#include "unicode/ucal.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "erarules.h"
+#include "gregoimp.h"
+#include "uassert.h"
+
+U_NAMESPACE_BEGIN
+
+static const int32_t MAX_ENCODED_START_YEAR = 32767;
+static const int32_t MIN_ENCODED_START_YEAR = -32768;
+static const int32_t MIN_ENCODED_START = -2147483391; // encodeDate(MIN_ENCODED_START_YEAR, 1, 1, ...);
+
+static const int32_t YEAR_MASK = 0xFFFF0000;
+static const int32_t MONTH_MASK = 0x0000FF00;
+static const int32_t DAY_MASK = 0x000000FF;
+
+static const int32_t MAX_INT32 = 0x7FFFFFFF;
+static const int32_t MIN_INT32 = 0xFFFFFFFF;
+
+static const UChar VAL_FALSE[] = {0x66, 0x61, 0x6c, 0x73, 0x65}; // "false"
+static const UChar VAL_FALSE_LEN = 5;
+
+static UBool isSet(int startDate) {
+ return startDate != 0;
+}
+
+static UBool isValidRuleStartDate(int32_t year, int32_t month, int32_t day) {
+ return year >= MIN_ENCODED_START_YEAR && year <= MAX_ENCODED_START_YEAR
+ && month >= 1 && month <= 12 && day >=1 && day <= 31;
+}
+
+/**
+ * Encode year/month/date to a single integer.
+ * year is high 16 bits (-32768 to 32767), month is
+ * next 8 bits and day of month is last 8 bits.
+ *
+ * @param year year
+ * @param month month (1-base)
+ * @param day day of month
+ * @return an encoded date.
+ */
+static int32_t encodeDate(int32_t year, int32_t month, int32_t day) {
+ return year << 16 | month << 8 | day;
+}
+
+static void decodeDate(int32_t encodedDate, int32_t (&fields)[3]) {
+ if (encodedDate == MIN_ENCODED_START) {
+ fields[0] = MIN_INT32;
+ fields[1] = 1;
+ fields[2] = 1;
+ } else {
+ fields[0] = (encodedDate & YEAR_MASK) >> 16;
+ fields[1] = (encodedDate & MONTH_MASK) >> 8;
+ fields[2] = encodedDate & DAY_MASK;
+ }
+}
+
+/**
+ * Compare an encoded date with another date specified by year/month/day.
+ * @param encoded An encoded date
+ * @param year Year of another date
+ * @param month Month of another date
+ * @param day Day of another date
+ * @return -1 when encoded date is earlier, 0 when two dates are same,
+ * and 1 when encoded date is later.
+ */
+static int32_t compareEncodedDateWithYMD(int encoded, int year, int month, int day) {
+ if (year < MIN_ENCODED_START_YEAR) {
+ if (encoded == MIN_ENCODED_START) {
+ if (year > MIN_INT32 || month > 1 || day > 1) {
+ return -1;
+ }
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (year > MAX_ENCODED_START_YEAR) {
+ return -1;
+ } else {
+ int tmp = encodeDate(year, month, day);
+ if (encoded < tmp) {
+ return -1;
+ } else if (encoded == tmp) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+}
+
+EraRules::EraRules(int32_t *startDates, int32_t numEras)
+ : startDates(startDates), numEras(numEras) {
+ initCurrentEra();
+}
+
+EraRules::~EraRules() {
+ uprv_free(startDates);
+}
+
+EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return nullptr;
+ }
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status));
+ ures_getByKey(rb.getAlias(), "calendarData", rb.getAlias(), &status);
+ ures_getByKey(rb.getAlias(), calType, rb.getAlias(), &status);
+ ures_getByKey(rb.getAlias(), "eras", rb.getAlias(), &status);
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ int32_t numEras = ures_getSize(rb.getAlias());
+ int32_t firstTentativeIdx = MAX_INT32;
+
+ int32_t *startDates = (int32_t*)uprv_malloc(numEras * sizeof(int32_t));
+ if (startDates == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ uprv_memset(startDates, 0, numEras * sizeof(int32_t));
+
+ while (ures_hasNext(rb.getAlias())) {
+ LocalUResourceBundlePointer eraRuleRes(ures_getNextResource(rb.getAlias(), nullptr, &status));
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ const char *eraIdxStr = ures_getKey(eraRuleRes.getAlias());
+ char *endp;
+ int32_t eraIdx = (int32_t)strtol(eraIdxStr, &endp, 10);
+ if ((size_t)(endp - eraIdxStr) != uprv_strlen(eraIdxStr)) {
+ status = U_INVALID_FORMAT_ERROR;
+ goto error;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_INVALID_FORMAT_ERROR;
+ goto error;
+ }
+ if (isSet(startDates[eraIdx])) {
+ // start date of the index was already set
+ status = U_INVALID_FORMAT_ERROR;
+ goto error;
+ }
+
+ UBool hasName = TRUE;
+ UBool hasEnd = TRUE;
+ int32_t len;
+ while (ures_hasNext(eraRuleRes.getAlias())) {
+ LocalUResourceBundlePointer res(ures_getNextResource(eraRuleRes.getAlias(), nullptr, &status));
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ const char *key = ures_getKey(res.getAlias());
+ if (uprv_strcmp(key, "start") == 0) {
+ const int32_t *fields = ures_getIntVector(res.getAlias(), &len, &status);
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ if (len != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) {
+ status = U_INVALID_FORMAT_ERROR;
+ goto error;
+ }
+ startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]);
+ } else if (uprv_strcmp(key, "named") == 0) {
+ const UChar *val = ures_getString(res.getAlias(), &len, &status);
+ if (u_strncmp(val, VAL_FALSE, VAL_FALSE_LEN) == 0) {
+ hasName = FALSE;
+ }
+ } else if (uprv_strcmp(key, "end") == 0) {
+ hasEnd = TRUE;
+ }
+ }
+
+ if (isSet(startDates[eraIdx])) {
+ if (hasEnd) {
+ // This implementation assumes either start or end is available, not both.
+ // For now, just ignore the end rule.
+ }
+ } else {
+ if (hasEnd) {
+ if (eraIdx != 0) {
+ // This implementation does not support end only rule for eras other than
+ // the first one.
+ status = U_INVALID_FORMAT_ERROR;
+ goto error;
+ }
+ U_ASSERT(eraIdx == 0);
+ startDates[eraIdx] = MIN_ENCODED_START;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ goto error;
+ }
+ }
+
+ if (hasName) {
+ if (eraIdx >= firstTentativeIdx) {
+ status = U_INVALID_FORMAT_ERROR;
+ goto error;
+ }
+ } else {
+ if (eraIdx < firstTentativeIdx) {
+ firstTentativeIdx = eraIdx;
+ }
+ }
+ }
+
+ EraRules *result;
+ if (firstTentativeIdx < MAX_INT32 && !includeTentativeEra) {
+ result = new EraRules(startDates, firstTentativeIdx);
+ } else {
+ result = new EraRules(startDates, numEras);
+ }
+
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return result;
+
+error:
+ uprv_free(startDates);
+ return nullptr;
+}
+
+void EraRules::getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const {
+ if(U_FAILURE(status)) {
+ return;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ decodeDate(startDates[eraIdx], fields);
+}
+
+int32_t EraRules::getStartYear(int32_t eraIdx, UErrorCode& status) const {
+ int year = MAX_INT32; // bogus value
+ if(U_FAILURE(status)) {
+ return year;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return year;
+ }
+ int fields[3];
+ decodeDate(startDates[eraIdx], fields);
+ year = fields[0];
+
+ return year;
+}
+
+int32_t EraRules::getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const {
+ if(U_FAILURE(status)) {
+ return -1;
+ }
+
+ if (month < 1 || month > 12 || day < 1 || day > 31) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+ int32_t high = numEras; // last index + 1
+ int32_t low;
+
+ // Short circuit for recent years. Most modern computations will
+ // occur in the last few eras.
+ if (compareEncodedDateWithYMD(startDates[getCurrentEraIndex()], year, month, day) <= 0) {
+ low = getCurrentEraIndex();
+ } else {
+ low = 0;
+ }
+
+ // Do binary search
+ while (low < high - 1) {
+ int i = (low + high) / 2;
+ if (compareEncodedDateWithYMD(startDates[i], year, month, day) <= 0) {
+ low = i;
+ } else {
+ high = i;
+ }
+ }
+ return low;
+}
+
+void EraRules::initCurrentEra() {
+ UDate now = ucal_getNow();
+ int year, month0, dom, dow, doy, mid;
+ Grego::timeToFields(now, year, month0, dom, dow, doy, mid);
+ int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom);
+ int eraIdx = numEras - 1;
+ while (eraIdx > 0) {
+ if (currentEncodedDate >= startDates[eraIdx]) {
+ break;
+ }
+ eraIdx--;
+ }
+ // Note: current era could be before the first era.
+ // In this case, this implementation returns the first era index (0).
+ currentEra = eraIdx;}
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef ERARULES_H_
+#define ERARULES_H_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+
+U_NAMESPACE_BEGIN
+
+class U_I18N_API EraRules : public UMemory {
+public:
+ ~EraRules();
+
+ static EraRules* createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status);
+
+ /**
+ * Gets number of effective eras
+ * @return number of effective eras
+ */
+ inline int32_t getNumberOfEras() const {
+ return numEras;
+ }
+
+ /**
+ * Gets start date of an era
+ * @param eraIdx Era index
+ * @param fields Receives date fields. The result includes values of year, month,
+ * day of month in this order. When an era has no start date, the result
+ * will be January 1st in year whose value is minimum integer.
+ * @param status Receives status.
+ */
+ void getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const;
+
+ /**
+ * Gets start year of an era
+ * @param eraIdx Era index
+ * @param status Receives status.
+ * @return The first year of an era. When a era has no start date, minimum int32
+ * value is returned.
+ */
+ int32_t getStartYear(int32_t eraIdx, UErrorCode& status) const;
+
+ /**
+ * Returns era index for the specified year/month/day.
+ * @param year Year
+ * @param month Month (1-base)
+ * @param day Day of month
+ * @param status Receives status
+ * @return era index (or 0, when the specified date is before the first era)
+ */
+ int32_t getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const;
+
+ /**
+ * Gets the current era index. This is calculated only once for an instance of
+ * EraRules.
+ *
+ * @return era index of current era (or 0, when current date is before the first era)
+ */
+ inline int32_t getCurrentEraIndex() const {
+ return currentEra;
+ }
+
+private:
+ EraRules(int32_t *startDates, int32_t numEra);
+
+ void initCurrentEra();
+
+ int32_t *startDates;
+ int32_t numEras;
+ int32_t currentEra;
+};
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif /* ERARULES_H_ */
</Link>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="erarules.cpp" />
<ClCompile Include="region.cpp" />
<ClCompile Include="uregion.cpp" />
<ClCompile Include="alphaindex.cpp" />
<ClInclude Include="collationtailoring.h" />
<ClInclude Include="collationweights.h" />
<ClInclude Include="dayperiodrules.h" />
+ <ClInclude Include="erarules.h" />
<ClInclude Include="numsys_impl.h" />
<ClInclude Include="region_impl.h" />
<ClInclude Include="selfmtimpl.h" />
<ClCompile Include="dayperiodrules.cpp">
<Filter>formatting</Filter>
</ClCompile>
+ <ClCompile Include="erarules.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="bocsu.cpp">
<ClInclude Include="utf8collationiterator.h">
<Filter>collation</Filter>
</ClInclude>
+ <ClInclude Include="erarules.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="i18n.rc">
<Filter>misc</Filter>
</ResourceCompile>
</ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
<CompileAsWinRT>false</CompileAsWinRT>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
- <ResourceCompile>
+ <ResourceCompile>
<Culture>0x0409</Culture>
<AdditionalIncludeDirectories>../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="erarules.cpp" />
<ClCompile Include="region.cpp" />
<ClCompile Include="uregion.cpp" />
<ClCompile Include="alphaindex.cpp" />
<ClInclude Include="collationtailoring.h" />
<ClInclude Include="collationweights.h" />
<ClInclude Include="dayperiodrules.h" />
+ <ClInclude Include="erarules.h" />
<ClInclude Include="numsys_impl.h" />
<ClInclude Include="region_impl.h" />
<ClInclude Include="selfmtimpl.h" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
+</Project>
\ No newline at end of file
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
-
+#if U_PLATFORM_HAS_WINUWP_API == 0
+#include <stdlib.h> // getenv() is not available in UWP env
+#endif
#include "cmemory.h"
+#include "erarules.h"
#include "japancal.h"
#include "unicode/gregocal.h"
#include "umutex.h"
#include "uassert.h"
-
-//#define U_DEBUG_JCAL
-
-#ifdef U_DEBUG_JCAL
-#include <stdio.h>
-#endif
+#include "ucln_in.h"
+#include "cstring.h"
+
+static icu::EraRules * gJapaneseEraRules = nullptr;
+static icu::UInitOnce gJapaneseEraRulesInitOnce = U_INITONCE_INITIALIZER;
+static int32_t gCurrentEra = 0;
+
+U_CDECL_BEGIN
+static UBool japanese_calendar_cleanup(void) {
+ if (gJapaneseEraRules) {
+ delete gJapaneseEraRules;
+ gJapaneseEraRules = nullptr;
+ }
+ gCurrentEra = 0;
+ gJapaneseEraRulesInitOnce.reset();
+ return TRUE;
+}
+U_CDECL_END
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar)
-// 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
- { 1379, 3, 22 }, // Koryaku
- { 1381, 2, 10 }, // Kowa
- { 1384, 4, 28 }, // Gench\u0169
- { 1384, 2, 27 }, // Meitoku
- { 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 UPRV_LENGTHOF(kEraInfo)
-
-/**
- * The current era, for reference.
- */
-static const int32_t kCurrentEra = (kEraCount-1); // int32_t to match the calendar field type
-
static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR
+static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
+
+// Initialize global Japanese era data
+static void U_CALLCONV initializeEras(UErrorCode &status) {
+ // Although start date of next Japanese era is planned ahead, a name of
+ // new era might not be available. This implementation allows tester to
+ // check a new era without era names by settings below (in priority order).
+ // By default, such tentative era is disabled.
+
+ // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
+ // 2. Windows registry (TBD)
+
+ UBool includeTentativeEra = FALSE;
+
+#if U_PLATFORM_HAS_WINUWP_API == 0
+ char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
+ if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) {
+ includeTentativeEra = TRUE;
+ }
+#endif
+ gJapaneseEraRules = EraRules::createInstance("japanese", includeTentativeEra, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ gCurrentEra = gJapaneseEraRules->getCurrentEraIndex();
+}
+
+static void init(UErrorCode &status) {
+ umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
+ ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
+}
/* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */
uint32_t JapaneseCalendar::getCurrentEra() {
- return kCurrentEra;
+ return gCurrentEra;
}
JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
: GregorianCalendar(aLocale, success)
{
+ init(success);
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
}
JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
: GregorianCalendar(source)
{
+ UErrorCode status = U_ZERO_ERROR;
+ init(status);
+ U_ASSERT(U_SUCCESS(status));
}
JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
int32_t month = 0;
// Find out if we are at the edge of an era
-
- if(eyear == kEraInfo[era].year) {
+ int32_t eraStart[3] = { 0,0,0 };
+ UErrorCode status = U_ZERO_ERROR;
+ gJapaneseEraRules->getStartDate(era, eraStart, status);
+ U_ASSERT(U_SUCCESS(status));
+ if(eyear == eraStart[0]) {
// Yes, we're in the first year of this era.
- return kEraInfo[era].month-1;
+ return eraStart[1] // month
+ -1; // return 0-based month
}
return month;
int32_t era = internalGetEra();
int32_t day = 1;
- if(eyear == kEraInfo[era].year) {
- if(month == (kEraInfo[era].month-1)) {
- return kEraInfo[era].day;
+ int32_t eraStart[3] = { 0,0,0 };
+ UErrorCode status = U_ZERO_ERROR;
+ gJapaneseEraRules->getStartDate(era, eraStart, status);
+ U_ASSERT(U_SUCCESS(status));
+ if(eyear == eraStart[0]) {
+ if(month == eraStart[1] - 1) {
+ return eraStart[2];
}
}
int32_t JapaneseCalendar::internalGetEra() const
{
- return internalGet(UCAL_ERA, kCurrentEra);
+ return internalGet(UCAL_ERA, gCurrentEra);
}
int32_t JapaneseCalendar::handleGetExtendedYear()
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
- year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
- } else {
- // Subtract one because year starts at 1
- year = internalGet(UCAL_YEAR) + kEraInfo[internalGetEra()].year - 1;
- }
- return year;
+ year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
+ U_ASSERT(U_SUCCESS(status));
+
+ // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
+ year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year)
+ + eraStartYear // add gregorian starting year
+ - 1; // Subtract one because year starts at 1
+ }
+ return year;
}
//Calendar::timeToFields(theTime, quick, status);
GregorianCalendar::handleComputeFields(julianDay, status);
int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
+ int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
- 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 \n", 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[era]=%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);
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, " Set ERA=%d, year=%d\n", low, year-kEraInfo[low].year+1);
-#endif
-
+ internalSet(UCAL_ERA, eraIdx);
+ internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
}
/*
if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
return 0;
}
- return kCurrentEra;
+ return gCurrentEra;
case UCAL_YEAR:
{
switch (limitType) {
return 1;
case UCAL_LIMIT_COUNT: //added to avoid warning
case UCAL_LIMIT_MAXIMUM:
- return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - kEraInfo[kCurrentEra].year;
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
+ U_ASSERT(U_SUCCESS(status));
+ return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
+ }
default:
return 1; // Error condition, invalid limitType
}
if (U_FAILURE(status)) {
return 0; // error case... any value
}
- if (era == kCurrentEra) {
+ if (era == gCurrentEra) {
// TODO: Investigate what value should be used here - revisit after 4.0.
return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
} else {
- int32_t nextEraYear = kEraInfo[era + 1].year;
- int32_t nextEraMonth = kEraInfo[era + 1].month;
- int32_t nextEraDate = kEraInfo[era + 1].day;
-
- int32_t maxYear = nextEraYear - kEraInfo[era].year + 1; // 1-base
+ int32_t nextEraStart[3] = { 0,0,0 };
+ gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
+ int32_t nextEraYear = nextEraStart[0];
+ int32_t nextEraMonth = nextEraStart[1]; // 1-base
+ int32_t nextEraDate = nextEraStart[2];
+
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
+ int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base
if (nextEraMonth == 1 && nextEraDate == 1) {
// Subtract 1, because the next era starts at Jan 1
maxYear--;
* July 30, 1912 (Taisho), December 25, 1926 (Showa), and January 7, 1989 (Heisei). Constants
* for these eras, suitable for use in the <code>UCAL_ERA</code> field, are provided
* in this class. Note that the <em>number</em> 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.
+ * less arbitrary. Currently, the era starting in 645 AD is era #0; however this
+ * may change in the future. Use the predefined constants rather than using actual,
+ * absolute numbers.
* <p>
+ * Since ICU4C 63, start date of each era is imported from CLDR. CLDR era data
+ * may contain tentative era in near future with placeholder names. By default,
+ * such era data is not enabled. ICU4C users who want to test the behavior of
+ * the future era can enable this one of following settings (in the priority
+ * order):
+ * <ol>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * </nl>
* @internal
*/
class JapaneseCalendar : public GregorianCalendar {
UCLN_I18N_SPOOFDATA,
UCLN_I18N_TRANSLITERATOR,
UCLN_I18N_REGEX,
+ UCLN_I18N_JAPANESE_CALENDAR,
UCLN_I18N_ISLAMIC_CALENDAR,
UCLN_I18N_CHINESE_CALENDAR,
UCLN_I18N_HEBREW_CALENDAR,
* to ~5,800,000 CE. Programmers should use the protected constants in `Calendar` to
* specify an extremely early or extremely late date.
*
+ * <p>
+ * The Japanese calendar uses a combination of era name and year number.
+ * When an emperor of Japan abdicates and a new emperor ascends the throne,
+ * a new era is declared and year number is reset to 1. Even if the date of
+ * abdication is scheduled ahead of time, the new era name might not be
+ * announced until just before the date. In such case, ICU4C may include
+ * a start date of future era without actual era name, but not enabled
+ * by default. ICU4C users who want to test the behavior of the future era
+ * can enable the tentative era by:
+ * <ul>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * </ul>
+ *
* @stable ICU 2.0
*/
class U_I18N_API Calendar : public UObject {
* For example, subtracting 5 days from the date <code>September 12, 1996</code>
* results in <code>September 7, 1996</code>.
*
+ * <p>
+ * The Japanese calendar uses a combination of era name and year number.
+ * When an emperor of Japan abdicates and a new emperor ascends the throne,
+ * a new era is declared and year number is reset to 1. Even if the date of
+ * abdication is scheduled ahead of time, the new era name might not be
+ * announced until just before the date. In such case, ICU4C may include
+ * a start date of future era without actual era name, but not enabled
+ * by default. ICU4C users who want to test the behavior of the future era
+ * can enable the tentative era by:
+ * <ul>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * </ul>
+ *
* @stable ICU 2.0
*/
numbertest_modifiers.o numbertest_patternmodifier.o numbertest_patternstring.o \
numbertest_stringbuilder.o numbertest_stringsegment.o \
numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
-static_unisets_test.o numfmtdatadriventest.o
+static_unisets_test.o numfmtdatadriventest.o erarulestest.o
DEPS = $(OBJECTS:.o=.d)
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/localpointer.h"
+#include "unicode/unistr.h"
+#include "erarules.h"
+#include "erarulestest.h"
+
+void EraRulesTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/)
+{
+ if (exec) {
+ logln("TestSuite EraRulesTest");
+ }
+ TESTCASE_AUTO_BEGIN;
+ TESTCASE_AUTO(testAPIs);
+ TESTCASE_AUTO(testJapanese);
+ TESTCASE_AUTO_END;
+}
+
+void EraRulesTest::testAPIs() {
+ const char * calTypes[] = {
+ "gregorian",
+ //"iso8601",
+ "buddhist",
+ "chinese",
+ "coptic",
+ "dangi",
+ "ethiopic",
+ "ethiopic-amete-alem",
+ "hebrew",
+ "indian",
+ "islamic",
+ "islamic-civil",
+ "islamic-rgsa",
+ "islamic-tbla",
+ "islamic-umalqura",
+ "japanese",
+ "persian",
+ "roc",
+ //"unknown",
+ NULL
+ };
+
+ for (int32_t i = 0; calTypes[i] != NULL; i++) {
+ UErrorCode status = U_ZERO_ERROR;
+ const char *calId = calTypes[i];
+
+ LocalPointer<EraRules> rules1(EraRules::createInstance(calId, FALSE, status));
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("Era rules for ") + calId + " is not available.");
+ continue;
+ }
+
+ LocalPointer<EraRules> rules2(EraRules::createInstance(calId, TRUE, status));
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("Era rules for ") + calId + " (including tentative eras) is not available.");
+ continue;
+ }
+
+ int32_t numEras1 = rules1->getNumberOfEras();
+ if (numEras1 <= 0) {
+ errln(UnicodeString("Number of era rules for ") + calId + " is " + numEras1);
+ }
+
+ int32_t numEras2 = rules2->getNumberOfEras();
+ if (numEras2 < numEras1) {
+ errln(UnicodeString("Number of era including tentative eras is fewer than one without tentative eras in calendar: ")
+ + calId);
+ }
+
+ LocalPointer<Calendar> cal(Calendar::createInstance("en", status));
+ if (U_FAILURE(status)) {
+ errln("Failed to create a Calendar instance.");
+ continue;
+ }
+ int32_t currentIdx = rules1->getCurrentEraIndex();
+ int32_t currentYear = cal->get(UCAL_YEAR, status);
+ int32_t idx = rules1->getEraIndex(
+ currentYear, cal->get(UCAL_MONTH, status) + 1,
+ cal->get(UCAL_DATE, status), status);
+ if (U_FAILURE(status)) {
+ errln("Error while getting index of era.");
+ continue;
+ }
+ if (idx != currentIdx) {
+ errln(UnicodeString("Current era index:") + currentIdx + " is different from era index of now:" + idx
+ + " in calendar:" + calId);
+ }
+
+ int32_t eraStartYear = rules1->getStartYear(currentIdx, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("Failed to get the start year of era index: ") + currentIdx + " in calendar: " + calId);
+ }
+ if (currentYear < eraStartYear) {
+ errln(UnicodeString("Current era's start year is after the current year in calendar:") + calId);
+ }
+ }
+}
+
+void EraRulesTest::testJapanese() {
+ const int32_t HEISEI = 235; // ICU4C does not define constants for eras
+
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<EraRules> rules(EraRules::createInstance("japanese", TRUE, status));
+ if (U_FAILURE(status)) {
+ errln("Failed to get era rules for Japanese calendar.");
+ return;
+ }
+ // Rules should have an era after Heisei
+ int32_t numRules = rules->getNumberOfEras();
+ if (numRules <= HEISEI) {
+ errln("Era after Heisei is not available.");
+ return;
+ }
+ int postHeiseiStartYear = rules->getStartYear(HEISEI + 1, status);
+ if (U_FAILURE(status)) {
+ errln("Failed to get the start year of era after Heisei.");
+ }
+ if (postHeiseiStartYear != 2019) {
+ errln(UnicodeString("Era after Heisei should start in 2019, but got ") + postHeiseiStartYear);
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef ERARULESTEST_H_
+#define ERARULESTEST_H_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+class EraRulesTest : public IntlTest {
+public:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL);
+
+private:
+ void testAPIs();
+ void testJapanese();
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif /* ERARULESTEST_H_ */
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- The following import will include the 'default' configuration options for VS projects. -->
<Import Project="..\..\allinone\Build.Windows.ProjectConfiguration.props" />
-
<PropertyGroup Label="Globals">
<ProjectGuid>{73632960-B3A6-464D-83A3-4B43365F19B8}</ProjectGuid>
<RootNamespace>intltest</RootNamespace>
<ClCompile Include="colldata.cpp">
<DisableLanguageExtensions>false</DisableLanguageExtensions>
</ClCompile>
+ <ClCompile Include="erarulestest.cpp" />
<ClCompile Include="numfmtspectest.cpp" />
<ClCompile Include="regiontst.cpp" />
<ClCompile Include="ucharstrietest.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="colldata.h" />
+ <ClInclude Include="erarulestest.h" />
<ClInclude Include="itrbbi.h" />
<ClInclude Include="rbbiapts.h" />
<ClInclude Include="rbbitst.h" />
</ClCompile>
<ClCompile Include="rbbimonkeytest.cpp">
<Filter>break iteration</Filter>
- </ClCompile>
+ </ClCompile>
<ClCompile Include="itspoof.cpp">
<Filter>spoof detection</Filter>
</ClCompile>
<ClCompile Include="ucharstrietest.cpp">
<Filter>data & memory</Filter>
</ClCompile>
+ <ClCompile Include="erarulestest.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="itrbbi.h">
<ClInclude Include="listformattertest.h">
<Filter>formatting</Filter>
</ClInclude>
+ <ClInclude Include="erarulestest.h">
+ <Filter>formatting</Filter>
+ </ClInclude>
</ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
#include "listformattertest.h" // ListFormatterTest
#include "regiontst.h" // RegionTest
#include "numbertest.h" // NumberTest
+#include "erarulestest.h" // EraRulesTest
extern IntlTest *createCompactDecimalFormatTest();
extern IntlTest *createGenderInfoTest();
break;
TESTCLASS(50,NumberFormatDataDrivenTest);
TESTCLASS(51,NumberTest);
+ TESTCLASS(52,EraRulesTest);
default: name = ""; break; //needed to end loop
}
if (exec) {
"",
"",
"",
+ "",
}
wide{
"",
"",
"",
"",
+ "",
}
narrow{
"",
"",
"",
"",
+ "",
}
}
intervalFormats{
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl;
+
+/**
+ * Calendar type enum, moved from com.ibm.icu.util.Calendar.
+ *
+ * @author Yoshito Umaoka
+ */
+public enum CalType {
+ GREGORIAN("gregorian"),
+ ISO8601("iso8601"),
+
+ BUDDHIST("buddhist"),
+ CHINESE("chinese"),
+ COPTIC("coptic"),
+ DANGI("dangi"),
+ ETHIOPIC("ethiopic"),
+ ETHIOPIC_AMETE_ALEM("ethiopic-amete-alem"),
+ HEBREW("hebrew"),
+ INDIAN("indian"),
+ ISLAMIC("islamic"),
+ ISLAMIC_CIVIL("islamic-civil"),
+ ISLAMIC_RGSA("islamic-rgsa"),
+ ISLAMIC_TBLA("islamic-tbla"),
+ ISLAMIC_UMALQURA("islamic-umalqura"),
+ JAPANESE("japanese"),
+ PERSIAN("persian"),
+ ROC("roc"),
+
+ UNKNOWN("unknown");
+
+ String id;
+
+ CalType(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+}
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl;
+
+import java.util.Arrays;
+
+import com.ibm.icu.util.ICUException;
+import com.ibm.icu.util.UResourceBundle;
+import com.ibm.icu.util.UResourceBundleIterator;
+
+/**
+ * <code>EraRules</code> represents calendar era rules specified
+ * in supplementalData/calendarData.
+ *
+ * @author Yoshito Umaoka
+ */
+public class EraRules {
+ private static final int MAX_ENCODED_START_YEAR = 32767;
+ private static final int MIN_ENCODED_START_YEAR = -32768;
+
+ public static final int MIN_ENCODED_START = encodeDate(MIN_ENCODED_START_YEAR, 1, 1);
+
+ private static final int YEAR_MASK = 0xFFFF0000;
+ private static final int MONTH_MASK = 0x0000FF00;
+ private static final int DAY_MASK = 0x000000FF;
+
+ private int[] startDates;
+ private int numEras;
+ private int currentEra;
+
+ private EraRules(int[] startDates, int numEras) {
+ this.startDates = startDates;
+ this.numEras = numEras;
+ initCurrentEra();
+ }
+
+ public static EraRules getInstance(CalType calType, boolean includeTentativeEra) {
+ UResourceBundle supplementalDataRes = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME,
+ "supplementalData", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
+ UResourceBundle calendarDataRes = supplementalDataRes.get("calendarData");
+ UResourceBundle calendarTypeRes = calendarDataRes.get(calType.getId());
+ UResourceBundle erasRes = calendarTypeRes.get("eras");
+
+ int numEras = erasRes.getSize();
+ int firstTentativeIdx = Integer.MAX_VALUE; // first tentative era index
+ int[] startDates = new int[numEras];
+
+ UResourceBundleIterator itr = erasRes.getIterator();
+ while (itr.hasNext()) {
+ UResourceBundle eraRuleRes = itr.next();
+ String eraIdxStr = eraRuleRes.getKey();
+ int eraIdx = -1;
+ try {
+ eraIdx = Integer.parseInt(eraIdxStr);
+ } catch (NumberFormatException e) {
+ throw new ICUException("Invald era rule key:" + eraIdxStr + " in era rule data for " + calType.getId());
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ throw new ICUException("Era rule key:" + eraIdxStr + " in era rule data for " + calType.getId()
+ + " must be in range [0, " + (numEras - 1) + "]");
+ }
+ if (isSet(startDates[eraIdx])) {
+ throw new ICUException(
+ "Dupulicated era rule for rule key:" + eraIdxStr + " in era rule data for " + calType.getId());
+ }
+
+ boolean hasName = true;
+ boolean hasEnd = false;
+ UResourceBundleIterator ruleItr = eraRuleRes.getIterator();
+ while (ruleItr.hasNext()) {
+ UResourceBundle res = ruleItr.next();
+ String key = res.getKey();
+ if (key.equals("start")) {
+ int[] fields = res.getIntVector();
+ if (fields.length != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) {
+ throw new ICUException(
+ "Invalid era rule date data:" + Arrays.toString(fields) + " in era rule data for "
+ + calType.getId());
+ }
+ startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]);
+ } else if (key.equals("named")) {
+ String val = res.getString();
+ if (val.equals("false")) {
+ hasName = false;
+ }
+ } else if (key.equals("end")) {
+ hasEnd = true;
+ }
+ }
+ if (isSet(startDates[eraIdx])) {
+ if (hasEnd) {
+ // This implementation assumes either start or end is available, not both.
+ // For now, just ignore the end rule.
+ }
+ } else {
+ if (hasEnd) {
+ if (eraIdx != 0) {
+ // This implementation does not support end only rule for eras other than
+ // the first one.
+ throw new ICUException(
+ "Era data for " + eraIdxStr + " in era rule data for " + calType.getId()
+ + " has only end rule.");
+ }
+ startDates[eraIdx] = MIN_ENCODED_START;
+ } else {
+ throw new ICUException("Missing era start/end rule date for key:" + eraIdxStr + " in era rule data for "
+ + calType.getId());
+ }
+ }
+
+ if (hasName) {
+ if (eraIdx >= firstTentativeIdx) {
+ throw new ICUException(
+ "Non-tentative era(" + eraIdx + ") must be placed before the first tentative era");
+ }
+ } else {
+ if (eraIdx < firstTentativeIdx) {
+ firstTentativeIdx = eraIdx;
+ }
+ }
+ }
+
+ if (firstTentativeIdx < Integer.MAX_VALUE && !includeTentativeEra) {
+ return new EraRules(startDates, firstTentativeIdx);
+ }
+
+ return new EraRules(startDates, numEras);
+ }
+
+ /**
+ * Gets number of effective eras
+ * @return number of effective eras
+ */
+ public int getNumberOfEras() {
+ return numEras;
+ }
+
+ /**
+ * Gets start date of an era
+ * @param eraIdx Era index
+ * @param fillIn Receives date fields if supplied. If null, or size of array
+ * is less than 3, then a new int[] will be newly allocated.
+ * @return An int array including values of year, month, day of month in this order.
+ * When an era has no start date, the result will be January 1st in year
+ * whose value is minimum integer.
+ */
+ public int[] getStartDate(int eraIdx, int[] fillIn) {
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ throw new IllegalArgumentException("eraIdx is out of range");
+ }
+ return decodeDate(startDates[eraIdx], fillIn);
+ }
+
+ /**
+ * Gets start year of an era
+ * @param eraIdx Era index
+ * @return The first year of an era. When a era has no start date, minimum integer
+ * value is returned.
+ */
+ public int getStartYear(int eraIdx) {
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ throw new IllegalArgumentException("eraIdx is out of range");
+ }
+ int[] fields = decodeDate(startDates[eraIdx], null);
+ return fields[0];
+ }
+
+ /**
+ * Returns era index for the specified year/month/day.
+ * @param year Year
+ * @param month Month (1-base)
+ * @param day Day of month
+ * @return era index (or 0, when the specified date is before the first era)
+ */
+ public int getEraIndex(int year, int month, int day) {
+ if (month < 1 || month > 12 || day < 1 || day > 31) {
+ throw new IllegalArgumentException("Illegal date - year:" + year + "month:" + month + "day:" + day);
+ }
+ int high = numEras; // last index + 1
+ int low;
+
+ // Short circuit for recent years. Most modern computations will
+ // occur in the last few eras.
+ if (compareEncodedDateWithYMD(startDates[getCurrentEraIndex()], year, month, day) <= 0) {
+ low = getCurrentEraIndex();
+ } else {
+ low = 0;
+ }
+
+ // Do binary search
+ while (low < high - 1) {
+ int i = (low + high) / 2;
+ if (compareEncodedDateWithYMD(startDates[i], year, month, day) <= 0) {
+ low = i;
+ } else {
+ high = i;
+ }
+ }
+ return low;
+ }
+
+ /**
+ * Gets the current era index. This is calculated only once for an instance of
+ * EraRules.
+ *
+ * @return era index of current era (or 0, when current date is before the first era)
+ */
+ public int getCurrentEraIndex() {
+ return currentEra;
+ }
+
+ private void initCurrentEra() {
+ int[] fields = Grego.timeToFields(System.currentTimeMillis(), null);
+ int currentEncodedDate = encodeDate(fields[0], fields[1] + 1 /* changes to 1-base */, fields[2]);
+ int eraIdx = numEras - 1;
+ while (eraIdx > 0) {
+ if (currentEncodedDate >= startDates[eraIdx]) {
+ break;
+ }
+ eraIdx--;
+ }
+ // Note: current era could be before the first era.
+ // In this case, this implementation returns the first era index (0).
+ currentEra = eraIdx;
+ }
+
+ //
+ // private methods
+ //
+
+ private static boolean isSet(int startDate) {
+ return startDate != 0;
+ }
+
+ private static boolean isValidRuleStartDate(int year, int month, int day) {
+ return year >= MIN_ENCODED_START_YEAR && year <= MAX_ENCODED_START_YEAR
+ && month >= 1 && month <= 12 && day >= 1 && day <= 31;
+ }
+
+ /**
+ * Encode year/month/date to a single integer.
+ * year is high 16 bits (-32768 to 32767), month is
+ * next 8 bits and day of month is last 8 bits.
+ *
+ * @param year year
+ * @param month month (1-base)
+ * @param day day of month
+ * @return an encoded date.
+ */
+ private static int encodeDate(int year, int month, int day) {
+ return year << 16 | month << 8 | day;
+ }
+
+ private static int[] decodeDate(int encodedDate, int[] fillIn) {
+ int year, month, day;
+ if (encodedDate == MIN_ENCODED_START) {
+ year = Integer.MIN_VALUE;
+ month = 1;
+ day = 1;
+ } else {
+ year = (encodedDate & YEAR_MASK) >> 16;
+ month = (encodedDate & MONTH_MASK) >> 8;
+ day = encodedDate & DAY_MASK;
+ }
+
+ if (fillIn != null && fillIn.length >= 3) {
+ fillIn[0] = year;
+ fillIn[1] = month;
+ fillIn[2] = day;
+ return fillIn;
+ }
+
+ int[] result = {year, month, day};
+ return result;
+ }
+
+ /**
+ * Compare an encoded date with another date specified by year/month/day.
+ * @param encoded An encoded date
+ * @param year Year of another date
+ * @param month Month of another date
+ * @param day Day of another date
+ * @return -1 when encoded date is earlier, 0 when two dates are same,
+ * and 1 when encoded date is later.
+ */
+ private static int compareEncodedDateWithYMD(int encoded, int year, int month, int day) {
+ if (year < MIN_ENCODED_START_YEAR) {
+ if (encoded == MIN_ENCODED_START) {
+ if (year > Integer.MIN_VALUE || month > 1 || day > 1) {
+ return -1;
+ }
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (year > MAX_ENCODED_START_YEAR) {
+ return -1;
+ } else {
+ int tmp = encodeDate(year, month, day);
+ if (encoded < tmp) {
+ return -1;
+ } else if (encoded == tmp) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ }
+}
\ No newline at end of file
import java.util.Locale;
import java.util.MissingResourceException;
+import com.ibm.icu.impl.CalType;
import com.ibm.icu.impl.CalendarUtil;
import com.ibm.icu.impl.ICUCache;
import com.ibm.icu.impl.ICUData;
return region;
}
- private enum CalType {
- GREGORIAN("gregorian"),
- ISO8601("iso8601"),
-
- BUDDHIST("buddhist"),
- CHINESE("chinese"),
- COPTIC("coptic"),
- DANGI("dangi"),
- ETHIOPIC("ethiopic"),
- ETHIOPIC_AMETE_ALEM("ethiopic-amete-alem"),
- HEBREW("hebrew"),
- INDIAN("indian"),
- ISLAMIC("islamic"),
- ISLAMIC_CIVIL("islamic-civil"),
- ISLAMIC_RGSA("islamic-rgsa"),
- ISLAMIC_TBLA("islamic-tbla"),
- ISLAMIC_UMALQURA("islamic-umalqura"),
- JAPANESE("japanese"),
- PERSIAN("persian"),
- ROC("roc"),
-
- UNKNOWN("unknown");
-
- String id;
-
- CalType(String id) {
- this.id = id;
- }
- }
-
private static CalType getCalendarTypeForLocale(ULocale l) {
String s = CalendarUtil.getCalendarType(l);
if (s != null) {
s = s.toLowerCase(Locale.ENGLISH);
for (CalType type : CalType.values()) {
- if (s.equals(type.id)) {
+ if (s.equals(type.getId())) {
return type;
}
}
String prefRegion = ULocale.getRegionForSupplementalData(locale, true);
// Read preferred calendar values from supplementalData calendarPreferences
- ArrayList<String> values = new ArrayList<String>();
+ ArrayList<String> values = new ArrayList<>();
UResourceBundle rb = UResourceBundle.getBundleInstance(
ICUData.ICU_BASE_NAME,
}
// then, add other available clanedars
for (CalType t : CalType.values()) {
- if (!values.contains(t.id)) {
- values.add(t.id);
+ if (!values.contains(t.getId())) {
+ values.add(t.getId());
}
}
return values.toArray(new String[values.size()]);
CalType type = CalType.GREGORIAN;
String typeString = getType();
for (CalType testType : CalType.values()) {
- if (typeString.equals(testType.id)) {
+ if (typeString.equals(testType.getId())) {
type = testType;
break;
}
CalType type = CalType.GREGORIAN;
String typeString = getType();
for (CalType testType : CalType.values()) {
- if (typeString.equals(testType.id)) {
+ if (typeString.equals(testType.getId())) {
type = testType;
break;
}
// date format pattern cache
private static final ICUCache<String, PatternData> PATTERN_CACHE =
- new SimpleCache<String, PatternData>();
+ new SimpleCache<>();
// final fallback patterns
private static final String[] DEFAULT_PATTERNS = {
"HH:mm:ss z",
import java.util.Date;
import java.util.Locale;
+import com.ibm.icu.impl.CalType;
+import com.ibm.icu.impl.EraRules;
+
/**
* <code>JapaneseCalendar</code> is a subclass of <code>GregorianCalendar</code>
* that numbers years and eras based on the reigns of the Japanese emperors.
* 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.
+ * mode either form of date is acceptable as input.
* <p>
* 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 <code>ERA</code> field, are provided
* in this class. Note that the <em>number</em> 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.
+ * less arbitrary. Currently, the era starting in 645 AD is era #0; however this
+ * may change in the future. Use the predefined constants rather than using actual,
+ * absolute numbers.
+ * <p>
+ * Since ICU4J 63, start date of each era is imported from CLDR. CLDR era data
+ * may contain tentative era in near future with placeholder names. By default,
+ * such era data is not enabled. ICU4J users who want to test the behavior of
+ * the future era can enable this by one of following settings (in the priority
+ * order):
+ * <ol>
+ * <li>Java system property <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * <li>Java system property <code>jdk.calendar.japanese.supplemental.era=xxx</code>.
+ * (Note: This configuration is used for specifying a new era's start date and
+ * names in OpenJDK. ICU4J implementation enables the CLDR tentative era when
+ * this property is defined, but it does not use the start date and names specified
+ * by the property value.)</li>
+ * </nl>
* <p>
* This class should not be subclassed.</p>
* <p>
- * JapaneseCalendar usually should be instantiated using
+ * JapaneseCalendar usually should be instantiated using
* {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
* with the tag <code>"@calendar=japanese"</code>.</p>
*
// Use 1970 as the default value of EXTENDED_YEAR
private static final int GREGORIAN_EPOCH = 1970;
+ private static final EraRules ERA_RULES;
+
+ static {
+ // Although start date of next Japanese era is planned ahead, a name of
+ // new era might not be available. This implementation allows tester to
+ // check a new era without era names by settings below (in priority order).
+ // By default, such tentative era is disabled.
+ //
+ // 1. System property ICU_ENABLE_TENTATIVE_ERA=true or false
+ // 2. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
+ // 3. Java system property - jdk.calendar.japanese.supplemental.era for Japanese
+ //
+ // Note: Java system property specifies the start date of new Japanese era,
+ // but this implementation always uses the date read from ICU data.
+
+ boolean includeTentativeEra = false;
+
+ final String VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
+
+ String eraConf = System.getProperty(VAR_NAME);
+ if (eraConf == null) {
+ eraConf = System.getenv(VAR_NAME);
+ }
+
+ if (eraConf != null) {
+ includeTentativeEra = eraConf.equalsIgnoreCase("true");
+ } else {
+ String jdkEraConf = System.getProperty("jdk.calendar.japanese.supplemental.era");
+ includeTentativeEra = jdkEraConf != null;
+ }
+
+ ERA_RULES = EraRules.getInstance(CalType.JAPANESE, includeTentativeEra);
+ }
+
/**
* @stable ICU 2.8
*/
+ @Override
protected int handleGetExtendedYear() {
// EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
// The default value of EXTENDED_YEAR is 1970 (Showa 45)
newerField(EXTENDED_YEAR, ERA) == EXTENDED_YEAR) {
year = internalGet(EXTENDED_YEAR, GREGORIAN_EPOCH);
} else {
- // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
- year = internalGet(YEAR, 1) // pin to minimum of year 1 (first year)
- + ERAS[internalGet(ERA, CURRENT_ERA) * 3] // add gregorian starting year
- - 1; // Subtract one because year starts at 1
+ // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
+ year = internalGet(YEAR, 1) // pin to minimum of year 1 (first year)
+ + ERA_RULES.getStartYear(internalGet(ERA, CURRENT_ERA)) // add gregorian starting year
+ - 1; // Subtract one because year starts at 1
}
return year;
}
-
+
/**
* Called by handleComputeJulianDay. Returns the default month (0-based) for the year,
* taking year and era into account. Defaults to 0 (JANUARY) for Gregorian.
* @draft ICU 3.6 (retain)
* @see #MONTH
*/
- protected int getDefaultMonthInYear(int extendedYear)
- {
- int era = internalGet(ERA, CURRENT_ERA);
- //computeFields(status); // No need to compute fields here - expect the caller already did so.
-
- // Find out if we are at the edge of an era
- if(extendedYear == ERAS[era*3]) {
- return ERAS[(era*3)+1] // month..
- -1; // return 0-based month
- } else {
- return super.getDefaultMonthInYear(extendedYear);
- }
+ @Override
+ protected int getDefaultMonthInYear(int extendedYear) {
+ int era = internalGet(ERA, CURRENT_ERA);
+ // computeFields(status); // No need to compute fields here - expect the caller already did so.
+
+ // Find out if we are at the edge of an era
+ int[] eraStart = ERA_RULES.getStartDate(era, null);
+ if (extendedYear == eraStart[0]) {
+ return eraStart[1] // month..
+ - 1; // return 0-based month
+ } else {
+ return super.getDefaultMonthInYear(extendedYear);
+ }
}
/**
* @provisional ICU 3.6
* @see #DAY_OF_MONTH
*/
+ @Override
protected int getDefaultDayInMonth(int extendedYear, int month) {
- int era = internalGet(ERA, CURRENT_ERA);
-
- if(extendedYear == ERAS[era*3]) { // if it is year 1..
- if(month == ((ERAS[(era*3)+1])-1)) { // if it is the emperor's first month..
- return ERAS[(era*3)+2]; // return the D_O_M of acession
+ int era = internalGet(ERA, CURRENT_ERA);
+ int[] eraStart = ERA_RULES.getStartDate(era, null);
+
+ if (extendedYear == eraStart[0]) { // if it is year 1..
+ if (month == (eraStart[1] - 1)) { // if it is the emperor's first month..
+ return eraStart[2]; // return the D_O_M of accession
+ }
}
- }
- return super.getDefaultDayInMonth(extendedYear, month);
+ return super.getDefaultDayInMonth(extendedYear, month);
}
/**
* @stable ICU 2.8
*/
+ @Override
protected void handleComputeFields(int julianDay) {
super.handleComputeFields(julianDay);
int year = internalGet(EXTENDED_YEAR);
+ int eraIdx = ERA_RULES.getEraIndex(year, internalGet(MONTH) + 1 /* 1-base */, internalGet(DAY_OF_MONTH));
- int 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.
- if (year > ERAS[ERAS.length - 3]) {
- low = CURRENT_ERA;
- } else {
- // Binary search
- int high = ERAS.length / 3;
-
- while (low < high - 1) {
- int i = (low + high) / 2;
- int diff = year - ERAS[i*3];
-
- // 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(MONTH) - (ERAS[i*3 + 1] - 1);
- if (diff == 0) {
- diff = internalGet(DAY_OF_MONTH) - ERAS[i*3 + 2];
- }
- }
- if (diff >= 0) {
- low = i;
- } else {
- high = i;
- }
- }
- }
-
- // 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(ERA, low);
- internalSet(YEAR, year - ERAS[low*3] + 1);
+ internalSet(ERA, eraIdx);
+ internalSet(YEAR, year - ERA_RULES.getStartYear(eraIdx) + 1);
}
- private static final int[] ERAS = {
- // Gregorian date of each emperor's ascension
- // Years are AD, months are 1-based.
- // Year Month Day
- 645, 6, 19, // Taika
- 650, 2, 15, // Hakuchi
- 672, 1, 1, // Hakuho
- 686, 7, 20, // Shucho
- 701, 3, 21, // Taiho
- 704, 5, 10, // Keiun
- 708, 1, 11, // Wado
- 715, 9, 2, // Reiki
- 717, 11, 17, // Yoro
- 724, 2, 4, // Jinki
- 729, 8, 5, // Tempyo
- 749, 4, 14, // Tempyo-kampo
- 749, 7, 2, // Tempyo-shoho
- 757, 8, 18, // Tempyo-hoji
- 765, 1, 7, // Tempho-jingo
- 767, 8, 16, // Jingo-keiun
- 770, 10, 1, // Hoki
- 781, 1, 1, // Ten-o
- 782, 8, 19, // Enryaku
- 806, 5, 18, // Daido
- 810, 9, 19, // Konin
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 1372, 4, 1, // Bunch\u0169
- 1375, 5, 27, // Tenju
- 1379, 3, 22, // Koryaku
- 1381, 2, 10, // Kowa
- 1384, 4, 28, // Gench\u0169
- 1384, 2, 27, // Meitoku
- 1387, 8, 23, // Kakei
- 1389, 2, 9, // Koo
- 1390, 3, 26, // Meitoku
- 1394, 7, 5, // Oei
- 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
- 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
- 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
- 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
- 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
- 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
- 1865, 4, 7, // Keio
- 1868, 9, 8, // Meiji
- 1912, 7, 30, // Taisho
- 1926, 12, 25, // Showa
- 1989, 1, 8, // Heisei
- };
-
//-------------------------------------------------------------------------
// Public constants for some of the recent eras that folks might use...
//-------------------------------------------------------------------------
/**
* @stable ICU 2.8
*/
- static public final int CURRENT_ERA = (ERAS.length / 3) - 1;
-
- /**
+ static public final int CURRENT_ERA = ERA_RULES.getCurrentEraIndex();
+
+ /**
* Constant for the era starting on Sept. 8, 1868 AD.
- * @stable ICU 2.8
+ * @stable ICU 2.8
*/
- static public final int MEIJI = CURRENT_ERA - 3;
+ static public final int MEIJI = 232;
- /**
- * Constant for the era starting on July 30, 1912 AD.
- * @stable ICU 2.8
+ /**
+ * Constant for the era starting on July 30, 1912 AD.
+ * @stable ICU 2.8
*/
- static public final int TAISHO = CURRENT_ERA - 2;
-
- /**
- * Constant for the era starting on Dec. 25, 1926 AD.
- * @stable ICU 2.8
+ static public final int TAISHO = 233;
+
+ /**
+ * Constant for the era starting on Dec. 25, 1926 AD.
+ * @stable ICU 2.8
*/
- static public final int SHOWA = CURRENT_ERA - 1;
+ static public final int SHOWA = 234;
- /**
- * Constant for the era starting on Jan. 7, 1989 AD.
- * @stable ICU 2.8
+ /**
+ * Constant for the era starting on Jan. 7, 1989 AD.
+ * @stable ICU 2.8
*/
- static public final int HEISEI = CURRENT_ERA;
+ static public final int HEISEI = 235;
/**
* Override GregorianCalendar. We should really handle YEAR_WOY and
* not critical.
* @stable ICU 2.8
*/
+ @Override
@SuppressWarnings("fallthrough")
protected int handleGetLimit(int field, int limitType) {
switch (field) {
case LEAST_MAXIMUM:
return 1;
case MAXIMUM:
- return super.handleGetLimit(field, MAXIMUM) - ERAS[CURRENT_ERA*3];
+ return super.handleGetLimit(field, MAXIMUM) - ERA_RULES.getStartYear(CURRENT_ERA);
}
//Fall through to the default if not handled above
}
* {@inheritDoc}
* @stable ICU 3.8
*/
+ @Override
public String getType() {
return "japanese";
}
* @internal
* @deprecated This API is ICU internal only.
*/
+ @Override
@Deprecated
public boolean haveDefaultCentury() {
return false;
* {@inheritDoc}
* @stable ICU 4.0
*/
+ @Override
public int getActualMaximum(int field) {
if (field == YEAR) {
int era = get(Calendar.ERA);
// TODO: Investigate what value should be used here - revisit after 4.0.
return handleGetLimit(YEAR, MAXIMUM);
} else {
- int nextEraYear = ERAS[(era+1)*3];
- int nextEraMonth = ERAS[(era+1)*3 + 1];
- int nextEraDate = ERAS[(era+1)*3 + 2];
+ int[] nextEraStart = ERA_RULES.getStartDate(era + 1, null);
+ int nextEraYear = nextEraStart[0];
+ int nextEraMonth = nextEraStart[1]; // 1-base
+ int nextEraDate = nextEraStart[2];
- int maxYear = nextEraYear - ERAS[era*3] + 1; // 1-base
+ int maxYear = nextEraYear - ERA_RULES.getStartYear(era) + 1; // 1-base
if (nextEraMonth == 1 && nextEraDate == 1) {
// Substract 1, because the next era starts at Jan 1
maxYear--;
version https://git-lfs.github.com/spec/v1
-oid sha256:36d0ec0c543d1dccafcc6985a7c18285b255afb98bc2bdb16a867a22600bfddb
-size 12487287
+oid sha256:92dc0a5ca71ac54537a6c7c42c2f80ccbd3298d9ebf69c3d732199230d5100c6
+size 12487439
version https://git-lfs.github.com/spec/v1
-oid sha256:469f76e391dced8e9ae4a9543513dddd6d4d2026ad6cbc0ab79d9553da803e6a
+oid sha256:d2308b3498ce1c2b869b60b5a0f7cea6f08aff2fac046ae260e10688c15c60b2
size 92857
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.dev.test.calendar;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.impl.CalType;
+import com.ibm.icu.impl.EraRules;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.JapaneseCalendar;
+import com.ibm.icu.util.ULocale;
+
+/**
+ * Tests for EraRules class
+ */
+@RunWith(JUnit4.class)
+public class EraRulesTest extends TestFmwk {
+ @Test
+ public void testAPIs() {
+ for (CalType calType : CalType.values()) {
+ String calId = calType.getId();
+ if (calId.equals("iso8601") || calId.equals("unknown")) {
+ continue;
+ }
+ EraRules rules1 = EraRules.getInstance(calType, false);
+ if (rules1 == null) {
+ errln("Era rules for " + calId + " is not available.");
+ }
+
+ EraRules rules2 = EraRules.getInstance(calType, true);
+ if (rules2 == null) {
+ errln("Era rules for " + calId + " (including tentative eras) is not available.");
+ }
+ int numEras1 = rules1.getNumberOfEras();
+ if (numEras1 <= 0) {
+ errln("Number of era rules for " + calId + " is " + numEras1);
+ }
+ int numEras2 = rules2.getNumberOfEras();
+ if (numEras2 < numEras1) {
+ errln("Number of era including tentative eras is fewer than one without tentative eras in calendar: "
+ + calId);
+ }
+
+ Calendar cal = Calendar.getInstance(new ULocale("en"));
+ int currentIdx = rules1.getCurrentEraIndex();
+ int currentYear = cal.get(Calendar.YEAR);
+ int idx = rules1.getEraIndex(currentYear, cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE));
+ if (idx != currentIdx) {
+ errln("Current era index:" + currentIdx + " is different from era index of now:" + idx
+ + " in calendar:" + calId);
+ }
+
+ int eraStartYear = rules1.getStartYear(currentIdx);
+ if (currentYear < eraStartYear) {
+ errln("Current era's start year is after the current year in calendar:" + calId);
+ }
+ }
+ }
+
+ @Test
+ public void testJapanese() {
+ EraRules rules = EraRules.getInstance(CalType.JAPANESE, true);
+ // Rules should have an era after Heisei
+ int numRules = rules.getNumberOfEras();
+ if (numRules <= JapaneseCalendar.HEISEI) {
+ errln("Era after Heisei is not available.");
+ }
+ int postHeiseiStartYear = rules.getStartYear(JapaneseCalendar.HEISEI + 1);
+ if (postHeiseiStartYear != 2019) {
+ errln("Era after Heisei should start in 2019, but got " + postHeiseiStartYear);
+ }
+ }
+}