Initial revision
[gcc.git] / libjava / java / util / GregorianCalendar.java
1 /* Copyright (C) 1998, 1999 Cygnus Solutions
2
3 This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
7 details. */
8
9 package java.util;
10
11 /**
12 * @author Per Bothner <bothner@cygnus.com>
13 * @date October 24, 1998.
14 */
15
16 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3,
17 * and "The Java Language Specification", ISBN 0-201-63451-1.
18 * Status: "leniency" is not handled, and neither is roll-over in
19 * add and roll. This is partly because of unclear specification.
20 * hashCode has no spec.
21 */
22
23 public class GregorianCalendar extends Calendar {
24 public static final int BC = 0;
25 public static final int AD = 1;
26
27 // The fields are as specified in Sun's "Serialized Form"
28 // in the JDK 1.2 beta 4 API specification.
29 // Value from a simple test program (getGregorianChange.getTime()).
30 long gregorianCutover = -12219292800000L;
31
32 private final static int[] mins = {
33 0 /* ERA */,
34 1 /* YEAR */,
35 0 /* MONTH */,
36 0 /* WEEK_OF_YEAR */,
37 0 /* WEEK_OF_MONTH */,
38 1 /* DATE */,
39 1 /* DAY_OF_YEAR */,
40 1 /* DAY_OF_WEEK */,
41 -1 /* DAY_OF_WEEK_IN_MONTH */,
42 0 /* AM_PM */,
43 0 /* HOUR */,
44 0 /* HOUR_OF_DAY */,
45 0 /* MINUTE */,
46 0 /* SECOND */,
47 0 /* MILLISECOND */,
48 -43200000 /* ZONE_OFFSET */,
49 0 /* DST_OFFSET */
50 };
51
52 private final static int[] maxs = {
53 1 /* ERA */,
54 5000000 /* YEAR */,
55 11 /* MONTH */,
56 54 /* WEEK_OF_YEAR */,
57 6 /* WEEK_OF_MONTH */,
58 31 /* DATE */,
59 366 /* DAY_OF_YEAR */,
60 7 /* DAY_OF_WEEK */,
61 6 /* DAY_OF_WEEK_IN_MONTH */,
62 1 /* AM_PM */,
63 12 /* HOUR */,
64 23 /* HOUR_OF_DAY */,
65 59 /* MINUTE */,
66 59 /* SECOND */,
67 999 /* MILLISECOND */,
68 43200000 /* ZONE_OFFSET */,
69 3600000 /* DST_OFFSET */
70 };
71
72 private final static int[] leastMaximums = {
73 1 /* ERA */,
74 5000000 /* YEAR */,
75 11 /* MONTH */,
76 53 /* WEEK_OF_YEAR */,
77 6 /* WEEK_OF_MONTH */,
78 28 /* DATE */,
79 365 /* DAY_OF_YEAR */,
80 7 /* DAY_OF_WEEK */,
81 4 /* DAY_OF_WEEK_IN_MONTH */,
82 1 /* AM_PM */,
83 11 /* HOUR */,
84 23 /* HOUR_OF_DAY */,
85 59 /* MINUTE */,
86 59 /* SECOND */,
87 999 /* MILLISECOND */,
88 43200000 /* ZONE_OFFSET */,
89 3600000 /* DST_OFFSET */
90 };
91
92 public GregorianCalendar ()
93 {
94 this(null, null);
95 }
96
97 public GregorianCalendar (TimeZone zone)
98 {
99 this (zone, null);
100 }
101
102 public GregorianCalendar (Locale locale)
103 {
104 this (null, locale);
105 }
106
107 public GregorianCalendar (TimeZone zone, Locale locale)
108 {
109 super (zone, locale);
110 }
111
112 public GregorianCalendar (int year, int month, int date)
113 {
114 this((TimeZone) null);
115 set (year, month, date);
116 }
117
118 public GregorianCalendar (int year, int month, int date,
119 int hour, int minute)
120 {
121 this((TimeZone) null);
122 set (year, month, date, hour, minute);
123 }
124
125 public GregorianCalendar (int year, int month, int date,
126 int hour, int minute, int second)
127 {
128 this((TimeZone) null);
129 set (year, month, date, hour, minute, second);
130 }
131
132 public int getMinimum(int calfield) { return mins[calfield]; }
133 public int getGreatestMinimum(int calfield) { return mins[calfield]; }
134 public int getMaximum(int calfield) { return maxs[calfield]; }
135 public int getLeastMaximum(int calfield) { return leastMaximums[calfield]; }
136
137 protected native void computeFields();
138
139 protected native void computeTime();
140
141 public void add (int fld, int amount)
142 {
143 if (fld >= ZONE_OFFSET)
144 throw new IllegalArgumentException("bad field to add");
145 fields[fld] += amount;
146 adjust(fld);
147 }
148
149 public void roll (int fld, boolean up)
150 {
151 if (fld >= ZONE_OFFSET)
152 throw new IllegalArgumentException("bad field to roll");
153
154 int old = fields[fld];
155 if (up)
156 {
157 fields[fld] = old == getMaximum(fld) ? getMinimum(fld)
158 : old + 1;
159 }
160 else
161 {
162 fields[fld] = old == getMinimum(fld) ? getMaximum(fld)
163 : old - 1;
164 }
165 }
166
167 private void adjust (int fld)
168 {
169 int value = fields[fld];
170 int radix = maxs[fld] + 1;
171 switch (fld)
172 {
173 case MONTH:
174 case SECOND:
175 case MILLISECOND:
176 if (value >= radix)
177 {
178 int next = value / radix;
179 fields[fld] = value - radix * next;
180 fields[fld - 1] += next;
181 adjust(fld - 1);
182 }
183 else if (value < 0) // min[fld]
184 {
185 int next = (value - radix - 1) / radix;
186 fields[fld] = value - radix * next;
187 fields[fld - 1] += next;
188 adjust(fld - 1);
189 }
190 break;
191 }
192 }
193
194 public final Date getGregorianChange() { return new Date(gregorianCutover); }
195 public void setGregorianChange (Date date)
196 { gregorianCutover = date.getTime(); }
197
198 public boolean isLeapYear(int year)
199 {
200 if ((year % 4) != 0)
201 return false;
202 if ((year % 100) != 0 || (year % 400) == 0)
203 return true;
204 // year divisible by 100 but not 400.
205 GregorianCalendar date = new GregorianCalendar(year, FEBRUARY, 28);
206 return gregorianCutover < date.getTimeInMillis();
207 }
208
209 public boolean after (Object cal)
210 {
211 return cal instanceof Calendar
212 && getTimeInMillis() > ((Calendar) cal).getTimeInMillis();
213 }
214
215 public boolean before (Object cal)
216 {
217 return cal instanceof Calendar
218 && getTimeInMillis() < ((Calendar) cal).getTimeInMillis();
219 }
220
221 public boolean equals (Object obj)
222 {
223 if (obj == null || ! (obj instanceof GregorianCalendar))
224 return false;
225 GregorianCalendar other = (GregorianCalendar) obj;
226
227 for (int i = FIELD_COUNT; --i >= 0; )
228 {
229 boolean set = isSet[i];
230 if (set != other.isSet[i]
231 || (set && fields[i] != other.fields[i]))
232 return false;
233 }
234 if (areFieldsSet != other.areFieldsSet
235 || isTimeSet != other.isTimeSet
236 || (isTimeSet && time != other.time)
237 || getFirstDayOfWeek() != other.getFirstDayOfWeek()
238 || getMinimalDaysInFirstWeek() != other.getMinimalDaysInFirstWeek()
239 || isLenient() != other.isLenient()
240 || ! getTimeZone().equals(other.getTimeZone()))
241 return false;
242 return true;
243 }
244
245 public int hashCode ()
246 {
247 int hashcode = 0;
248 for (int i = FIELD_COUNT; --i >= 0; )
249 {
250 if (isSet[i])
251 hashcode += 37 * fields[i];
252 }
253 if (isTimeSet)
254 hashcode += 89 * time;
255 return hashcode;
256 }
257 }