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