2 *******************************************************************************
\r
3 * Copyright (C) 2007-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.util;
\r
8 import java.util.Date;
\r
10 import com.ibm.icu.impl.Grego;
\r
14 * <code>AnnualTimeZoneRule</code> is a class used for representing a time zone
\r
15 * rule which takes effect annually. Years used in this class are
\r
16 * all Gregorian calendar years.
\r
20 public class AnnualTimeZoneRule extends TimeZoneRule {
\r
22 private static final long serialVersionUID = -8870666707791230688L;
\r
25 * The constant representing the maximum year used for designating a rule is permanent.
\r
28 public static final int MAX_YEAR = Integer.MAX_VALUE;
\r
30 private final DateTimeRule dateTimeRule;
\r
31 private final int startYear;
\r
32 private final int endYear;
\r
35 * Constructs a <code>AnnualTimeZoneRule</code> with the name, the GMT offset of its
\r
36 * standard time, the amount of daylight saving offset adjustment,
\r
37 * the annual start time rule and the start/until years.
\r
39 * @param name The time zone name.
\r
40 * @param rawOffset The GMT offset of its standard time in milliseconds.
\r
41 * @param dstSavings The amount of daylight saving offset adjustment in
\r
42 * milliseconds. If this ia a rule for standard time,
\r
43 * the value of this argument is 0.
\r
44 * @param dateTimeRule The start date/time rule repeated annually.
\r
45 * @param startYear The first year when this rule takes effect.
\r
46 * @param endYear The last year when this rule takes effect. If this
\r
47 * rule is effective forever in future, specify MAX_YEAR.
\r
51 public AnnualTimeZoneRule(String name, int rawOffset, int dstSavings,
\r
52 DateTimeRule dateTimeRule, int startYear, int endYear) {
\r
53 super(name, rawOffset, dstSavings);
\r
54 this.dateTimeRule = dateTimeRule;
\r
55 this.startYear = startYear;
\r
56 this.endYear = endYear > MAX_YEAR ? MAX_YEAR : endYear;
\r
60 * Gets the start date/time rule associated used by this rule.
\r
62 * @return An <code>AnnualDateTimeRule</code> which represents the start date/time
\r
63 * rule used by this time zone rule.
\r
67 public DateTimeRule getRule() {
\r
68 return dateTimeRule;
\r
72 * Gets the first year when this rule takes effect.
\r
74 * @return The start year of this rule. The year is in Gregorian calendar
\r
75 * with 0 == 1 BCE, -1 == 2 BCE, etc.
\r
79 public int getStartYear() {
\r
84 * Gets the end year when this rule takes effect.
\r
86 * @return The end year of this rule (inclusive). The year is in Gregorian calendar
\r
87 * with 0 == 1 BCE, -1 == 2 BCE, etc.
\r
91 public int getEndYear() {
\r
96 * Gets the time when this rule takes effect in the given year.
\r
98 * @param year The Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
\r
99 * @param prevRawOffset The standard time offset from UTC before this rule
\r
100 * takes effect in milliseconds.
\r
101 * @param prevDSTSavings The amount of daylight saving offset from the
\r
104 * @return The time when this rule takes effect in the year, or
\r
105 * null if this rule is not applicable in the year.
\r
109 public Date getStartInYear(int year, int prevRawOffset, int prevDSTSavings) {
\r
110 if (year < startYear || year > endYear) {
\r
115 int type = dateTimeRule.getDateRuleType();
\r
117 if (type == DateTimeRule.DOM) {
\r
118 ruleDay = Grego.fieldsToDay(year, dateTimeRule.getRuleMonth(), dateTimeRule.getRuleDayOfMonth());
\r
120 boolean after = true;
\r
121 if (type == DateTimeRule.DOW) {
\r
122 int weeks = dateTimeRule.getRuleWeekInMonth();
\r
124 ruleDay = Grego.fieldsToDay(year, dateTimeRule.getRuleMonth(), 1);
\r
125 ruleDay += 7 * (weeks - 1);
\r
128 ruleDay = Grego.fieldsToDay(year, dateTimeRule.getRuleMonth(),
\r
129 Grego.monthLength(year, dateTimeRule.getRuleMonth()));
\r
130 ruleDay += 7 * (weeks + 1);
\r
133 int month = dateTimeRule.getRuleMonth();
\r
134 int dom = dateTimeRule.getRuleDayOfMonth();
\r
135 if (type == DateTimeRule.DOW_LEQ_DOM) {
\r
138 if (month == Calendar.FEBRUARY && dom == 29 && !Grego.isLeapYear(year)) {
\r
142 ruleDay = Grego.fieldsToDay(year, month, dom);
\r
145 int dow = Grego.dayOfWeek(ruleDay);
\r
146 int delta = dateTimeRule.getRuleDayOfWeek() - dow;
\r
148 delta = delta < 0 ? delta + 7 : delta;
\r
150 delta = delta > 0 ? delta - 7 : delta;
\r
155 long ruleTime = ruleDay * Grego.MILLIS_PER_DAY + dateTimeRule.getRuleMillisInDay();
\r
156 if (dateTimeRule.getTimeRuleType() != DateTimeRule.UTC_TIME) {
\r
157 ruleTime -= prevRawOffset;
\r
159 if (dateTimeRule.getTimeRuleType() == DateTimeRule.WALL_TIME) {
\r
160 ruleTime -= prevDSTSavings;
\r
162 return new Date(ruleTime);
\r
169 public Date getFirstStart(int prevRawOffset, int prevDSTSavings) {
\r
170 return getStartInYear(startYear, prevRawOffset, prevDSTSavings);
\r
177 public Date getFinalStart(int prevRawOffset, int prevDSTSavings) {
\r
178 if (endYear == MAX_YEAR) {
\r
181 return getStartInYear(endYear, prevRawOffset, prevDSTSavings);
\r
188 public Date getNextStart(long base, int prevRawOffset, int prevDSTSavings, boolean inclusive) {
\r
189 int[] fields = Grego.timeToFields(base, null);
\r
190 int year = fields[0];
\r
191 if (year < startYear) {
\r
192 return getFirstStart(prevRawOffset, prevDSTSavings);
\r
194 Date d = getStartInYear(year, prevRawOffset, prevDSTSavings);
\r
195 if (d != null && (d.getTime() < base || (!inclusive && (d.getTime() == base)))) {
\r
196 d = getStartInYear(year + 1, prevRawOffset, prevDSTSavings);
\r
205 public Date getPreviousStart(long base, int prevRawOffset, int prevDSTSavings, boolean inclusive) {
\r
206 int[] fields = Grego.timeToFields(base, null);
\r
207 int year = fields[0];
\r
208 if (year > endYear) {
\r
209 return getFinalStart(prevRawOffset, prevDSTSavings);
\r
211 Date d = getStartInYear(year, prevRawOffset, prevDSTSavings);
\r
212 if (d != null && (d.getTime() > base || (!inclusive && (d.getTime() == base)))) {
\r
213 d = getStartInYear(year - 1, prevRawOffset, prevDSTSavings);
\r
222 public boolean isEquivalentTo(TimeZoneRule other) {
\r
223 if (!(other instanceof AnnualTimeZoneRule)) {
\r
226 AnnualTimeZoneRule otherRule = (AnnualTimeZoneRule)other;
\r
227 if (startYear == otherRule.startYear
\r
228 && endYear == otherRule.endYear
\r
229 && dateTimeRule.equals(otherRule.dateTimeRule)) {
\r
230 return super.isEquivalentTo(other);
\r
236 * {@inheritDoc}<br><br>
\r
237 * Note: This method in <code>AnnualTimeZoneRule</code> always returns true.
\r
240 public boolean isTransitionRule() {
\r
245 * Returns a <code>String</code> representation of this <code>AnnualTimeZoneRule</code> object.
\r
246 * This method is used for debugging purpose only. The string representation can be changed
\r
247 * in future version of ICU without any notice.
\r
251 public String toString() {
\r
252 StringBuilder buf = new StringBuilder();
\r
253 buf.append(super.toString());
\r
254 buf.append(", rule={" + dateTimeRule + "}");
\r
255 buf.append(", startYear=" + startYear);
\r
256 buf.append(", endYear=");
\r
257 if (endYear == MAX_YEAR) {
\r
260 buf.append(endYear);
\r
262 return buf.toString();
\r