Path: blob/master/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java
41159 views
/*1* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.util.calendar;2627import java.security.AccessController;28import java.util.TimeZone;29import java.util.regex.Matcher;30import java.util.regex.Pattern;31import sun.security.action.GetPropertyAction;3233/**34*35* @author Masayoshi Okutsu36* @since 1.637*/3839public class LocalGregorianCalendar extends BaseCalendar {40private static final Era[] JAPANESE_ERAS = {41new Era("Meiji", "M", -3218832000000L, true),42new Era("Taisho", "T", -1812153600000L, true),43new Era("Showa", "S", -1357603200000L, true),44new Era("Heisei", "H", 600220800000L, true),45new Era("Reiwa", "R", 1556668800000L, true),46};4748private static boolean isValidEra(Era newEra, Era[] eras) {49Era last = eras[eras.length - 1];50if (last.getSince(null) >= newEra.getSince(null)) {51return false;52}53// The new era name should be unique. Its abbr may not.54String newName = newEra.getName();55for (Era era : eras) {56if (era.getName().equals(newName)) {57return false;58}59}60return true;61}6263private String name;64private Era[] eras;6566public static class Date extends BaseCalendar.Date {6768protected Date() {69super();70}7172protected Date(TimeZone zone) {73super(zone);74}7576private int gregorianYear = FIELD_UNDEFINED;7778@Override79public Date setEra(Era era) {80if (getEra() != era) {81super.setEra(era);82gregorianYear = FIELD_UNDEFINED;83}84return this;85}8687@Override88public Date addYear(int localYear) {89super.addYear(localYear);90gregorianYear += localYear;91return this;92}9394@Override95public Date setYear(int localYear) {96if (getYear() != localYear) {97super.setYear(localYear);98gregorianYear = FIELD_UNDEFINED;99}100return this;101}102103@Override104public int getNormalizedYear() {105return gregorianYear;106}107108@Override109public void setNormalizedYear(int normalizedYear) {110this.gregorianYear = normalizedYear;111}112113void setLocalEra(Era era) {114super.setEra(era);115}116117void setLocalYear(int year) {118super.setYear(year);119}120121@Override122public String toString() {123String time = super.toString();124time = time.substring(time.indexOf('T'));125StringBuffer sb = new StringBuffer();126Era era = getEra();127if (era != null) {128String abbr = era.getAbbreviation();129if (abbr != null) {130sb.append(abbr);131}132}133sb.append(getYear()).append('.');134CalendarUtils.sprintf0d(sb, getMonth(), 2).append('.');135CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);136sb.append(time);137return sb.toString();138}139}140141static LocalGregorianCalendar getLocalGregorianCalendar(String name) {142// Only the Japanese calendar is supported.143if (!"japanese".equals(name)) {144return null;145}146147// Append an era to the predefined eras if it's given by the property.148String prop = GetPropertyAction149.privilegedGetProperty("jdk.calendar.japanese.supplemental.era");150if (prop != null) {151Era era = parseEraEntry(prop);152if (era != null) {153if (isValidEra(era, JAPANESE_ERAS)) {154int length = JAPANESE_ERAS.length;155Era[] eras = new Era[length + 1];156System.arraycopy(JAPANESE_ERAS, 0, eras, 0, length);157eras[length] = era;158return new LocalGregorianCalendar(name, eras);159}160}161}162return new LocalGregorianCalendar(name, JAPANESE_ERAS);163}164165private static Era parseEraEntry(String entry) {166String[] keyValuePairs = entry.split(",");167String eraName = null;168boolean localTime = true;169long since = 0;170String abbr = null;171172for (String item : keyValuePairs) {173String[] keyvalue = item.split("=");174if (keyvalue.length != 2) {175return null;176}177String key = keyvalue[0].trim();178String value = convertUnicodeEscape(keyvalue[1].trim());179switch (key) {180case "name":181eraName = value;182break;183case "since":184if (value.endsWith("u")) {185localTime = false;186value = value.substring(0, value.length() - 1);187}188try {189since = Long.parseLong(value);190} catch (NumberFormatException e) {191return null;192}193break;194case "abbr":195abbr = value;196break;197default:198return null;199}200}201if (eraName == null || eraName.isEmpty()202|| abbr == null || abbr.isEmpty()) {203return null;204}205return new Era(eraName, abbr, since, localTime);206}207208private static String convertUnicodeEscape(String src) {209Matcher m = Pattern.compile("\\\\u([0-9a-fA-F]{4})").matcher(src);210StringBuilder sb = new StringBuilder();211while (m.find()) {212m.appendReplacement(sb,213Character.toString((char)Integer.parseUnsignedInt(m.group(1), 16)));214}215m.appendTail(sb);216return sb.toString();217}218219private LocalGregorianCalendar(String name, Era[] eras) {220this.name = name;221this.eras = eras;222setEras(eras);223}224225@Override226public String getName() {227return name;228}229230@Override231public Date getCalendarDate() {232return getCalendarDate(System.currentTimeMillis(), newCalendarDate());233}234235@Override236public Date getCalendarDate(long millis) {237return getCalendarDate(millis, newCalendarDate());238}239240@Override241public Date getCalendarDate(long millis, TimeZone zone) {242return getCalendarDate(millis, newCalendarDate(zone));243}244245@Override246public Date getCalendarDate(long millis, CalendarDate date) {247Date ldate = (Date) super.getCalendarDate(millis, date);248return adjustYear(ldate, millis, ldate.getZoneOffset());249}250251private Date adjustYear(Date ldate, long millis, int zoneOffset) {252int i;253for (i = eras.length - 1; i >= 0; --i) {254Era era = eras[i];255long since = era.getSince(null);256if (era.isLocalTime()) {257since -= zoneOffset;258}259if (millis >= since) {260ldate.setLocalEra(era);261int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;262ldate.setLocalYear(y);263break;264}265}266if (i < 0) {267ldate.setLocalEra(null);268ldate.setLocalYear(ldate.getNormalizedYear());269}270ldate.setNormalized(true);271return ldate;272}273274@Override275public Date newCalendarDate() {276return new Date();277}278279@Override280public Date newCalendarDate(TimeZone zone) {281return new Date(zone);282}283284@Override285public boolean validate(CalendarDate date) {286Date ldate = (Date) date;287Era era = ldate.getEra();288if (era != null) {289if (!validateEra(era)) {290return false;291}292ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);293Date tmp = newCalendarDate(date.getZone());294tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth());295normalize(tmp);296if (tmp.getEra() != era) {297return false;298}299} else {300if (date.getYear() >= eras[0].getSinceDate().getYear()) {301return false;302}303ldate.setNormalizedYear(ldate.getYear());304}305return super.validate(ldate);306}307308private boolean validateEra(Era era) {309for (Era era1 : eras) {310if (era == era1) {311return true;312}313}314return false;315}316317@Override318public boolean normalize(CalendarDate date) {319if (date.isNormalized()) {320return true;321}322323normalizeYear(date);324Date ldate = (Date) date;325326// Normalize it as a Gregorian date and get its millisecond value327super.normalize(ldate);328329boolean hasMillis = false;330long millis = 0;331int year = ldate.getNormalizedYear();332int i;333Era era = null;334for (i = eras.length - 1; i >= 0; --i) {335era = eras[i];336if (era.isLocalTime()) {337CalendarDate sinceDate = era.getSinceDate();338int sinceYear = sinceDate.getYear();339if (year > sinceYear) {340break;341}342if (year == sinceYear) {343int month = ldate.getMonth();344int sinceMonth = sinceDate.getMonth();345if (month > sinceMonth) {346break;347}348if (month == sinceMonth) {349int day = ldate.getDayOfMonth();350int sinceDay = sinceDate.getDayOfMonth();351if (day > sinceDay) {352break;353}354if (day == sinceDay) {355long timeOfDay = ldate.getTimeOfDay();356long sinceTimeOfDay = sinceDate.getTimeOfDay();357if (timeOfDay >= sinceTimeOfDay) {358break;359}360--i;361break;362}363}364}365} else {366if (!hasMillis) {367millis = super.getTime(date);368hasMillis = true;369}370371long since = era.getSince(date.getZone());372if (millis >= since) {373break;374}375}376}377if (i >= 0) {378ldate.setLocalEra(era);379@SuppressWarnings("null")380int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;381ldate.setLocalYear(y);382} else {383// Set Gregorian year with no era384ldate.setEra(null);385ldate.setLocalYear(year);386ldate.setNormalizedYear(year);387}388ldate.setNormalized(true);389return true;390}391392@Override393void normalizeMonth(CalendarDate date) {394normalizeYear(date);395super.normalizeMonth(date);396}397398void normalizeYear(CalendarDate date) {399Date ldate = (Date) date;400// Set the supposed-to-be-correct Gregorian year first401// e.g., Showa 90 becomes 2015 (1926 + 90 - 1).402Era era = ldate.getEra();403if (era == null || !validateEra(era)) {404ldate.setNormalizedYear(ldate.getYear());405} else {406ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);407}408}409410/**411* Returns whether the specified Gregorian year is a leap year.412* @see #isLeapYear(Era, int)413*/414@Override415public boolean isLeapYear(int gregorianYear) {416return CalendarUtils.isGregorianLeapYear(gregorianYear);417}418419public boolean isLeapYear(Era era, int year) {420if (era == null) {421return isLeapYear(year);422}423int gyear = era.getSinceDate().getYear() + year - 1;424return isLeapYear(gyear);425}426427@Override428public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {429Date ldate = (Date) date;430super.getCalendarDateFromFixedDate(ldate, fixedDate);431adjustYear(ldate, (fixedDate - EPOCH_OFFSET) * DAY_IN_MILLIS, 0);432}433}434435436