diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/impl/Grego.java b/icu4j/main/core/src/main/java/com/ibm/icu/impl/Grego.java index e10e49e64ae..50f38efa8b4 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/impl/Grego.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/impl/Grego.java @@ -107,48 +107,55 @@ public class Grego { * @return the day of week */ public static int dayOfWeek(long day) { - long[] remainder = new long[1]; - floorDivide(day + 5 /* Calendar.THURSDAY */, 7, remainder); - int dayOfWeek = (int)remainder[0]; + Pair result = floorDivideAndRemainer(day + 5 /* Calendar.THURSDAY */, 7); + int dayOfWeek = result.second; dayOfWeek = (dayOfWeek == 0) ? 7 : dayOfWeek; return dayOfWeek; } + public static Pair dayToYear(long day) { + // Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar) + day += JULIAN_1970_CE - JULIAN_1_CE; + Pair n400 = floorDivideAndRemainer(day, 146097); + Pair n100 = floorDivideAndRemainer(n400.second, 36524); + Pair n4 = floorDivideAndRemainer(n100.second, 1461); + Pair n1 = floorDivideAndRemainer(n4.second, 365); + + int year = (int)(400 * n400.first + 100 * n100.first + 4 * n4.first + n1.first); + int dayOfYear = n1.second; + if (n100.first == 4 || n1.first == 4) { + dayOfYear = 365; // Dec 31 at end of 4- or 400-yr cycle + } + else { + ++year; + } + dayOfYear++; // 1-based day of year + return new Pair(year, dayOfYear); + } + public static int[] dayToFields(long day, int[] fields) { if (fields == null || fields.length < 5) { fields = new int[5]; } + Pair result = dayToYear(day); + int year = result.first; + int dayOfYear = result.second; // Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar) day += JULIAN_1970_CE - JULIAN_1_CE; - long[] rem = new long[1]; - long n400 = floorDivide(day, 146097, rem); - long n100 = floorDivide(rem[0], 36524, rem); - long n4 = floorDivide(rem[0], 1461, rem); - long n1 = floorDivide(rem[0], 365, rem); - - int year = (int)(400 * n400 + 100 * n100 + 4 * n4 + n1); - int dayOfYear = (int)rem[0]; - if (n100 == 4 || n1 == 4) { - dayOfYear = 365; // Dec 31 at end of 4- or 400-yr cycle - } - else { - ++year; - } boolean isLeap = isLeapYear(year); int correction = 0; int march1 = isLeap ? 60 : 59; // zero-based DOY for March 1 - if (dayOfYear >= march1) { + if (dayOfYear > march1) { correction = isLeap ? 1 : 2; } - int month = (12 * (dayOfYear + correction) + 6) / 367; // zero-based month - int dayOfMonth = dayOfYear - DAYS_BEFORE[isLeap ? month + 12 : month] + 1; // one-based DOM + int month = (12 * (dayOfYear - 1 + correction) + 6) / 367; // zero-based month + int dayOfMonth = dayOfYear - DAYS_BEFORE[isLeap ? month + 12 : month]; // one-based DOM int dayOfWeek = (int)((day + 2) % 7); // day 0 is Monday(2) if (dayOfWeek < 1 /* Sunday */) { dayOfWeek += 7; } - dayOfYear++; // 1-based day of year fields[0] = year; fields[1] = month; @@ -173,13 +180,16 @@ public class Grego { if (fields == null || fields.length < 6) { fields = new int[6]; } - long[] remainder = new long[1]; - long day = floorDivide(time, 24*60*60*1000 /* milliseconds per day */, remainder); - dayToFields(day, fields); - fields[5] = (int)remainder[0]; + Pair result = floorDivideAndRemainer(time, 24*60*60*1000 /* milliseconds per day */); + dayToFields(result.first, fields); + fields[5] = result.second; return fields; } + public static int timeToYear(long time) { + return dayToYear(floorDivideAndRemainer(time, 24*60*60*1000 /* milliseconds per day */).first).first; + } + public static long floorDivide(long numerator, long denominator) { // We do this computation in order to handle // a numerator of Long.MIN_VALUE correctly @@ -188,14 +198,12 @@ public class Grego { ((numerator + 1) / denominator) - 1; } - private static long floorDivide(long numerator, long denominator, long[] remainder) { + private static Pair floorDivideAndRemainer(long numerator, int denominator) { if (numerator >= 0) { - remainder[0] = numerator % denominator; - return numerator / denominator; + return new Pair(floorDivide(numerator, denominator), (int)(numerator % denominator)); } - long quotient = ((numerator + 1) / denominator) - 1; - remainder[0] = numerator - (quotient * denominator); - return quotient; + long quotient = floorDivide(numerator, denominator); + return new Pair(quotient, (int)(numerator - (quotient * denominator))); } /* diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/impl/OlsonTimeZone.java b/icu4j/main/core/src/main/java/com/ibm/icu/impl/OlsonTimeZone.java index 5f5c7c8d333..c1d6ce6cbf2 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/impl/OlsonTimeZone.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/impl/OlsonTimeZone.java @@ -234,10 +234,8 @@ public class OlsonTimeZone extends BasicTimeZone { } } - int[] fields = Grego.timeToFields(current, null); - - finalStartYear = fields[0]; - finalStartMillis = Grego.fieldsToDay(fields[0], 0, 1); + finalStartYear = Grego.timeToYear(current); + finalStartMillis = Grego.fieldsToDay(finalStartYear, 0, 1); if (bDst) { // we probably do not need to set start year of final rule @@ -314,11 +312,11 @@ public class OlsonTimeZone extends BasicTimeZone { return (finalZone != null && finalZone.useDaylightTime()); } - int[] fields = Grego.timeToFields(current, null); + int year = Grego.timeToYear(current); // Find start of this year, and start of next year - long start = Grego.fieldsToDay(fields[0], 0, 1) * SECONDS_PER_DAY; - long limit = Grego.fieldsToDay(fields[0] + 1, 0, 1) * SECONDS_PER_DAY; + long start = Grego.fieldsToDay(year, 0, 1) * SECONDS_PER_DAY; + long limit = Grego.fieldsToDay(year + 1, 0, 1) * SECONDS_PER_DAY; // Return true if DST is observed at any time during the current // year. @@ -1296,4 +1294,4 @@ public class OlsonTimeZone extends BasicTimeZone { tz.isFrozen = false; return tz; } -} \ No newline at end of file +} diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/util/AnnualTimeZoneRule.java b/icu4j/main/core/src/main/java/com/ibm/icu/util/AnnualTimeZoneRule.java index c1bb6daf812..8427e617d4d 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/util/AnnualTimeZoneRule.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/util/AnnualTimeZoneRule.java @@ -191,8 +191,7 @@ public class AnnualTimeZoneRule extends TimeZoneRule { */ @Override public Date getNextStart(long base, int prevRawOffset, int prevDSTSavings, boolean inclusive) { - int[] fields = Grego.timeToFields(base, null); - int year = fields[0]; + int year = Grego.timeToYear(base); if (year < startYear) { return getFirstStart(prevRawOffset, prevDSTSavings); } @@ -209,8 +208,7 @@ public class AnnualTimeZoneRule extends TimeZoneRule { */ @Override public Date getPreviousStart(long base, int prevRawOffset, int prevDSTSavings, boolean inclusive) { - int[] fields = Grego.timeToFields(base, null); - int year = fields[0]; + int year = Grego.timeToYear(base); if (year > endYear) { return getFinalStart(prevRawOffset, prevDSTSavings); } diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/util/BasicTimeZone.java b/icu4j/main/core/src/main/java/com/ibm/icu/util/BasicTimeZone.java index cb78582a8b0..50483f0799c 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/util/BasicTimeZone.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/util/BasicTimeZone.java @@ -342,12 +342,10 @@ public abstract class BasicTimeZone extends TimeZone { filteredRules.add(ar); } else { // Calculate the transition year - int[] dfields = new int[6]; - Grego.timeToFields(tzt.getTime(), dfields); // Recreate the rule AnnualTimeZoneRule newar = new AnnualTimeZoneRule(ar.getName(), ar.getRawOffset(), ar.getDSTSavings(), - ar.getRule(), dfields[0], ar.getEndYear()); + ar.getRule(), Grego.timeToYear(tzt.getTime()), ar.getEndYear()); filteredRules.add(newar); } // Check if this is a final rule diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/util/VTimeZone.java b/icu4j/main/core/src/main/java/com/ibm/icu/util/VTimeZone.java index 6edcc825686..be953b09908 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/util/VTimeZone.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/util/VTimeZone.java @@ -823,14 +823,13 @@ public class VTimeZone extends BasicTimeZone { DateTimeRule.UTC_TIME); } else { // Update the end year - int fields[] = Grego.timeToFields(start.getTime(), null); newRule = new AnnualTimeZoneRule( finalRule.getName(), finalRule.getRawOffset(), finalRule.getDSTSavings(), finalRule.getRule(), finalRule.getStartYear(), - fields[0]); + Grego.timeToYear(start.getTime())); } rules.set(finalRuleIdx, newRule); }