1 /*
2  * Copyright (c) 2005, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.util.calendar;
27 
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.IOException;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import java.security.PrivilegedActionException;
34 import java.security.PrivilegedExceptionAction;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.Properties;
38 import java.util.StringTokenizer;
39 import java.util.TimeZone;
40 
41 /**
42  *
43  * @author Masayoshi Okutsu
44  * @since 1.6
45  */
46 
47 public class LocalGregorianCalendar extends BaseCalendar {
48     private String name;
49     private Era[] eras;
50 
51     public static class Date extends BaseCalendar.Date {
52 
Date()53         protected Date() {
54             super();
55         }
56 
Date(TimeZone zone)57         protected Date(TimeZone zone) {
58             super(zone);
59         }
60 
61         private int gregorianYear = FIELD_UNDEFINED;
62 
setEra(Era era)63         public Date setEra(Era era) {
64             if (getEra() != era) {
65                 super.setEra(era);
66                 gregorianYear = FIELD_UNDEFINED;
67             }
68             return this;
69         }
70 
addYear(int localYear)71         public Date addYear(int localYear) {
72             super.addYear(localYear);
73             gregorianYear += localYear;
74             return this;
75         }
76 
setYear(int localYear)77         public Date setYear(int localYear) {
78             if (getYear() != localYear) {
79                 super.setYear(localYear);
80                 gregorianYear = FIELD_UNDEFINED;
81             }
82             return this;
83         }
84 
getNormalizedYear()85         public int getNormalizedYear() {
86             return gregorianYear;
87         }
88 
setNormalizedYear(int normalizedYear)89         public void setNormalizedYear(int normalizedYear) {
90             this.gregorianYear = normalizedYear;
91         }
92 
setLocalEra(Era era)93         void setLocalEra(Era era) {
94             super.setEra(era);
95         }
96 
setLocalYear(int year)97         void setLocalYear(int year) {
98             super.setYear(year);
99         }
100 
toString()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 
getLocalGregorianCalendar(String name)120     static LocalGregorianCalendar getLocalGregorianCalendar(String name) {
121         // Android-changed: use getCalendarProperties()
122         Properties calendarProps;
123         try {
124             calendarProps = getCalendarProperties();
125         } catch (IOException e) {
126             throw new RuntimeException(e);
127         }
128 
129         // Parse calendar.*.eras
130         String props = calendarProps.getProperty("calendar." + name + ".eras");
131         if (props == null) {
132             return null;
133         }
134         List<Era> eras = new ArrayList<Era>();
135         StringTokenizer eraTokens = new StringTokenizer(props, ";");
136         while (eraTokens.hasMoreTokens()) {
137             String items = eraTokens.nextToken().trim();
138             StringTokenizer itemTokens = new StringTokenizer(items, ",");
139             String eraName = null;
140             boolean localTime = true;
141             long since = 0;
142             String abbr = null;
143 
144             while (itemTokens.hasMoreTokens()) {
145                 String item = itemTokens.nextToken();
146                 int index = item.indexOf('=');
147                 // it must be in the key=value form.
148                 if (index == -1) {
149                     return null;
150                 }
151                 String key = item.substring(0, index);
152                 String value = item.substring(index + 1);
153                 if ("name".equals(key)) {
154                     eraName = value;
155                 } else if ("since".equals(key)) {
156                     if (value.endsWith("u")) {
157                         localTime = false;
158                         since = Long.parseLong(value.substring(0, value.length() - 1));
159                     } else {
160                         since = Long.parseLong(value);
161                     }
162                 } else if ("abbr".equals(key)) {
163                     abbr = value;
164                 } else {
165                     throw new RuntimeException("Unknown key word: " + key);
166                 }
167             }
168             Era era = new Era(eraName, abbr, since, localTime);
169             eras.add(era);
170         }
171         // Android-changed: Throw if no eras were found, as other code depends on there being
172         // at least one era.
173         if (eras.isEmpty()) {
174             throw new RuntimeException("No eras for " + name);
175         }
176         Era[] eraArray = new Era[eras.size()];
177         eras.toArray(eraArray);
178 
179         return new LocalGregorianCalendar(name, eraArray);
180     }
181 
LocalGregorianCalendar(String name, Era[] eras)182     private LocalGregorianCalendar(String name, Era[] eras) {
183         this.name = name;
184         this.eras = eras;
185         setEras(eras);
186     }
187 
getName()188     public String getName() {
189         return name;
190     }
191 
getCalendarDate()192     public Date getCalendarDate() {
193         return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
194     }
195 
getCalendarDate(long millis)196     public Date getCalendarDate(long millis) {
197         return getCalendarDate(millis, newCalendarDate());
198     }
199 
getCalendarDate(long millis, TimeZone zone)200     public Date getCalendarDate(long millis, TimeZone zone) {
201         return getCalendarDate(millis, newCalendarDate(zone));
202     }
203 
getCalendarDate(long millis, CalendarDate date)204     public Date getCalendarDate(long millis, CalendarDate date) {
205         Date ldate = (Date) super.getCalendarDate(millis, date);
206         return adjustYear(ldate, millis, ldate.getZoneOffset());
207     }
208 
adjustYear(Date ldate, long millis, int zoneOffset)209     private Date adjustYear(Date ldate, long millis, int zoneOffset) {
210         int i;
211         for (i = eras.length - 1; i >= 0; --i) {
212             Era era = eras[i];
213             long since = era.getSince(null);
214             if (era.isLocalTime()) {
215                 since -= zoneOffset;
216             }
217             if (millis >= since) {
218                 ldate.setLocalEra(era);
219                 int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
220                 ldate.setLocalYear(y);
221                 break;
222             }
223         }
224         if (i < 0) {
225             ldate.setLocalEra(null);
226             ldate.setLocalYear(ldate.getNormalizedYear());
227         }
228         ldate.setNormalized(true);
229         return ldate;
230     }
231 
newCalendarDate()232     public Date newCalendarDate() {
233         return new Date();
234     }
235 
newCalendarDate(TimeZone zone)236     public Date newCalendarDate(TimeZone zone) {
237         return new Date(zone);
238     }
239 
validate(CalendarDate date)240     public boolean validate(CalendarDate date) {
241         Date ldate = (Date) date;
242         Era era = ldate.getEra();
243         if (era != null) {
244             if (!validateEra(era)) {
245                 return false;
246             }
247             ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
248             Date tmp = newCalendarDate(date.getZone());
249             tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth());
250             normalize(tmp);
251             if (tmp.getEra() != era) {
252                 return false;
253             }
254         } else {
255             if (date.getYear() >= eras[0].getSinceDate().getYear()) {
256                 return false;
257             }
258             ldate.setNormalizedYear(ldate.getYear());
259         }
260         return super.validate(ldate);
261     }
262 
validateEra(Era era)263     private boolean validateEra(Era era) {
264         // Validate the era
265         for (int i = 0; i < eras.length; i++) {
266             if (era == eras[i]) {
267                 return true;
268             }
269         }
270         return false;
271     }
272 
normalize(CalendarDate date)273     public boolean normalize(CalendarDate date) {
274         if (date.isNormalized()) {
275             return true;
276         }
277 
278         normalizeYear(date);
279         Date ldate = (Date) date;
280 
281         // Normalize it as a Gregorian date and get its millisecond value
282         super.normalize(ldate);
283 
284         boolean hasMillis = false;
285         long millis = 0;
286         int year = ldate.getNormalizedYear();
287         int i;
288         Era era = null;
289         for (i = eras.length - 1; i >= 0; --i) {
290             era = eras[i];
291             if (era.isLocalTime()) {
292                 CalendarDate sinceDate = era.getSinceDate();
293                 int sinceYear = sinceDate.getYear();
294                 if (year > sinceYear) {
295                     break;
296                 }
297                 if (year == sinceYear) {
298                     int month = ldate.getMonth();
299                     int sinceMonth = sinceDate.getMonth();
300                     if (month > sinceMonth) {
301                         break;
302                     }
303                     if (month == sinceMonth) {
304                         int day = ldate.getDayOfMonth();
305                         int sinceDay = sinceDate.getDayOfMonth();
306                         if (day > sinceDay) {
307                             break;
308                         }
309                         if (day == sinceDay) {
310                             long timeOfDay = ldate.getTimeOfDay();
311                             long sinceTimeOfDay = sinceDate.getTimeOfDay();
312                             if (timeOfDay >= sinceTimeOfDay) {
313                                 break;
314                             }
315                             --i;
316                             break;
317                         }
318                     }
319                 }
320             } else {
321                 if (!hasMillis) {
322                     millis  = super.getTime(date);
323                     hasMillis = true;
324                 }
325 
326                 long since = era.getSince(date.getZone());
327                 if (millis >= since) {
328                     break;
329                 }
330             }
331         }
332         if (i >= 0) {
333             ldate.setLocalEra(era);
334             int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
335             ldate.setLocalYear(y);
336         } else {
337             // Set Gregorian year with no era
338             ldate.setEra(null);
339             ldate.setLocalYear(year);
340             ldate.setNormalizedYear(year);
341         }
342         ldate.setNormalized(true);
343         return true;
344     }
345 
normalizeMonth(CalendarDate date)346     void normalizeMonth(CalendarDate date) {
347         normalizeYear(date);
348         super.normalizeMonth(date);
349     }
350 
normalizeYear(CalendarDate date)351     void normalizeYear(CalendarDate date) {
352         Date ldate = (Date) date;
353         // Set the supposed-to-be-correct Gregorian year first
354         // e.g., Showa 90 becomes 2015 (1926 + 90 - 1).
355         Era era = ldate.getEra();
356         if (era == null || !validateEra(era)) {
357             ldate.setNormalizedYear(ldate.getYear());
358         } else {
359             ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
360         }
361     }
362 
363     /**
364      * Returns whether the specified Gregorian year is a leap year.
365      * @see #isLeapYear(Era, int)
366      */
isLeapYear(int gregorianYear)367     public boolean isLeapYear(int gregorianYear) {
368         return CalendarUtils.isGregorianLeapYear(gregorianYear);
369     }
370 
isLeapYear(Era era, int year)371     public boolean isLeapYear(Era era, int year) {
372         if (era == null) {
373             return isLeapYear(year);
374         }
375         int gyear = era.getSinceDate().getYear() + year - 1;
376         return isLeapYear(gyear);
377     }
378 
getCalendarDateFromFixedDate(CalendarDate date, long fixedDate)379     public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
380         Date ldate = (Date) date;
381         super.getCalendarDateFromFixedDate(ldate, fixedDate);
382         adjustYear(ldate, (fixedDate - EPOCH_OFFSET) * DAY_IN_MILLIS, 0);
383     }
384 }
385