package sun.util.calendar;
import java.security.AccessController;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import sun.security.action.GetPropertyAction;
public class LocalGregorianCalendar extends BaseCalendar {
private static final Era[] JAPANESE_ERAS = {
new Era("Meiji", "M", -3218832000000L, true),
new Era("Taisho", "T", -1812153600000L, true),
new Era("Showa", "S", -1357603200000L, true),
new Era("Heisei", "H", 600220800000L, true),
new Era("Reiwa", "R", 1556668800000L, true),
};
private static boolean isValidEra(Era newEra, Era[] eras) {
Era last = eras[eras.length - 1];
if (last.getSince(null) >= newEra.getSince(null)) {
return false;
}
String newName = newEra.getName();
for (Era era : eras) {
if (era.getName().equals(newName)) {
return false;
}
}
return true;
}
private String name;
private Era[] eras;
public static class Date extends BaseCalendar.Date {
protected Date() {
super();
}
protected Date(TimeZone zone) {
super(zone);
}
private int gregorianYear = FIELD_UNDEFINED;
@Override
public Date setEra(Era era) {
if (getEra() != era) {
super.setEra(era);
gregorianYear = FIELD_UNDEFINED;
}
return this;
}
@Override
public Date addYear(int localYear) {
super.addYear(localYear);
gregorianYear += localYear;
return this;
}
@Override
public Date setYear(int localYear) {
if (getYear() != localYear) {
super.setYear(localYear);
gregorianYear = FIELD_UNDEFINED;
}
return this;
}
@Override
public int getNormalizedYear() {
return gregorianYear;
}
@Override
public void setNormalizedYear(int normalizedYear) {
this.gregorianYear = normalizedYear;
}
void setLocalEra(Era era) {
super.setEra(era);
}
void setLocalYear(int year) {
super.setYear(year);
}
@Override
public String toString() {
String time = super.toString();
time = time.substring(time.indexOf('T'));
StringBuffer sb = new StringBuffer();
Era era = getEra();
if (era != null) {
String abbr = era.getAbbreviation();
if (abbr != null) {
sb.append(abbr);
}
}
sb.append(getYear()).append('.');
CalendarUtils.sprintf0d(sb, getMonth(), 2).append('.');
CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);
sb.append(time);
return sb.toString();
}
}
static LocalGregorianCalendar getLocalGregorianCalendar(String name) {
if (!"japanese".equals(name)) {
return null;
}
String prop = GetPropertyAction
.privilegedGetProperty("jdk.calendar.japanese.supplemental.era");
if (prop != null) {
Era era = parseEraEntry(prop);
if (era != null) {
if (isValidEra(era, JAPANESE_ERAS)) {
int length = JAPANESE_ERAS.length;
Era[] eras = new Era[length + 1];
System.arraycopy(JAPANESE_ERAS, 0, eras, 0, length);
eras[length] = era;
return new LocalGregorianCalendar(name, eras);
}
}
}
return new LocalGregorianCalendar(name, JAPANESE_ERAS);
}
private static Era parseEraEntry(String entry) {
String[] keyValuePairs = entry.split(",");
String eraName = null;
boolean localTime = true;
long since = 0;
String abbr = null;
for (String item : keyValuePairs) {
String[] keyvalue = item.split("=");
if (keyvalue.length != 2) {
return null;
}
String key = keyvalue[0].trim();
String value = convertUnicodeEscape(keyvalue[1].trim());
switch (key) {
case "name":
eraName = value;
break;
case "since":
if (value.endsWith("u")) {
localTime = false;
value = value.substring(0, value.length() - 1);
}
try {
since = Long.parseLong(value);
} catch (NumberFormatException e) {
return null;
}
break;
case "abbr":
abbr = value;
break;
default:
return null;
}
}
if (eraName == null || eraName.isEmpty()
|| abbr == null || abbr.isEmpty()) {
return null;
}
return new Era(eraName, abbr, since, localTime);
}
private static String convertUnicodeEscape(String src) {
Matcher m = Pattern.compile("\\\\u([0-9a-fA-F]{4})").matcher(src);
StringBuilder sb = new StringBuilder();
while (m.find()) {
m.appendReplacement(sb,
Character.toString((char)Integer.parseUnsignedInt(m.group(1), 16)));
}
m.appendTail(sb);
return sb.toString();
}
private LocalGregorianCalendar(String name, Era[] eras) {
this.name = name;
this.eras = eras;
setEras(eras);
}
@Override
public String getName() {
return name;
}
@Override
public Date getCalendarDate() {
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
}
@Override
public Date getCalendarDate(long millis) {
return getCalendarDate(millis, newCalendarDate());
}
@Override
public Date getCalendarDate(long millis, TimeZone zone) {
return getCalendarDate(millis, newCalendarDate(zone));
}
@Override
public Date getCalendarDate(long millis, CalendarDate date) {
Date ldate = (Date) super.getCalendarDate(millis, date);
return adjustYear(ldate, millis, ldate.getZoneOffset());
}
private Date adjustYear(Date ldate, long millis, int zoneOffset) {
int i;
for (i = eras.length - 1; i >= 0; --i) {
Era era = eras[i];
long since = era.getSince(null);
if (era.isLocalTime()) {
since -= zoneOffset;
}
if (millis >= since) {
ldate.setLocalEra(era);
int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
ldate.setLocalYear(y);
break;
}
}
if (i < 0) {
ldate.setLocalEra(null);
ldate.setLocalYear(ldate.getNormalizedYear());
}
ldate.setNormalized(true);
return ldate;
}
@Override
public Date newCalendarDate() {
return new Date();
}
@Override
public Date newCalendarDate(TimeZone zone) {
return new Date(zone);
}
@Override
public boolean validate(CalendarDate date) {
Date ldate = (Date) date;
Era era = ldate.getEra();
if (era != null) {
if (!validateEra(era)) {
return false;
}
ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
Date tmp = newCalendarDate(date.getZone());
tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth());
normalize(tmp);
if (tmp.getEra() != era) {
return false;
}
} else {
if (date.getYear() >= eras[0].getSinceDate().getYear()) {
return false;
}
ldate.setNormalizedYear(ldate.getYear());
}
return super.validate(ldate);
}
private boolean validateEra(Era era) {
for (Era era1 : eras) {
if (era == era1) {
return true;
}
}
return false;
}
@Override
public boolean normalize(CalendarDate date) {
if (date.isNormalized()) {
return true;
}
normalizeYear(date);
Date ldate = (Date) date;
super.normalize(ldate);
boolean hasMillis = false;
long millis = 0;
int year = ldate.getNormalizedYear();
int i;
Era era = null;
for (i = eras.length - 1; i >= 0; --i) {
era = eras[i];
if (era.isLocalTime()) {
CalendarDate sinceDate = era.getSinceDate();
int sinceYear = sinceDate.getYear();
if (year > sinceYear) {
break;
}
if (year == sinceYear) {
int month = ldate.getMonth();
int sinceMonth = sinceDate.getMonth();
if (month > sinceMonth) {
break;
}
if (month == sinceMonth) {
int day = ldate.getDayOfMonth();
int sinceDay = sinceDate.getDayOfMonth();
if (day > sinceDay) {
break;
}
if (day == sinceDay) {
long timeOfDay = ldate.getTimeOfDay();
long sinceTimeOfDay = sinceDate.getTimeOfDay();
if (timeOfDay >= sinceTimeOfDay) {
break;
}
--i;
break;
}
}
}
} else {
if (!hasMillis) {
millis = super.getTime(date);
hasMillis = true;
}
long since = era.getSince(date.getZone());
if (millis >= since) {
break;
}
}
}
if (i >= 0) {
ldate.setLocalEra(era);
@SuppressWarnings("null")
int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
ldate.setLocalYear(y);
} else {
ldate.setEra(null);
ldate.setLocalYear(year);
ldate.setNormalizedYear(year);
}
ldate.setNormalized(true);
return true;
}
@Override
void normalizeMonth(CalendarDate date) {
normalizeYear(date);
super.normalizeMonth(date);
}
void normalizeYear(CalendarDate date) {
Date ldate = (Date) date;
Era era = ldate.getEra();
if (era == null || !validateEra(era)) {
ldate.setNormalizedYear(ldate.getYear());
} else {
ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
}
}
@Override
public boolean isLeapYear(int gregorianYear) {
return CalendarUtils.isGregorianLeapYear(gregorianYear);
}
public boolean isLeapYear(Era era, int year) {
if (era == null) {
return isLeapYear(year);
}
int gyear = era.getSinceDate().getYear() + year - 1;
return isLeapYear(gyear);
}
@Override
public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
Date ldate = (Date) date;
super.getCalendarDateFromFixedDate(ldate, fixedDate);
adjustYear(ldate, (fixedDate - EPOCH_OFFSET) * DAY_IN_MILLIS, 0);
}
}