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