Home | History | Annotate | Download | only in calendar
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 //  2016 and later: Unicode, Inc. and others.
      3 // License & terms of use: http://www.unicode.org/copyright.html#License
      4 /*
      5  *******************************************************************************
      6  * Copyright (C) 2012, International Business Machines Corporation and         *
      7  * others. All Rights Reserved.                                                *
      8  *******************************************************************************
      9  */
     10 package android.icu.dev.test.calendar;
     11 import java.util.Date;
     12 
     13 import org.junit.Test;
     14 import org.junit.runner.RunWith;
     15 import org.junit.runners.JUnit4;
     16 
     17 import android.icu.text.DateFormat;
     18 import android.icu.util.Calendar;
     19 import android.icu.util.DangiCalendar;
     20 import android.icu.util.GregorianCalendar;
     21 import android.icu.util.TimeZone;
     22 import android.icu.util.ULocale;
     23 import android.icu.testsharding.MainTestShard;
     24 
     25 @MainTestShard
     26 @RunWith(JUnit4.class)
     27 public class DangiTest extends CalendarTestFmwk {
     28     /**
     29      * Test basic mapping to and from Gregorian.
     30      */
     31     @Test
     32     public void TestMapping() {
     33         final int[] DATA = {
     34             // (Note: months are 1-based)
     35             // Gregorian    Korean (Dan-gi)
     36             1964,  9,  4,   4297,  7,0, 28,
     37             1964,  9,  5,   4297,  7,0, 29,
     38             1964,  9,  6,   4297,  8,0,  1,
     39             1964,  9,  7,   4297,  8,0,  2,
     40             1961, 12, 25,   4294, 11,0, 18,
     41             1999,  6,  4,   4332,  4,0, 21,
     42 
     43             1990,  5, 23,   4323,  4,0, 29,
     44             1990,  5, 24,   4323,  5,0,  1,
     45             1990,  6, 22,   4323,  5,0, 30,
     46             1990,  6, 23,   4323,  5,1,  1,
     47             1990,  7, 20,   4323,  5,1, 28,
     48             1990,  7, 21,   4323,  5,1, 29,
     49             1990,  7, 22,   4323,  6,0,  1,
     50 
     51             // Some tricky dates (where GMT+8 doesn't agree with GMT+9)
     52             //
     53             // The list is from http://www.math.snu.ac.kr/~kye/others/lunar.html ('kye ref').
     54             // However, for some dates disagree with the above reference so KASI's
     55             // calculation was cross-referenced:
     56             //  http://astro.kasi.re.kr/Life/ConvertSolarLunarForm.aspx?MenuID=115
     57             1880, 11,  3,   4213, 10,0,  1, // astronomer's GMT+8 / KASI disagrees with the kye ref
     58             1882, 12, 10,   4215, 11,0,  1,
     59             1883,  7, 4,    4216,  6,0,  1,
     60             1884,  4, 25,   4217,  4,0,  1,
     61             1885,  5, 14,   4218,  4,0,  1,
     62             1891,  1, 10,   4223, 12,0,  1,
     63             1893,  4, 16,   4226,  3,0,  1,
     64             1894,  5,  5,   4227,  4,0,  1,
     65             1897,  7, 29,   4230,  7,0,  1, // astronomer's GMT+8 disagrees with all other ref (looks like our astronomer's error, see ad hoc fix at ChineseCalendar::getTimezoneOffset)
     66             1903, 10, 20,   4236,  9,0,  1,
     67             1904,  1, 17,   4236, 12,0,  1,
     68             1904, 11,  7,   4237, 10,0,  1,
     69             1905,  5,  4,   4238,  4,0,  1,
     70             1907,  7, 10,   4240,  6,0,  1,
     71             1908,  4, 30,   4241,  4,0,  1,
     72             1908,  9, 25,   4241,  9,0,  1,
     73             1909,  9, 14,   4242,  8,0,  1,
     74             1911, 12, 20,   4244, 11,0,  1,
     75             1976, 11, 22,   4309, 10,0,  1,
     76         };
     77 
     78         Calendar cal = Calendar.getInstance(new ULocale("ko_KR@calendar=dangi"));
     79         StringBuilder buf = new StringBuilder();
     80 
     81         logln("Gregorian -> Korean Lunar (Dangi)");
     82 
     83         Calendar grego = Calendar.getInstance();
     84         grego.clear();
     85         for (int i = 0; i < DATA.length;) {
     86             grego.set(DATA[i++], DATA[i++] - 1, DATA[i++]);
     87             Date date = grego.getTime();
     88             cal.setTime(date);
     89             int y = cal.get(Calendar.EXTENDED_YEAR);
     90             int m = cal.get(Calendar.MONTH) + 1; // 0-based -> 1-based
     91             int L = cal.get(Calendar.IS_LEAP_MONTH);
     92             int d = cal.get(Calendar.DAY_OF_MONTH);
     93             int yE = DATA[i++]; // Expected y, m, isLeapMonth, d
     94             int mE = DATA[i++]; // 1-based
     95             int LE = DATA[i++];
     96             int dE = DATA[i++];
     97             buf.setLength(0);
     98             buf.append(date + " -> ");
     99             buf.append(y + "/" + m + (L == 1 ? "(leap)" : "") + "/" + d);
    100             if (y == yE && m == mE && L == LE && d == dE) {
    101                 logln("OK: " + buf.toString());
    102             } else {
    103                 errln("Fail: " + buf.toString() + ", expected " + yE + "/" + mE + (LE == 1 ? "(leap)" : "") + "/" + dE);
    104             }
    105         }
    106 
    107         logln("Korean Lunar (Dangi) -> Gregorian");
    108         for (int i = 0; i < DATA.length;) {
    109             grego.set(DATA[i++], DATA[i++] - 1, DATA[i++]);
    110             Date dexp = grego.getTime();
    111             int cyear = DATA[i++];
    112             int cmonth = DATA[i++];
    113             int cisleapmonth = DATA[i++];
    114             int cdayofmonth = DATA[i++];
    115             cal.clear();
    116             cal.set(Calendar.EXTENDED_YEAR, cyear);
    117             cal.set(Calendar.MONTH, cmonth - 1);
    118             cal.set(Calendar.IS_LEAP_MONTH, cisleapmonth);
    119             cal.set(Calendar.DAY_OF_MONTH, cdayofmonth);
    120             Date date = cal.getTime();
    121             buf.setLength(0);
    122             buf.append(cyear + "/" + cmonth + (cisleapmonth == 1 ? "(leap)" : "") + "/" + cdayofmonth);
    123             buf.append(" -> " + date);
    124             if (date.equals(dexp)) {
    125                 logln("OK: " + buf.toString());
    126             } else {
    127                 errln("Fail: " + buf.toString() + ", expected " + dexp);
    128             }
    129         }
    130     }
    131 
    132     /**
    133      * Make sure no Gregorian dates map to Chinese 1-based day of
    134      * month zero.  This was a problem with some of the astronomical
    135      * new moon determinations.
    136      */
    137     @Test
    138     public void TestZeroDOM() {
    139         Calendar cal = Calendar.getInstance(new ULocale("ko_KR@calendar=dangi"));
    140         GregorianCalendar greg = new GregorianCalendar(1989, Calendar.SEPTEMBER, 1);
    141         logln("Start: " + greg.getTime());
    142         for (int i=0; i<1000; ++i) {
    143             cal.setTimeInMillis(greg.getTimeInMillis());
    144             if (cal.get(Calendar.DAY_OF_MONTH) == 0) {
    145                 errln("Fail: " + greg.getTime() + " -> " +
    146                       cal.get(Calendar.YEAR) + "/" +
    147                       cal.get(Calendar.MONTH) +
    148                       (cal.get(Calendar.IS_LEAP_MONTH)==1?"(leap)":"") +
    149                       "/" + cal.get(Calendar.DAY_OF_MONTH));
    150             }
    151             greg.add(Calendar.DAY_OF_YEAR, 1);
    152         }
    153         logln("End: " + greg.getTime());
    154     }
    155 
    156     /**
    157      * Test minimum and maximum functions.
    158      */
    159     @Test
    160     public void TestLimits() {
    161         // The number of days and the start date can be adjusted
    162         // arbitrarily to either speed up the test or make it more
    163         // thorough, but try to test at least a full year, preferably a
    164         // full non-leap and a full leap year.
    165 
    166         // Final parameter is either number of days, if > 0, or test
    167         // duration in seconds, if < 0.
    168         Calendar tempcal = Calendar.getInstance();
    169         tempcal.clear();
    170         tempcal.set(1989, Calendar.NOVEMBER, 1);
    171         Calendar dangi = Calendar.getInstance(new ULocale("ko_KR@calendar=dangi"));
    172         doLimitsTest(dangi, null, tempcal.getTime());
    173         doTheoreticalLimitsTest(dangi, true);
    174     }
    175 
    176     /**
    177      * Make sure IS_LEAP_MONTH participates in field resolution.
    178      */
    179     @Test
    180     public void TestResolution() {
    181         Calendar cal = Calendar.getInstance(new ULocale("ko_KR@calendar=dangi"));
    182         DateFormat fmt = DateFormat.getDateInstance(cal, DateFormat.DEFAULT);
    183 
    184         // May 22 4334 = y4334 m4 d30 doy119
    185         // May 23 4334 = y4334 m4* d1 doy120
    186 
    187         final int THE_YEAR = 4334;
    188         final int END = -1;
    189 
    190         int[] DATA = {
    191             // Format:
    192             // (field, value)+, END, exp.month, exp.isLeapMonth, exp.DOM
    193             // Note: exp.month is ONE-BASED
    194 
    195             // If we set DAY_OF_YEAR only, that should be used
    196             Calendar.DAY_OF_YEAR, 1,
    197             END,
    198             1,0,1, // Expect 1-1
    199 
    200             // If we set MONTH only, that should be used
    201             Calendar.IS_LEAP_MONTH, 1,
    202             Calendar.DAY_OF_MONTH, 1,
    203             Calendar.MONTH, 3,
    204             END,
    205             4,1,1, // Expect 4*-1
    206 
    207             // If we set the DOY last, that should take precedence
    208             Calendar.MONTH, 1, // Should ignore
    209             Calendar.IS_LEAP_MONTH, 1, // Should ignore
    210             Calendar.DAY_OF_MONTH, 1, // Should ignore
    211             Calendar.DAY_OF_YEAR, 121,
    212             END,
    213             4,1,2, // Expect 4*-2
    214 
    215             // If we set IS_LEAP_MONTH last, that should take precedence
    216             Calendar.MONTH, 3,
    217             Calendar.DAY_OF_MONTH, 1,
    218             Calendar.DAY_OF_YEAR, 5, // Should ignore
    219             Calendar.IS_LEAP_MONTH, 1,
    220             END,
    221             4,1,1, // Expect 4*-1
    222         };
    223 
    224         StringBuilder buf = new StringBuilder();
    225         for (int i=0; i<DATA.length; ) {
    226             cal.clear();
    227             cal.set(Calendar.EXTENDED_YEAR, THE_YEAR);
    228             buf.setLength(0);
    229             buf.append("EXTENDED_YEAR=" + THE_YEAR);
    230             while (DATA[i] != END) {
    231                 cal.set(DATA[i++], DATA[i++]);
    232                 buf.append(" " + fieldName(DATA[i-2]) + "=" + DATA[i-1]);
    233             }
    234             ++i; // Skip over END mark
    235             int expMonth = DATA[i++]-1;
    236             int expIsLeapMonth = DATA[i++];
    237             int expDOM = DATA[i++];
    238             int month = cal.get(Calendar.MONTH);
    239             int isLeapMonth = cal.get(Calendar.IS_LEAP_MONTH);
    240             int dom = cal.get(Calendar.DAY_OF_MONTH);
    241             if (expMonth == month && expIsLeapMonth == isLeapMonth &&
    242                 dom == expDOM) {
    243                 logln("OK: " + buf + " => " + fmt.format(cal.getTime()));
    244             } else {
    245                 String s = fmt.format(cal.getTime());
    246                 cal.clear();
    247                 cal.set(Calendar.EXTENDED_YEAR, THE_YEAR);
    248                 cal.set(Calendar.MONTH, expMonth);
    249                 cal.set(Calendar.IS_LEAP_MONTH, expIsLeapMonth);
    250                 cal.set(Calendar.DAY_OF_MONTH, expDOM);
    251                 errln("Fail: " + buf + " => " + s +
    252                       "=" + (month+1) + "," + isLeapMonth + "," + dom +
    253                       ", expected " + fmt.format(cal.getTime()) +
    254                       "=" + (expMonth+1) + "," + expIsLeapMonth + "," + expDOM);
    255             }
    256         }
    257     }
    258 
    259     /**
    260      * Test the behavior of fields that are out of range.
    261      */
    262     @Test
    263     public void TestOutOfRange() {
    264         int[] DATA = new int[] {
    265             // Input       Output
    266             4334, 13,  1,   4335,  1,  1,
    267             4334, 18,  1,   4335,  6,  1,
    268             4335,  0,  1,   4334, 12,  1,
    269             4335, -6,  1,   4334,  6,  1,
    270             4334,  1, 32,   4334,  2,  2, // 1-4334 has 30 days
    271             4334,  2, -1,   4334,  1, 29,
    272         };
    273         Calendar cal = Calendar.getInstance(new ULocale("ko_KR@calendar=dangi"));
    274         for (int i = 0; i < DATA.length;) {
    275             int y1 = DATA[i++];
    276             int m1 = DATA[i++] - 1;
    277             int d1 = DATA[i++];
    278             int y2 = DATA[i++];
    279             int m2 = DATA[i++] - 1;
    280             int d2 = DATA[i++];
    281             cal.clear();
    282             cal.set(Calendar.EXTENDED_YEAR, y1);
    283             cal.set(MONTH, m1);
    284             cal.set(DATE, d1);
    285             int y = cal.get(Calendar.EXTENDED_YEAR);
    286             int m = cal.get(MONTH);
    287             int d = cal.get(DATE);
    288             if (y != y2 || m != m2 || d != d2) {
    289                 errln("Fail: " + y1 + "/" + (m1 + 1) + "/" + d1 + " resolves to " + y + "/" + (m + 1) + "/" + d
    290                         + ", expected " + y2 + "/" + (m2 + 1) + "/" + d2);
    291             } else if (isVerbose()) {
    292                 logln("OK: " + y1 + "/" + (m1 + 1) + "/" + d1 + " resolves to " + y + "/" + (m + 1) + "/" + d);
    293             }
    294         }
    295     }
    296 
    297     /**
    298      * Test the behavior of KoreanLunarCalendar.add().  The only real
    299      * nastiness with roll is the MONTH field around leap months.
    300      */
    301     @Test
    302     public void TestAdd() {
    303         int[][] tests = new int[][] {
    304             // MONTHS ARE 1-BASED HERE
    305             // input               add           output
    306             // year  mon    day    field amount  year  mon    day
    307             {  4338,   3,0,  15,   MONTH,   3,   4338,   6,0,  15 }, // normal
    308             {  4335,  12,0,  15,   MONTH,   1,   4336,   1,0,  15 }, // across year
    309             {  4336,   1,0,  15,   MONTH,  -1,   4335,  12,0,  15 }, // across year
    310             {  4334,   3,0,  15,   MONTH,   3,   4334,   5,0,  15 }, // 4=leap
    311             {  4334,   3,0,  15,   MONTH,   2,   4334,   4,1,  15 }, // 4=leap
    312             {  4334,   4,0,  15,   MONTH,   1,   4334,   4,1,  15 }, // 4=leap
    313             {  4334,   4,1,  15,   MONTH,   1,   4334,   5,0,  15 }, // 4=leap
    314             {  4334,   3,0,  30,   MONTH,   2,   4334,   4,1,  29 }, // dom should pin
    315             {  4334,   3,0,  30,   MONTH,   3,   4334,   5,0,  30 }, // no dom pin
    316             {  4334,   3,0,  30,   MONTH,   4,   4334,   6,0,  29 }, // dom should pin
    317         };
    318 
    319         Calendar cal = Calendar.getInstance(new ULocale("ko_KR@calendar=dangi"));
    320         doRollAddDangi(ADD, cal, tests);
    321     }
    322 
    323     /**
    324      * Test the behavior of KoreanLunarCalendar.roll().  The only real
    325      * nastiness with roll is the MONTH field around leap months.
    326      */
    327     @Test
    328     public void TestRoll() {
    329         int[][] tests = new int[][] {
    330             // MONTHS ARE 1-BASED HERE
    331             // input               add           output
    332             // year  mon    day    field amount  year  mon    day
    333             {  4338,   3,0,  15,   MONTH,   3,   4338,   6,0,  15 }, // normal
    334             {  4338,   3,0,  15,   MONTH,  11,   4338,   2,0,  15 }, // normal
    335             {  4335,  12,0,  15,   MONTH,   1,   4335,   1,0,  15 }, // across year
    336             {  4336,   1,0,  15,   MONTH,  -1,   4336,  12,0,  15 }, // across year
    337             {  4334,   3,0,  15,   MONTH,   3,   4334,   5,0,  15 }, // 4=leap
    338             {  4334,   3,0,  15,   MONTH,  16,   4334,   5,0,  15 }, // 4=leap
    339             {  4334,   3,0,  15,   MONTH,   2,   4334,   4,1,  15 }, // 4=leap
    340             {  4334,   3,0,  15,   MONTH,  28,   4334,   4,1,  15 }, // 4=leap
    341             {  4334,   4,0,  15,   MONTH,   1,   4334,   4,1,  15 }, // 4=leap
    342             {  4334,   4,0,  15,   MONTH, -12,   4334,   4,1,  15 }, // 4=leap
    343             {  4334,   4,1,  15,   MONTH,   1,   4334,   5,0,  15 }, // 4=leap
    344             {  4334,   4,1,  15,   MONTH, -25,   4334,   5,0,  15 }, // 4=leap
    345             {  4334,   3,0,  30,   MONTH,   2,   4334,   4,1,  29 }, // dom should pin
    346             {  4334,   3,0,  30,   MONTH,  15,   4334,   4,1,  29 }, // dom should pin
    347             {  4334,   3,0,  30,   MONTH,  16,   4334,   5,0,  30 }, // no dom pin
    348             {  4334,   3,0,  30,   MONTH,  -9,   4334,   6,0,  29 }, // dom should pin
    349         };
    350 
    351         Calendar cal = Calendar.getInstance(new ULocale("ko_KR@calendar=dangi"));
    352         doRollAddDangi(ROLL, cal, tests);
    353     }
    354 
    355     void doRollAddDangi(boolean roll, Calendar cal, int[][] tests) {
    356         String name = roll ? "rolling" : "adding";
    357 
    358         for (int i = 0; i < tests.length; i++) {
    359             int[] test = tests[i];
    360 
    361             cal.clear();
    362             cal.set(Calendar.EXTENDED_YEAR, test[0]);
    363             cal.set(Calendar.MONTH, test[1] - 1);
    364             cal.set(Calendar.IS_LEAP_MONTH, test[2]);
    365             cal.set(Calendar.DAY_OF_MONTH, test[3]);
    366             if (roll) {
    367                 cal.roll(test[4], test[5]);
    368             } else {
    369                 cal.add(test[4], test[5]);
    370             }
    371             if (cal.get(Calendar.EXTENDED_YEAR) != test[6] || cal.get(MONTH) != (test[7] - 1)
    372                     || cal.get(Calendar.IS_LEAP_MONTH) != test[8] || cal.get(DATE) != test[9]) {
    373                 errln("Fail: " + name + " " + ymdToString(test[0], test[1] - 1, test[2], test[3]) + " "
    374                         + fieldName(test[4]) + " by " + test[5] + ": expected "
    375                         + ymdToString(test[6], test[7] - 1, test[8], test[9]) + ", got " + ymdToString(cal));
    376             } else if (isVerbose()) {
    377                 logln("OK: " + name + " " + ymdToString(test[0], test[1] - 1, test[2], test[3]) + " "
    378                         + fieldName(test[4]) + " by " + test[5] + ": got " + ymdToString(cal));
    379             }
    380         }
    381     }
    382 
    383     /**
    384      * Convert year,month,day values to the form "year/month/day".
    385      * On input the month value is zero-based, but in the result string it is one-based.
    386      */
    387     static public String ymdToString(int year, int month, int isLeapMonth, int day) {
    388         return "" + year + "/" + (month + 1) + ((isLeapMonth != 0) ? "(leap)" : "") + "/" + day;
    389     }
    390 
    391     @Test
    392     public void TestCoverage() {
    393         // DangiCalendar()
    394         // DangiCalendar(Date)
    395         // DangiCalendar(TimeZone, ULocale)
    396         Date d = new Date();
    397 
    398         DangiCalendar cal1 = new DangiCalendar();
    399         cal1.setTime(d);
    400 
    401         DangiCalendar cal2 = new DangiCalendar(d);
    402 
    403         DangiCalendar cal3 = new DangiCalendar(TimeZone.getDefault(), ULocale.getDefault());
    404         cal3.setTime(d);
    405 
    406         assertEquals("DangiCalendar() and DangiCalendar(Date)", cal1, cal2);
    407         assertEquals("DangiCalendar() and DangiCalendar(TimeZone,ULocale)", cal1, cal3);
    408 
    409         // String getType()
    410         String type = cal1.getType();
    411         assertEquals("getType()", "dangi", type);
    412     }
    413 
    414     @Test
    415     public void TestInitWithCurrentTime() {
    416         // If the chinese calendar current millis isn't called, the default year is wrong.
    417         // this test is assuming the 'year' is the current cycle
    418         // so when we cross a cycle boundary, the target will need to change
    419         // that shouldn't be for awhile yet...
    420 
    421         Calendar cc = Calendar.getInstance(new ULocale("ko_KR@calendar=dangi"));
    422         cc.set(Calendar.EXTENDED_YEAR, 4338);
    423         cc.set(Calendar.MONTH, 0);
    424          // need to set leap month flag off, otherwise, the test case always fails when
    425          // current time is in a leap month
    426         cc.set(Calendar.IS_LEAP_MONTH, 0);
    427         cc.set(Calendar.DATE, 19);
    428         cc.set(Calendar.HOUR_OF_DAY, 0);
    429         cc.set(Calendar.MINUTE, 0);
    430         cc.set(Calendar.SECOND, 0);
    431         cc.set(Calendar.MILLISECOND, 0);
    432 
    433         cc.add(Calendar.DATE, 1);
    434 
    435         Calendar cal = new GregorianCalendar(2005, Calendar.FEBRUARY, 28);
    436         Date target = cal.getTime();
    437         Date result = cc.getTime();
    438 
    439         assertEquals("chinese and gregorian date should match", target, result);
    440     }
    441 }
    442