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