blob: 09a0d12ccc27b31505616363659930418aca326b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.util.calendar;
27
28import java.io.File;
29import java.io.FileInputStream;
30import java.io.IOException;
31import java.security.AccessController;
32import java.security.PrivilegedAction;
33import java.security.PrivilegedActionException;
34import java.security.PrivilegedExceptionAction;
35import java.util.ArrayList;
36import java.util.List;
37import java.util.Properties;
38import java.util.StringTokenizer;
39import java.util.TimeZone;
40
41/**
42 *
43 * @author Masayoshi Okutsu
44 * @since 1.6
45 */
46
47public class LocalGregorianCalendar extends BaseCalendar {
48 private String name;
49 private Era[] eras;
50
51 public static class Date extends BaseCalendar.Date {
52
53 protected Date() {
54 super();
55 }
56
57 protected Date(TimeZone zone) {
58 super(zone);
59 }
60
61 private int gregorianYear = FIELD_UNDEFINED;
62
63 public Date setEra(Era era) {
64 if (getEra() != era) {
65 super.setEra(era);
66 gregorianYear = FIELD_UNDEFINED;
67 }
68 return this;
69 }
70
71 public Date addYear(int localYear) {
72 super.addYear(localYear);
73 gregorianYear += localYear;
74 return this;
75 }
76
77 public Date setYear(int localYear) {
78 if (getYear() != localYear) {
79 super.setYear(localYear);
80 gregorianYear = FIELD_UNDEFINED;
81 }
82 return this;
83 }
84
85 public int getNormalizedYear() {
86 return gregorianYear;
87 }
88
89 public void setNormalizedYear(int normalizedYear) {
90 this.gregorianYear = normalizedYear;
91 }
92
93 void setLocalEra(Era era) {
94 super.setEra(era);
95 }
96
97 void setLocalYear(int year) {
98 super.setYear(year);
99 }
100
101 public String toString() {
102 String time = super.toString();
103 time = time.substring(time.indexOf('T'));
104 StringBuffer sb = new StringBuffer();
105 Era era = getEra();
106 if (era != null) {
107 String abbr = era.getAbbreviation();
108 if (abbr != null) {
109 sb.append(abbr);
110 }
111 }
112 sb.append(getYear()).append('.');
113 CalendarUtils.sprintf0d(sb, getMonth(), 2).append('.');
114 CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);
115 sb.append(time);
116 return sb.toString();
117 }
118 }
119
120 static LocalGregorianCalendar getLocalGregorianCalendar(String name) {
121 Properties calendarProps = null;
122 try {
123 String homeDir = AccessController.doPrivileged(
124 new sun.security.action.GetPropertyAction("java.home"));
125 final String fname = homeDir + File.separator + "lib" + File.separator
126 + "calendars.properties";
127 calendarProps = (Properties) AccessController.doPrivileged(new PrivilegedExceptionAction() {
128 public Object run() throws IOException {
129 Properties props = new Properties();
130 props.load(new FileInputStream(fname));
131 return props;
132 }
133 });
134 } catch (PrivilegedActionException e) {
135 throw new RuntimeException(e.getException());
136 }
137
138 // Parse calendar.*.eras
139 String props = calendarProps.getProperty("calendar." + name + ".eras");
140 if (props == null) {
141 return null;
142 }
143 List<Era> eras = new ArrayList<Era>();
144 StringTokenizer eraTokens = new StringTokenizer(props, ";");
145 while (eraTokens.hasMoreTokens()) {
146 String items = eraTokens.nextToken().trim();
147 StringTokenizer itemTokens = new StringTokenizer(items, ",");
148 String eraName = null;
149 boolean localTime = true;
150 long since = 0;
151 String abbr = null;
152
153 while (itemTokens.hasMoreTokens()) {
154 String item = itemTokens.nextToken();
155 int index = item.indexOf('=');
156 // it must be in the key=value form.
157 if (index == -1) {
158 return null;
159 }
160 String key = item.substring(0, index);
161 String value = item.substring(index + 1);
162 if ("name".equals(key)) {
163 eraName = value;
164 } else if ("since".equals(key)) {
165 if (value.endsWith("u")) {
166 localTime = false;
167 since = Long.parseLong(value.substring(0, value.length() - 1));
168 } else {
169 since = Long.parseLong(value);
170 }
171 } else if ("abbr".equals(key)) {
172 abbr = value;
173 } else {
174 throw new RuntimeException("Unknown key word: " + key);
175 }
176 }
177 Era era = new Era(eraName, abbr, since, localTime);
178 eras.add(era);
179 }
180 Era[] eraArray = new Era[eras.size()];
181 eras.toArray(eraArray);
182
183 return new LocalGregorianCalendar(name, eraArray);
184 }
185
186 private LocalGregorianCalendar(String name, Era[] eras) {
187 this.name = name;
188 this.eras = eras;
189 setEras(eras);
190 }
191
192 public String getName() {
193 return name;
194 }
195
196 public Date getCalendarDate() {
197 return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
198 }
199
200 public Date getCalendarDate(long millis) {
201 return getCalendarDate(millis, newCalendarDate());
202 }
203
204 public Date getCalendarDate(long millis, TimeZone zone) {
205 return getCalendarDate(millis, newCalendarDate(zone));
206 }
207
208 public Date getCalendarDate(long millis, CalendarDate date) {
209 Date ldate = (Date) super.getCalendarDate(millis, date);
210 return adjustYear(ldate, millis, ldate.getZoneOffset());
211 }
212
213 private Date adjustYear(Date ldate, long millis, int zoneOffset) {
214 int i;
215 for (i = eras.length - 1; i >= 0; --i) {
216 Era era = eras[i];
217 long since = era.getSince(null);
218 if (era.isLocalTime()) {
219 since -= zoneOffset;
220 }
221 if (millis >= since) {
222 ldate.setLocalEra(era);
223 int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
224 ldate.setLocalYear(y);
225 break;
226 }
227 }
228 if (i < 0) {
229 ldate.setLocalEra(null);
230 ldate.setLocalYear(ldate.getNormalizedYear());
231 }
232 ldate.setNormalized(true);
233 return ldate;
234 }
235
236 public Date newCalendarDate() {
237 return new Date();
238 }
239
240 public Date newCalendarDate(TimeZone zone) {
241 return new Date(zone);
242 }
243
244 public boolean validate(CalendarDate date) {
245 Date ldate = (Date) date;
246 Era era = ldate.getEra();
247 if (era != null) {
248 if (!validateEra(era)) {
249 return false;
250 }
251 ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear());
252 } else {
253 ldate.setNormalizedYear(ldate.getYear());
254 }
255 return super.validate(ldate);
256 }
257
258 private boolean validateEra(Era era) {
259 // Validate the era
260 for (int i = 0; i < eras.length; i++) {
261 if (era == eras[i]) {
262 return true;
263 }
264 }
265 return false;
266 }
267
268 public boolean normalize(CalendarDate date) {
269 if (date.isNormalized()) {
270 return true;
271 }
272
273 normalizeYear(date);
274 Date ldate = (Date) date;
275
276 // Normalize it as a Gregorian date and get its millisecond value
277 super.normalize(ldate);
278
279 boolean hasMillis = false;
280 long millis = 0;
281 int year = ldate.getNormalizedYear();
282 int i;
283 Era era = null;
284 for (i = eras.length - 1; i >= 0; --i) {
285 era = eras[i];
286 if (era.isLocalTime()) {
287 CalendarDate sinceDate = era.getSinceDate();
288 int sinceYear = sinceDate.getYear();
289 if (year > sinceYear) {
290 break;
291 }
292 if (year == sinceYear) {
293 int month = ldate.getMonth();
294 int sinceMonth = sinceDate.getMonth();
295 if (month > sinceMonth) {
296 break;
297 }
298 if (month == sinceMonth) {
299 int day = ldate.getDayOfMonth();
300 int sinceDay = sinceDate.getDayOfMonth();
301 if (day > sinceDay) {
302 break;
303 }
304 if (day == sinceDay) {
305 long timeOfDay = ldate.getTimeOfDay();
306 long sinceTimeOfDay = sinceDate.getTimeOfDay();
307 if (timeOfDay >= sinceTimeOfDay) {
308 break;
309 }
310 --i;
311 break;
312 }
313 }
314 }
315 } else {
316 if (!hasMillis) {
317 millis = super.getTime(date);
318 hasMillis = true;
319 }
320
321 long since = era.getSince(date.getZone());
322 if (millis >= since) {
323 break;
324 }
325 }
326 }
327 if (i >= 0) {
328 ldate.setLocalEra(era);
329 int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
330 ldate.setLocalYear(y);
331 } else {
332 // Set Gregorian year with no era
333 ldate.setEra(null);
334 ldate.setLocalYear(year);
335 ldate.setNormalizedYear(year);
336 }
337 ldate.setNormalized(true);
338 return true;
339 }
340
341 void normalizeMonth(CalendarDate date) {
342 normalizeYear(date);
343 super.normalizeMonth(date);
344 }
345
346 void normalizeYear(CalendarDate date) {
347 Date ldate = (Date) date;
348 // Set the supposed-to-be-correct Gregorian year first
349 // e.g., Showa 90 becomes 2015 (1926 + 90 - 1).
350 Era era = ldate.getEra();
351 if (era == null || !validateEra(era)) {
352 ldate.setNormalizedYear(ldate.getYear());
353 } else {
354 ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
355 }
356 }
357
358 /**
359 * Returns whether the specified Gregorian year is a leap year.
360 * @see #isLeapYear(Era, int)
361 */
362 public boolean isLeapYear(int gregorianYear) {
363 return CalendarUtils.isGregorianLeapYear(gregorianYear);
364 }
365
366 public boolean isLeapYear(Era era, int year) {
367 if (era == null) {
368 return isLeapYear(year);
369 }
370 int gyear = era.getSinceDate().getYear() + year - 1;
371 return isLeapYear(gyear);
372 }
373
374 public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
375 Date ldate = (Date) date;
376 super.getCalendarDateFromFixedDate(ldate, fixedDate);
377 adjustYear(ldate, (fixedDate - EPOCH_OFFSET) * DAY_IN_MILLIS, 0);
378 }
379}