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