1/*
2 *******************************************************************************
3 * Copyright (C) 2005-2010, International Business Machines Corporation and    *
4 * others. All Rights Reserved.                                                *
5 *******************************************************************************
6 */
7package com.ibm.icu.dev.test.calendar;
8
9import java.util.Date;
10import java.util.Locale;
11
12import com.ibm.icu.impl.LocaleUtility;
13import com.ibm.icu.text.DateFormat;
14import com.ibm.icu.text.SimpleDateFormat;
15import com.ibm.icu.util.Calendar;
16import com.ibm.icu.util.CopticCalendar;
17import com.ibm.icu.util.EthiopicCalendar;
18import com.ibm.icu.util.GregorianCalendar;
19import com.ibm.icu.util.TimeZone;
20import com.ibm.icu.util.ULocale;
21
22/**
23 * Tests for the <code>CopticCalendar</code> class.
24 */
25public class CopticTest extends CalendarTest
26{
27    public static void main(String args[]) throws Exception {
28        new CopticTest().run(args);
29    }
30
31    /** Constants to save typing. */
32    public static final int TOUT      = CopticCalendar.TOUT;
33    public static final int BABA      = CopticCalendar.BABA;
34    public static final int HATOR     = CopticCalendar.HATOR;
35    public static final int KIAHK     = CopticCalendar.KIAHK;
36    public static final int TOBA      = CopticCalendar.TOBA;
37    public static final int AMSHIR    = CopticCalendar.AMSHIR;
38    public static final int BARAMHAT  = CopticCalendar.BARAMHAT;
39    public static final int BARAMOUDA = CopticCalendar.BARAMOUDA;
40    public static final int BASHANS   = CopticCalendar.BASHANS;
41    public static final int PAONA     = CopticCalendar.PAONA;
42    public static final int EPEP      = CopticCalendar.EPEP;
43    public static final int MESRA     = CopticCalendar.MESRA;
44    public static final int NASIE     = CopticCalendar.NASIE;
45
46    /* Test dates from:
47     * "The Amharic Letters of Emperor Theodore of Ethiopia to Queen Victoria and
48     * Her Special Envoy", David Appleyard, Girma Selasse Asfaw, Oxford University Press,
49     * June 1 1979, ISBN: 0856726605, Longwood Pr Ltd
50     *
51     * Coptic         Gregorian    JD
52     * 20/02/1579     29/10/1862  2401443
53     * 29/10/1581     05/07/1865  2402423
54     * 22/05/1582     29/01/1866  2402631
55     * 10/08/1582     17/04/1866  2402709
56     * 28/04/1583     05/01/1867  2402972
57     * 05/05/1584     13/01/1868  2403345
58     *
59     * --------------------------------------------------
60     *
61     * From the Calendrica applet:  http://emr.cs.iit.edu/home/reingold/calendar-book/Calendrica.html
62     *
63     * Coptic         Gregorian    JD
64     * 07/05/-284     01/01/0000  1721060
65     * 08/05/-283     01/01/0001  1721426
66     * 06/13/-1       29/08/0283  1824664
67     *
68     * 01/01/0000     30/08/0283  1824665
69     * 01/01/0001     29/08/0284  1825030
70     * 01/01/0002     29/08/0285  1825395
71     * 01/01/0003     29/08/0286  1825760
72     * 01/01/0004     30/08/0287  1826126
73     * 05/13/0000     28/08/0284  1825029
74     * 05/13/0001     28/08/0285  1825394
75     * 05/13/0002     28/08/0286  1825759
76     * 05/13/0003     28/08/0287  1826124
77     * 06/13/0003     29/08/0287  1826125  first coptic leap year
78     * 05/13/0004     28/08/0288  1826490
79     *
80     * 06/02/1299     13/10/1582  2299159
81     * 07/02/1299     14/10/1582  2299160  Julian 04/10/1582
82     * 08/02/1299     15/10/1582  2299161
83     * 09/02/1299     16/10/1582  2299162
84     *
85     * 23/04/1616     01/01/1900  2415021
86     * 23/04/1721     01/01/2005  2453372
87     * 05/13/2000     12/09/2284  2555529
88     */
89
90
91    /** A huge list of test cases to make sure that computeTime and computeFields
92     * work properly for a wide range of data in the civil calendar.
93     */
94    public void TestCases()
95    {
96        final TestCase[] tests = {
97            //
98            // The months in this table are 1-based rather than 0-based,
99            // because it's easier to edit that way.
100            //                      Coptic
101            //          Julian Day  Era  Year  Month Day  WkDay Hour Min Sec
102            //
103            // Dates from "Emporer Theodore..."
104
105            new TestCase(2401442.5,  1,  1579,    2,  20,  WED,    0,  0,  0), // Gregorian: 20/10/1862
106            new TestCase(2402422.5,  1,  1581,   10,  29,  WED,    0,  0,  0), // Gregorian: 05/07/1865
107            new TestCase(2402630.5,  1,  1582,    5,  22,  MON,    0,  0,  0), // Gregorian: 29/01/1866
108            new TestCase(2402708.5,  1,  1582,    8,  10,  TUE,    0,  0,  0), // Gregorian: 17/04/1866
109            new TestCase(2402971.5,  1,  1583,    4,  28,  SAT,    0,  0,  0), // Gregorian: 05/01/1867
110            new TestCase(2403344.5,  1,  1584,    5,   5,  MON,    0,  0,  0), // Gregorian: 13/01/1868
111            new TestCase(1721059.5,  0,   285,    5,   7,  SAT,    0,  0,  0), // Gregorian: 01/01/0000
112            new TestCase(1721425.5,  0,   284,    5,   8,  MON,    0,  0,  0), // Gregorian: 01/01/0001
113            new TestCase(1824663.5,  0,     2,   13,   6,  WED,    0,  0,  0), // Gregorian: 29/08/0283
114            new TestCase(1824664.5,  0,     1,    1,   1,  THU,    0,  0,  0), // Gregorian: 30/08/0283
115            new TestCase(1825029.5,  1,     1,    1,   1,  FRI,    0,  0,  0), // Gregorian: 29/08/0284
116            new TestCase(1825394.5,  1,     2,    1,   1,  SAT,    0,  0,  0), // Gregorian: 29/08/0285
117            new TestCase(1825759.5,  1,     3,    1,   1,  SUN,    0,  0,  0), // Gregorian: 29/08/0286
118            new TestCase(1826125.5,  1,     4,    1,   1,  TUE,    0,  0,  0), // Gregorian: 30/08/0287
119            new TestCase(1825028.5,  0,     1,   13,   5,  THU,    0,  0,  0), // Gregorian: 28/08/0284
120            new TestCase(1825393.5,  1,     1,   13,   5,  FRI,    0,  0,  0), // Gregorian: 28/08/0285
121            new TestCase(1825758.5,  1,     2,   13,   5,  SAT,    0,  0,  0), // Gregorian: 28/08/0286
122            new TestCase(1826123.5,  1,     3,   13,   5,  SUN,    0,  0,  0), // Gregorian: 28/08/0287
123            new TestCase(1826124.5,  1,     3,   13,   6,  MON,    0,  0,  0), // Gregorian: 29/08/0287
124                          // above is first coptic leap year
125            new TestCase(1826489.5,  1,     4,   13,   5,  TUE,    0,  0,  0), // Gregorian: 28/08/0288
126            new TestCase(2299158.5,  1,  1299,    2,   6,  WED,    0,  0,  0), // Gregorian: 13/10/1582
127            new TestCase(2299159.5,  1,  1299,    2,   7,  THU,    0,  0,  0), // Gregorian: 14/10/1582
128
129            new TestCase(2299160.5,  1,  1299,    2,   8,  FRI,    0,  0,  0), // Gregorian: 15/10/1582
130            new TestCase(2299161.5,  1,  1299,    2,   9,  SAT,    0,  0,  0), // Gregorian: 16/10/1582
131
132            new TestCase(2415020.5,  1,  1616,    4,  23,  MON,    0,  0,  0), // Gregorian: 01/01/1900
133            new TestCase(2453371.5,  1,  1721,    4,  23,  SAT,    0,  0,  0), // Gregorian: 01/01/2005
134            new TestCase(2555528.5,  1,  2000,   13,   5,  FRI,    0,  0,  0), // Gregorian: 12/09/2284
135        };
136
137        CopticCalendar testCalendar = new CopticCalendar();
138        testCalendar.setLenient(true);
139        doTestCases(tests, testCalendar);
140    }
141
142    // basic sanity check that the conversion algorithm round-trips
143    public void TestCopticToJD() {
144        CopticCalendar cal = new CopticCalendar();
145        cal.clear();
146        for (int y = -2; y < 3; ++y) {
147            for (int m = 0; m < 12; ++m) { // don't understand rules for 13th month
148                for (int d = 1; d < 25; d += 3) { // play it safe on days per month
149                    int jd = CopticCalendar.copticToJD(y, m, d);
150                    cal.set(Calendar.JULIAN_DAY, jd);
151                    int eyear = cal.get(Calendar.EXTENDED_YEAR);
152                    int month = cal.get(Calendar.MONTH);
153                    int day = cal.get(Calendar.DAY_OF_MONTH);
154                    if (!(y == eyear &&
155                          m == month &&
156                          d == day)) {
157                        errln("y: " + y +
158                              " m: " + m +
159                              " d: " + d +
160                              " --> jd: " + jd +
161                              " --> y: " + eyear +
162                              " m: " + month +
163                              " d: " + day);
164                    }
165                }
166            }
167        }
168    }
169
170    // basic check to see that we print out eras ok
171    // eventually should modify to use locale strings and formatter appropriate to coptic calendar
172    public void TestEraStart() {
173        SimpleDateFormat fmt = new SimpleDateFormat("EEE MMM dd, yyyy GG");
174        SimpleDateFormat copticFmt = new SimpleDateFormat("EEE MMM dd, yyyy GG");
175        copticFmt.setCalendar(new CopticCalendar());
176
177        CopticCalendar cal = new CopticCalendar(1, 0, 1);
178        assertEquals("Coptic Date", "Fri Jan 01, 0001 AD", copticFmt.format(cal));
179        assertEquals("Gregorian Date", "Fri Aug 29, 0284 AD", fmt.format(cal.getTime()));
180
181        cal.set(Calendar.ERA, 0);
182        cal.set(Calendar.YEAR, 1);
183        assertEquals("Coptic Date", "Thu Jan 01, 0001 BC", copticFmt.format(cal));
184        assertEquals("Gregorian Date", "Thu Aug 30, 0283 AD", fmt.format(cal.getTime()));
185    }
186
187    public void TestBasic() {
188        CopticCalendar cal = new CopticCalendar();
189        cal.clear();
190        cal.set(1000, 0, 30);
191        logln("1000/0/30-> " +
192              cal.get(YEAR) + "/" +
193              cal.get(MONTH) + "/" +
194              cal.get(DATE));
195        cal.clear();
196        cal.set(1, 0, 30);
197        logln("1/0/30 -> " +
198              cal.get(YEAR) + "/" +
199              cal.get(MONTH) + "/" +
200              cal.get(DATE));
201    }
202
203    /**
204     * Test limits of the Coptic calendar
205     */
206    public void TestLimits() {
207        Calendar cal = Calendar.getInstance();
208        cal.set(2007, Calendar.JANUARY, 1);
209        CopticCalendar coptic = new CopticCalendar();
210        doLimitsTest(coptic, null, cal.getTime());
211        doTheoreticalLimitsTest(coptic, true);
212    }
213
214    /**
215     * Test for track ticket 6379 - proper reporting of
216     * maximum month lengths
217     */
218    public void Test6379()
219    {
220        CopticCalendar copticCal = new CopticCalendar();
221        copticCal.clear();
222
223        for (int year = 1725; year < 1735; year++) {    // Coptic 1725-01-01 = Gregorian 2008-09-11
224            boolean isLeap = ((year % 4) == 3);
225            copticCal.set(Calendar.YEAR, year);
226
227            int maxMonth = copticCal.getActualMaximum(Calendar.MONTH);
228
229            for (int month = 0; month <= maxMonth; month++) {
230                copticCal.set(Calendar.MONTH, month);
231                int maxDayOfMonth = copticCal.getActualMaximum(Calendar.DAY_OF_MONTH);
232
233                int expected = (month != maxMonth) ? 30 : (isLeap ? 6 : 5);
234                if (maxDayOfMonth != expected) {
235                    errln("FAIL: Expected maximum " + expected + " days for month #"
236                            + (month + 1) + " - returned:" + maxDayOfMonth);
237                }
238            }
239        }
240    }
241
242    public void TestCoverage() {
243
244        {
245            // new CopticCalendar(TimeZone)
246            CopticCalendar cal = new CopticCalendar(TimeZone.getDefault());
247            if(cal == null){
248                errln("could not create CopticCalendar with TimeZone");
249            }
250        }
251
252        {
253            // new CopticCalendar(ULocale)
254            CopticCalendar cal = new CopticCalendar(ULocale.getDefault());
255            if(cal == null){
256                errln("could not create CopticCalendar with ULocale");
257            }
258        }
259
260        {
261            // new CopticCalendar(Locale)
262            CopticCalendar cal = new CopticCalendar(Locale.getDefault());
263            if(cal == null){
264                errln("could not create CopticCalendar with Locale");
265            }
266        }
267
268        {
269            // new CopticCalendar(TimeZone, Locale)
270            CopticCalendar cal = new CopticCalendar(TimeZone.getDefault(),Locale.getDefault());
271            if(cal == null){
272                errln("could not create CopticCalendar with TimeZone, Locale");
273            }
274        }
275
276        {
277            // new CopticCalendar(TimeZone, ULocale)
278            CopticCalendar cal = new CopticCalendar(TimeZone.getDefault(),ULocale.getDefault());
279            if(cal == null){
280                errln("could not create CopticCalendar with TimeZone, ULocale");
281            }
282        }
283
284        {
285            // new CopticCalendar(Date)
286            CopticCalendar cal = new CopticCalendar(new Date());
287            if(cal == null){
288                errln("could not create CopticCalendar with Date");
289            }
290        }
291
292        {
293            // new CopticCalendar(int year, int month, int date)
294            CopticCalendar cal = new CopticCalendar(1997, CopticCalendar.TOUT, 1);
295            if(cal == null){
296                errln("could not create CopticCalendar with year,month,date");
297            }
298        }
299
300        {
301            // new CopticCalendar(int year, int month, int date, int hour, int minute, int second)
302            CopticCalendar cal = new CopticCalendar(1997, CopticCalendar.TOUT, 1, 1, 1, 1);
303            if(cal == null){
304                errln("could not create CopticCalendar with year,month,date,hour,minute,second");
305            }
306        }
307
308        {
309            // data
310            CopticCalendar cal = new CopticCalendar(1997, CopticCalendar.TOUT, 1);
311            Date time = cal.getTime();
312
313            String[] calendarLocales = {
314                "am_ET", "gez_ET", "ti_ET"
315            };
316
317            String[] formatLocales = {
318                "en", "am", "am_ET", "gez", "ti"
319            };
320            for (int i = 0; i < calendarLocales.length; ++i) {
321                String calLocName = calendarLocales[i];
322                Locale calLocale = LocaleUtility.getLocaleFromName(calLocName);
323                cal = new CopticCalendar(calLocale);
324
325                for (int j = 0; j < formatLocales.length; ++j) {
326                    String locName = formatLocales[j];
327                    Locale formatLocale = LocaleUtility.getLocaleFromName(locName);
328                    DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale);
329                    logln(calLocName + "/" + locName + " --> " + format.format(time));
330                }
331            }
332        }
333    }
334
335    public void TestYear() {
336        // Gregorian Calendar
337        Calendar gCal= new GregorianCalendar();
338        Date gToday=gCal.getTime();
339        gCal.add(GregorianCalendar.MONTH,2);
340        Date gFuture=gCal.getTime();
341        DateFormat gDF = DateFormat.getDateInstance(gCal,DateFormat.FULL);
342        logln("gregorian calendar: " + gDF.format(gToday) +
343              " + 2 months = " + gDF.format(gFuture));
344
345        // Coptic Calendar
346        CopticCalendar cCal= new CopticCalendar();
347        Date cToday=cCal.getTime();
348        cCal.add(CopticCalendar.MONTH,2);
349        Date cFuture=cCal.getTime();
350        DateFormat cDF = DateFormat.getDateInstance(cCal,DateFormat.FULL);
351        logln("coptic calendar: " + cDF.format(cToday) +
352              " + 2 months = " + cDF.format(cFuture));
353
354        // EthiopicCalendar
355        EthiopicCalendar eCal= new EthiopicCalendar();
356        Date eToday=eCal.getTime();
357        eCal.add(EthiopicCalendar.MONTH,2); // add 2 months
358        eCal.setAmeteAlemEra(false);
359        Date eFuture=eCal.getTime();
360        DateFormat eDF = DateFormat.getDateInstance(eCal,DateFormat.FULL);
361        logln("ethiopic calendar: " + eDF.format(eToday) +
362              " + 2 months = " + eDF.format(eFuture));
363    }
364
365    public void TestAddSet() {
366        class TestAddSetItem {
367            private int startYear;
368            private int startMonth; // 0-based
369            private int startDay; // 1-based
370            private int fieldToChange;
371            private int fieldDelta;
372            private int endYear;
373            private int endMonth;
374            private int endDay;
375            TestAddSetItem(int sYr, int sMo, int sDa, int field, int delta, int eYr, int eMo, int eDa) {
376                startYear = sYr;
377                startMonth = sMo;
378                startDay = sDa;
379                fieldToChange = field;
380                fieldDelta = delta;
381                endYear = eYr;
382                endMonth = eMo;
383                endDay = eDa;
384            }
385            public int getStartYear()  { return startYear; }
386            public int getStartMonth() { return startMonth; }
387            public int getStartDay()   { return startDay; }
388            public int getField()      { return fieldToChange; }
389            public int getDelta()      { return fieldDelta; }
390            public int getEndYear()    { return endYear; }
391            public int getEndMonth()   { return endMonth; }
392            public int getEndDay()     { return endDay; }
393        }
394        final TestAddSetItem[] tests = {
395            new TestAddSetItem( 1724, 12, 1, Calendar.MONTH, +1, 1725,  0, 1 ),
396            new TestAddSetItem( 1724, 12, 1, Calendar.MONTH, +9, 1725,  8, 1 ),
397            new TestAddSetItem( 1723, 12, 2, Calendar.MONTH, +1, 1724,  0, 2 ), // 1723 is a leap year
398            new TestAddSetItem( 1723, 12, 2, Calendar.MONTH, +9, 1724,  8, 2 ),
399            new TestAddSetItem( 1725,  0, 1, Calendar.MONTH, -1, 1724, 12, 1 ),
400            new TestAddSetItem( 1725,  0, 1, Calendar.MONTH, -6, 1724,  7, 1 ),
401            new TestAddSetItem( 1724, 12, 1, Calendar.DATE,  +8, 1725,  0, 4 ),
402            new TestAddSetItem( 1723, 12, 1, Calendar.DATE,  +8, 1724,  0, 3 ), // 1723 is a leap year
403            new TestAddSetItem( 1724,  0, 1, Calendar.DATE,  -1, 1723, 12, 6 ),
404        };
405        CopticCalendar testCalendar = new CopticCalendar();
406        for ( int i = 0; i < tests.length; i++ ) {
407            TestAddSetItem item = tests[i];
408            testCalendar.set( item.getStartYear(), item.getStartMonth(), item.getStartDay(), 9, 0 );
409            testCalendar.add( item.getField(), item.getDelta() );
410            int endYear = testCalendar.get(Calendar.YEAR);
411            int endMonth = testCalendar.get(Calendar.MONTH);
412            int endDay = testCalendar.get(Calendar.DATE);
413            if ( endYear != item.getEndYear() || endMonth != item.getEndMonth() || endDay != item.getEndDay() ) {
414                errln("CToJD FAILS: field " + item.getField() + " delta " + item.getDelta() +
415                            " expected yr " + item.getEndYear() + " mo " + item.getEndMonth() +  " da " + item.getEndDay() +
416                            " got yr " + endYear + " mo " + endMonth +  " da " + endDay);
417            }
418        }
419    }
420}
421