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