1 /*
2  * Copyright (c) 2000, 2019, 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;
27 
28 import java.io.IOException;
29 import java.io.ObjectInputStream;
30 import java.util.GregorianCalendar;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.TimeZone;
34 import sun.util.locale.provider.CalendarDataUtility;
35 
36 public class BuddhistCalendar extends GregorianCalendar {
37 
38 //////////////////
39 // Class Variables
40 //////////////////
41 
42     @java.io.Serial
43     private static final long serialVersionUID = -8527488697350388578L;
44 
45     private static final int BUDDHIST_YEAR_OFFSET = 543;
46 
47 ///////////////
48 // Constructors
49 ///////////////
50 
51     /**
52      * Constructs a default BuddhistCalendar using the current time
53      * in the default time zone with the default locale.
54      */
BuddhistCalendar()55     public BuddhistCalendar() {
56         super();
57     }
58 
59     /**
60      * Constructs a BuddhistCalendar based on the current time
61      * in the given time zone with the default locale.
62      * @param zone the given time zone.
63      */
BuddhistCalendar(TimeZone zone)64     public BuddhistCalendar(TimeZone zone) {
65         super(zone);
66     }
67 
68     /**
69      * Constructs a BuddhistCalendar based on the current time
70      * in the default time zone with the given locale.
71      * @param aLocale the given locale.
72      */
BuddhistCalendar(Locale aLocale)73     public BuddhistCalendar(Locale aLocale) {
74         super(aLocale);
75     }
76 
77     /**
78      * Constructs a BuddhistCalendar based on the current time
79      * in the given time zone with the given locale.
80      * @param zone the given time zone.
81      * @param aLocale the given locale.
82      */
BuddhistCalendar(TimeZone zone, Locale aLocale)83     public BuddhistCalendar(TimeZone zone, Locale aLocale) {
84         super(zone, aLocale);
85     }
86 
87 /////////////////
88 // Public methods
89 /////////////////
90 
91     /**
92      * Returns {@code "buddhist"} as the calendar type of this Calendar.
93      */
94     @Override
getCalendarType()95     public String getCalendarType() {
96         return "buddhist";
97     }
98 
99     /**
100      * Compares this BuddhistCalendar to an object reference.
101      * @param obj the object reference with which to compare
102      * @return true if this object is equal to <code>obj</code>; false otherwise
103      */
104     @Override
equals(Object obj)105     public boolean equals(Object obj) {
106         return obj instanceof BuddhistCalendar
107             && super.equals(obj);
108     }
109 
110     /**
111      * Override hashCode.
112      * Generates the hash code for the BuddhistCalendar object
113      */
114     @Override
hashCode()115     public int hashCode() {
116         return super.hashCode() ^ BUDDHIST_YEAR_OFFSET;
117     }
118 
119     /**
120      * Gets the value for a given time field.
121      * @param field the given time field.
122      * @return the value for the given time field.
123      */
124     @Override
get(int field)125     public int get(int field)
126     {
127         if (field == YEAR) {
128             return super.get(field) + yearOffset;
129         }
130         return super.get(field);
131     }
132 
133     /**
134      * Sets the time field with the given value.
135      * @param field the given time field.
136      * @param value the value to be set for the given time field.
137      */
138     @Override
set(int field, int value)139     public void set(int field, int value)
140     {
141         if (field == YEAR) {
142             super.set(field, value - yearOffset);
143         } else {
144             super.set(field, value);
145         }
146     }
147 
148     /**
149      * Adds the specified (signed) amount of time to the given time field.
150      * @param field the time field.
151      * @param amount the amount of date or time to be added to the field.
152      */
153     @Override
add(int field, int amount)154     public void add(int field, int amount)
155     {
156         int savedYearOffset = yearOffset;
157         // To let the superclass calculate date-time values correctly,
158         // temporarily make this GregorianCalendar.
159         yearOffset = 0;
160         try {
161             super.add(field, amount);
162         } finally {
163             yearOffset = savedYearOffset;
164         }
165     }
166 
167     /**
168      * Add to field a signed amount without changing larger fields.
169      * A negative roll amount means to subtract from field without changing
170      * larger fields.
171      * @param field the time field.
172      * @param amount the signed amount to add to <code>field</code>.
173      */
174     @Override
roll(int field, int amount)175     public void roll(int field, int amount)
176     {
177         int savedYearOffset = yearOffset;
178         // To let the superclass calculate date-time values correctly,
179         // temporarily make this GregorianCalendar.
180         yearOffset = 0;
181         try {
182             super.roll(field, amount);
183         } finally {
184             yearOffset = savedYearOffset;
185         }
186     }
187 
188     @Override
getDisplayName(int field, int style, Locale locale)189     public String getDisplayName(int field, int style, Locale locale) {
190         if (field != ERA) {
191             return super.getDisplayName(field, style, locale);
192         }
193 
194         return CalendarDataUtility.retrieveFieldValueName("buddhist", field, get(field), style, locale);
195     }
196 
197     @Override
getDisplayNames(int field, int style, Locale locale)198     public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
199         if (field != ERA) {
200             return super.getDisplayNames(field, style, locale);
201         }
202         return CalendarDataUtility.retrieveFieldValueNames("buddhist", field, style, locale);
203     }
204 
205     /**
206      * Returns the maximum value that this field could have, given the
207      * current date.  For example, with the date "Feb 3, 2540" and the
208      * <code>DAY_OF_MONTH</code> field, the actual maximum is 28; for
209      * "Feb 3, 2539" it is 29.
210      *
211      * @param field the field to determine the maximum of
212      * @return the maximum of the given field for the current date of this Calendar
213      */
214     @Override
getActualMaximum(int field)215     public int getActualMaximum(int field) {
216         int savedYearOffset = yearOffset;
217         // To let the superclass calculate date-time values correctly,
218         // temporarily make this GregorianCalendar.
219         yearOffset = 0;
220         try {
221             return super.getActualMaximum(field);
222         } finally {
223             yearOffset = savedYearOffset;
224         }
225     }
226 
227     @Override
228     @SuppressWarnings("empty-statement")
toString()229     public String toString() {
230         // The super class produces a String with the Gregorian year
231         // value (or '?')
232         String s = super.toString();
233         // If the YEAR field is UNSET, then return the Gregorian string.
234         if (!isSet(YEAR)) {
235             return s;
236         }
237 
238         final String yearField = "YEAR=";
239         int p = s.indexOf(yearField);
240         // If the string doesn't include the year value for some
241         // reason, then return the Gregorian string.
242         if (p == -1) {
243             return s;
244         }
245         p += yearField.length();
246         StringBuilder sb = new StringBuilder(s.length() + 10);
247         sb.append(s, 0, p);
248         // Skip the year number
249         while (Character.isDigit(s.charAt(p++)))
250             ;
251         int year = internalGet(YEAR) + BUDDHIST_YEAR_OFFSET;
252         sb.append(year).append(s, p - 1, s.length());
253         return sb.toString();
254     }
255 
256     private transient int yearOffset = BUDDHIST_YEAR_OFFSET;
257 
258     @java.io.Serial
readObject(ObjectInputStream stream)259     private void readObject(ObjectInputStream stream)
260         throws IOException, ClassNotFoundException {
261         stream.defaultReadObject();
262         yearOffset = BUDDHIST_YEAR_OFFSET;
263     }
264 }
265