]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/classes/core/src/com/ibm/icu/impl/Grego.java
Added flags.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / core / src / com / ibm / icu / impl / Grego.java
1 /**
2  *******************************************************************************
3  * Copyright (C) 2003-2008, International Business Machines Corporation and
4  * others. All Rights Reserved.
5  *******************************************************************************
6  * Partial port from ICU4C's Grego class in i18n/gregoimp.h.
7  *
8  * Methods ported, or moved here from OlsonTimeZone, initially
9  * for work on Jitterbug 5470:
10  *   tzdata2006n Brazil incorrect fall-back date 2009-mar-01
11  * Only the methods necessary for that work are provided - this is not a full
12  * port of ICU4C's Grego class (yet).
13  *
14  * These utilities are used by both OlsonTimeZone and SimpleTimeZone.
15  */
16
17 package com.ibm.icu.impl;
18
19 import com.ibm.icu.util.Calendar;
20
21 /**
22  * A utility class providing proleptic Gregorian calendar functions
23  * used by time zone and calendar code.  Do not instantiate.
24  *
25  * Note:  Unlike GregorianCalendar, all computations performed by this
26  * class occur in the pure proleptic GregorianCalendar.
27  */
28 public class Grego {
29
30     // Max/min milliseconds 
31     public static final long MIN_MILLIS = -184303902528000000L;
32     public static final long MAX_MILLIS = 183882168921600000L;
33
34     public static final int MILLIS_PER_SECOND = 1000;
35     public static final int MILLIS_PER_MINUTE = 60*MILLIS_PER_SECOND;
36     public static final int MILLIS_PER_HOUR = 60*MILLIS_PER_MINUTE;
37     public static final int MILLIS_PER_DAY = 24*MILLIS_PER_HOUR;
38     
39     //  January 1, 1 CE Gregorian
40     private static final int JULIAN_1_CE = 1721426;
41
42     //  January 1, 1970 CE Gregorian
43     private static final int JULIAN_1970_CE = 2440588;
44
45     private static final int[] MONTH_LENGTH = new int[] {
46         31,28,31,30,31,30,31,31,30,31,30,31,
47         31,29,31,30,31,30,31,31,30,31,30,31
48     };
49
50     private static final int[] DAYS_BEFORE = new int[] {
51         0,31,59,90,120,151,181,212,243,273,304,334,
52         0,31,60,91,121,152,182,213,244,274,305,335 };
53
54     /**
55      * Return true if the given year is a leap year.
56      * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
57      * @return true if the year is a leap year
58      */
59     public static final boolean isLeapYear(int year) {
60         // year&0x3 == year%4
61         return ((year&0x3) == 0) && ((year%100 != 0) || (year%400 == 0));
62     }
63
64     /**
65      * Return the number of days in the given month.
66      * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
67      * @param month 0-based month, with 0==Jan
68      * @return the number of days in the given month
69      */
70     public static final int monthLength(int year, int month) {
71         return MONTH_LENGTH[month + (isLeapYear(year) ? 12 : 0)];
72     }
73
74     /**
75      * Return the length of a previous month of the Gregorian calendar.
76      * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
77      * @param month 0-based month, with 0==Jan
78      * @return the number of days in the month previous to the given month
79      */
80     public static final int previousMonthLength(int year, int month) {
81         return (month > 0) ? monthLength(year, month-1) : 31;
82     }
83
84     /**
85      * Convert a year, month, and day-of-month, given in the proleptic
86      * Gregorian calendar, to 1970 epoch days.
87      * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
88      * @param month 0-based month, with 0==Jan
89      * @param dom 1-based day of month
90      * @return the day number, with day 0 == Jan 1 1970
91      */
92     public static long fieldsToDay(int year, int month, int dom) {
93         int y = year - 1;
94         long julian =
95             365 * y + floorDivide(y, 4) + (JULIAN_1_CE - 3) +    // Julian cal
96             floorDivide(y, 400) - floorDivide(y, 100) + 2 +   // => Gregorian cal
97             DAYS_BEFORE[month + (isLeapYear(year) ? 12 : 0)] + dom; // => month/dom
98         return julian - JULIAN_1970_CE; // JD => epoch day
99     }
100
101     /**
102      * Return the day of week on the 1970-epoch day
103      * @param day the 1970-epoch day (integral value)
104      * @return the day of week
105      */
106     public static int dayOfWeek(long day) {
107         long[] remainder = new long[1];
108         floorDivide(day + Calendar.THURSDAY, 7, remainder);
109         int dayOfWeek = (int)remainder[0];
110         dayOfWeek = (dayOfWeek == 0) ? 7 : dayOfWeek;
111         return dayOfWeek;
112     }
113
114     public static int[] dayToFields(long day, int[] fields) {
115         if (fields == null || fields.length < 5) {
116             fields = new int[5];
117         }
118         // Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
119         day += JULIAN_1970_CE - JULIAN_1_CE;
120
121         long[] rem = new long[1];
122         long n400 = floorDivide(day, 146097, rem);
123         long n100 = floorDivide(rem[0], 36524, rem);
124         long n4 = floorDivide(rem[0], 1461, rem);
125         long n1 = floorDivide(rem[0], 365, rem);
126
127         int year = (int)(400 * n400 + 100 * n100 + 4 * n4 + n1);
128         int dayOfYear = (int)rem[0];
129         if (n100 == 4 || n1 == 4) {
130             dayOfYear = 365;    // Dec 31 at end of 4- or 400-yr cycle
131         }
132         else {
133             ++year;
134         }
135
136         boolean isLeap = isLeapYear(year);
137         int correction = 0;
138         int march1 = isLeap ? 60 : 59;  // zero-based DOY for March 1
139         if (dayOfYear >= march1) {
140             correction = isLeap ? 1 : 2;
141         }
142         int month = (12 * (dayOfYear + correction) + 6) / 367;  // zero-based month
143         int dayOfMonth = dayOfYear - DAYS_BEFORE[isLeap ? month + 12 : month] + 1; // one-based DOM
144         int dayOfWeek = (int)((day + 2) % 7);  // day 0 is Monday(2)
145         if (dayOfWeek < 1 /* Sunday */) {
146             dayOfWeek += 7;
147         }
148         dayOfYear++; // 1-based day of year
149
150         fields[0] = year;
151         fields[1] = month;
152         fields[2] = dayOfMonth;
153         fields[3] = dayOfWeek;
154         fields[4] = dayOfYear;
155
156         return fields;
157     }
158
159     /*
160      * Convert long time to date/time fields
161      * 
162      * result[0] : year
163      * result[1] : month
164      * result[2] : dayOfMonth
165      * result[3] : dayOfWeek
166      * result[4] : dayOfYear
167      * result[5] : millisecond in day
168      */
169     public static int[] timeToFields(long time, int[] fields) {
170         if (fields == null || fields.length < 6) {
171             fields = new int[6];
172         }
173         long[] remainder = new long[1];
174         long day = floorDivide(time, 24*60*60*1000 /* milliseconds per day */, remainder);
175         dayToFields(day, fields);
176         fields[5] = (int)remainder[0];
177         return fields;
178     }
179
180     public static long floorDivide(long numerator, long denominator) {
181         // We do this computation in order to handle
182         // a numerator of Long.MIN_VALUE correctly
183         return (numerator >= 0) ?
184             numerator / denominator :
185             ((numerator + 1) / denominator) - 1;
186     }
187
188     private static long floorDivide(long numerator, long denominator, long[] remainder) {
189         if (numerator >= 0) {
190             remainder[0] = numerator % denominator;
191             return numerator / denominator;
192         }
193         long quotient = ((numerator + 1) / denominator) - 1;
194         remainder[0] = numerator - (quotient * denominator);
195         return quotient;
196     }
197
198     /*
199      * Returns the ordinal number for the specified day of week in the month.
200      * The valid return value is 1, 2, 3, 4 or -1.
201      */
202     public static int getDayOfWeekInMonth(int year, int month, int dayOfMonth) {
203         int weekInMonth = (dayOfMonth + 6)/7;
204         if (weekInMonth == 4) {
205             if (dayOfMonth + 7 > monthLength(year, month)) {
206                 weekInMonth = -1;
207             }
208         } else if (weekInMonth == 5) {
209             weekInMonth = -1;
210         }
211         return weekInMonth;
212     }
213 }