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