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 47 protected Date() { 48 super(); 49 } 50 51 protected Date(TimeZone zone) { 52 super(zone); 53 } 54 55 private int gregorianYear = FIELD_UNDEFINED; 56 57 @Override 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 67 public Date addYear(int localYear) { 68 super.addYear(localYear); 69 gregorianYear += localYear; 70 return this; 71 } 72 73 @Override 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 83 public int getNormalizedYear() { 84 return gregorianYear; 85 } 86 87 @Override 88 public void setNormalizedYear(int normalizedYear) { 89 this.gregorianYear = normalizedYear; 90 } 91 92 void setLocalEra(Era era) { 93 super.setEra(era); 94 } 95 96 void setLocalYear(int year) { 97 super.setYear(year); 98 } 99 100 @Override 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; 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 Era[] eraArray = new Era[eras.size()]; 170 eras.toArray(eraArray); 171 172 return new LocalGregorianCalendar(name, eraArray); 173 } 174 175 private LocalGregorianCalendar(String name, Era[] eras) { 176 this.name = name; 177 this.eras = eras; 178 setEras(eras); 179 } 180 181 @Override 182 public String getName() { 183 return name; 184 } 185 186 @Override 187 public Date getCalendarDate() { 188 return getCalendarDate(System.currentTimeMillis(), newCalendarDate()); 189 } 190 191 @Override 192 public Date getCalendarDate(long millis) { 193 return getCalendarDate(millis, newCalendarDate()); 194 } 195 196 @Override 197 public Date getCalendarDate(long millis, TimeZone zone) { 198 return getCalendarDate(millis, newCalendarDate(zone)); 199 } 200 201 @Override 202 public Date getCalendarDate(long millis, CalendarDate date) { 203 Date ldate = (Date) super.getCalendarDate(millis, date); 204 return adjustYear(ldate, millis, ldate.getZoneOffset()); 205 } 206 207 private Date adjustYear(Date ldate, long millis, int zoneOffset) { 208 int i; 209 for (i = eras.length - 1; i >= 0; --i) { 210 Era era = eras[i]; 211 long since = era.getSince(null); 212 if (era.isLocalTime()) { 213 since -= zoneOffset; 214 } 215 if (millis >= since) { 216 ldate.setLocalEra(era); 217 int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1; 218 ldate.setLocalYear(y); 219 break; 220 } 221 } 222 if (i < 0) { 223 ldate.setLocalEra(null); 224 ldate.setLocalYear(ldate.getNormalizedYear()); 225 } 226 ldate.setNormalized(true); 227 return ldate; 228 } 229 230 @Override 231 public Date newCalendarDate() { 232 return new Date(); 233 } 234 235 @Override 236 public Date newCalendarDate(TimeZone zone) { 237 return new Date(zone); 238 } 239 240 @Override 241 public boolean validate(CalendarDate date) { 242 Date ldate = (Date) date; 243 Era era = ldate.getEra(); 244 if (era != null) { 245 if (!validateEra(era)) { 246 return false; 247 } 248 ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1); 249 Date tmp = newCalendarDate(date.getZone()); 250 tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth()); 251 normalize(tmp); 252 if (tmp.getEra() != era) { 253 return false; 254 } 255 } else { 256 if (date.getYear() >= eras[0].getSinceDate().getYear()) { 257 return false; 258 } 259 ldate.setNormalizedYear(ldate.getYear()); 260 } 261 return super.validate(ldate); 262 } 263 264 private boolean validateEra(Era era) { 265 // Validate the era 266 for (int i = 0; i < eras.length; i++) { 267 if (era == eras[i]) { 268 return true; 269 } 270 } 271 return false; 272 } 273 274 @Override 275 public boolean normalize(CalendarDate date) { 276 if (date.isNormalized()) { 277 return true; 278 } 279 280 normalizeYear(date); 281 Date ldate = (Date) date; 282 283 // Normalize it as a Gregorian date and get its millisecond value 284 super.normalize(ldate); 285 286 boolean hasMillis = false; 287 long millis = 0; 288 int year = ldate.getNormalizedYear(); 289 int i; 290 Era era = null; 291 for (i = eras.length - 1; i >= 0; --i) { 292 era = eras[i]; 293 if (era.isLocalTime()) { 294 CalendarDate sinceDate = era.getSinceDate(); 295 int sinceYear = sinceDate.getYear(); 296 if (year > sinceYear) { 297 break; 298 } 299 if (year == sinceYear) { 300 int month = ldate.getMonth(); 301 int sinceMonth = sinceDate.getMonth(); 302 if (month > sinceMonth) { 303 break; 304 } 305 if (month == sinceMonth) { 306 int day = ldate.getDayOfMonth(); 307 int sinceDay = sinceDate.getDayOfMonth(); 308 if (day > sinceDay) { 309 break; 310 } 311 if (day == sinceDay) { 312 long timeOfDay = ldate.getTimeOfDay(); 313 long sinceTimeOfDay = sinceDate.getTimeOfDay(); 314 if (timeOfDay >= sinceTimeOfDay) { 315 break; 316 } 317 --i; 318 break; 319 } 320 } 321 } 322 } else { 323 if (!hasMillis) { 324 millis = super.getTime(date); 325 hasMillis = true; 326 } 327 328 long since = era.getSince(date.getZone()); 329 if (millis >= since) { 330 break; 331 } 332 } 333 } 334 if (i >= 0) { 335 ldate.setLocalEra(era); 336 int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1; 337 ldate.setLocalYear(y); 338 } else { 339 // Set Gregorian year with no era 340 ldate.setEra(null); 341 ldate.setLocalYear(year); 342 ldate.setNormalizedYear(year); 343 } 344 ldate.setNormalized(true); 345 return true; 346 } 347 348 @Override 349 void normalizeMonth(CalendarDate date) { 350 normalizeYear(date); 351 super.normalizeMonth(date); 352 } 353 354 void normalizeYear(CalendarDate date) { 355 Date ldate = (Date) date; 356 // Set the supposed-to-be-correct Gregorian year first 357 // e.g., Showa 90 becomes 2015 (1926 + 90 - 1). 358 Era era = ldate.getEra(); 359 if (era == null || !validateEra(era)) { 360 ldate.setNormalizedYear(ldate.getYear()); 361 } else { 362 ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1); 363 } 364 } 365 366 /** 367 * Returns whether the specified Gregorian year is a leap year. 368 * @see #isLeapYear(Era, int) 369 */ 370 @Override 371 public boolean isLeapYear(int gregorianYear) { 372 return CalendarUtils.isGregorianLeapYear(gregorianYear); 373 } 374 375 public boolean isLeapYear(Era era, int year) { 376 if (era == null) { 377 return isLeapYear(year); 378 } 379 int gyear = era.getSinceDate().getYear() + year - 1; 380 return isLeapYear(gyear); 381 } 382 383 @Override 384 public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) { 385 Date ldate = (Date) date; 386 super.getCalendarDateFromFixedDate(ldate, fixedDate); 387 adjustYear(ldate, (fixedDate - EPOCH_OFFSET) * DAY_IN_MILLIS, 0); 388 } 389 }