mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
Adds incomplete Calendar implementation
This commit is contained in:
parent
fdf216a400
commit
9df49fad0a
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.classlib.impl.unicode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
public class CLDRHelper {
|
||||||
|
public static String getCode(String language, String country) {
|
||||||
|
return !country.isEmpty() ? language + "-" + country : language;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.teavm.codegen.SourceWriter;
|
||||||
|
import org.teavm.javascript.ni.Generator;
|
||||||
|
import org.teavm.javascript.ni.GeneratorContext;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class CalendarNativeGenerator implements Generator {
|
||||||
|
@Override
|
||||||
|
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,9 @@ package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.teavm.codegen.SourceWriter;
|
import org.teavm.codegen.SourceWriter;
|
||||||
|
import org.teavm.dependency.DependencyChecker;
|
||||||
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.javascript.ni.Generator;
|
import org.teavm.javascript.ni.Generator;
|
||||||
import org.teavm.javascript.ni.GeneratorContext;
|
import org.teavm.javascript.ni.GeneratorContext;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -25,7 +28,7 @@ import org.teavm.model.MethodReference;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class DateNativeGenerator implements Generator {
|
public class DateNativeGenerator implements Generator, DependencyPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||||
switch (methodRef.getName()) {
|
switch (methodRef.getName()) {
|
||||||
|
@ -55,6 +58,24 @@ public class DateNativeGenerator implements Generator {
|
||||||
case "setSeconds":
|
case "setSeconds":
|
||||||
generateSetMethod(context, writer, methodRef.getName());
|
generateSetMethod(context, writer, methodRef.getName());
|
||||||
break;
|
break;
|
||||||
|
case "toString":
|
||||||
|
case "toGMTString":
|
||||||
|
generateToString(context, writer, methodRef.getName());
|
||||||
|
break;
|
||||||
|
case "toLocaleFormat":
|
||||||
|
generateToLocaleFormat(context, writer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||||
|
switch (method.getMethod().getName()) {
|
||||||
|
case "toString":
|
||||||
|
case "toLocaleFormat":
|
||||||
|
case "toGMTString":
|
||||||
|
method.getResult().propagate("java.lang.String");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,4 +111,15 @@ public class DateNativeGenerator implements Generator {
|
||||||
writer.append("return date.").append(methodName).append("(").append(context.getParameterName(2)).append(");")
|
writer.append("return date.").append(methodName).append("(").append(context.getParameterName(2)).append(");")
|
||||||
.softNewLine();
|
.softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateToString(GeneratorContext context, SourceWriter writer, String method) throws IOException {
|
||||||
|
writer.append("return $rt_str(new Date(").append(context.getParameterName(1)).append(").").append(method)
|
||||||
|
.append("());").softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateToLocaleFormat(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||||
|
writer.append("return $rt_str(new Date(").append(context.getParameterName(1))
|
||||||
|
.append(").toLocaleFormat($rt_ustr(").append(context.getParameterName(2)).append(")));")
|
||||||
|
.softNewLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@ import org.teavm.javascript.Renderer;
|
||||||
import org.teavm.javascript.ni.Generator;
|
import org.teavm.javascript.ni.Generator;
|
||||||
import org.teavm.javascript.ni.GeneratorContext;
|
import org.teavm.javascript.ni.GeneratorContext;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import com.google.gson.*;
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -36,6 +38,8 @@ public class LocaleSettingsNativeGenerator implements Generator {
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
private Properties properties;
|
private Properties properties;
|
||||||
private Map<String, LocaleInfo> knownLocales = new LinkedHashMap<>();
|
private Map<String, LocaleInfo> knownLocales = new LinkedHashMap<>();
|
||||||
|
private Map<String, Integer> minDaysMap = new LinkedHashMap<>();
|
||||||
|
private Map<String, Integer> firstDayMap = new LinkedHashMap<>();
|
||||||
private Set<String> availableLocales = new LinkedHashSet<>();
|
private Set<String> availableLocales = new LinkedHashSet<>();
|
||||||
private Set<String> availableLanguages = new LinkedHashSet<>();
|
private Set<String> availableLanguages = new LinkedHashSet<>();
|
||||||
private Set<String> availableCountries = new LinkedHashSet<>();
|
private Set<String> availableCountries = new LinkedHashSet<>();
|
||||||
|
@ -83,6 +87,10 @@ public class LocaleSettingsNativeGenerator implements Generator {
|
||||||
if (!entry.getName().endsWith(".json")) {
|
if (!entry.getName().endsWith(".json")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (entry.getName().equals("supplemental/weekData.json")) {
|
||||||
|
readWeekData(input);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int objectIndex = entry.getName().lastIndexOf('/');
|
int objectIndex = entry.getName().lastIndexOf('/');
|
||||||
String objectName = entry.getName().substring(objectIndex + 1);
|
String objectName = entry.getName().substring(objectIndex + 1);
|
||||||
String localeName = entry.getName().substring(0, objectIndex);
|
String localeName = entry.getName().substring(0, objectIndex);
|
||||||
|
@ -125,16 +133,50 @@ public class LocaleSettingsNativeGenerator implements Generator {
|
||||||
|
|
||||||
private void readCountries(String localeCode, LocaleInfo locale, InputStream input) {
|
private void readCountries(String localeCode, LocaleInfo locale, InputStream input) {
|
||||||
JsonObject root = (JsonObject)new JsonParser().parse(new InputStreamReader(input));
|
JsonObject root = (JsonObject)new JsonParser().parse(new InputStreamReader(input));
|
||||||
JsonObject languagesJson = root.get("main").getAsJsonObject().get(localeCode).getAsJsonObject()
|
JsonObject countriesJson = root.get("main").getAsJsonObject().get(localeCode).getAsJsonObject()
|
||||||
.get("localeDisplayNames").getAsJsonObject().get("territories").getAsJsonObject();
|
.get("localeDisplayNames").getAsJsonObject().get("territories").getAsJsonObject();
|
||||||
for (Map.Entry<String, JsonElement> property : languagesJson.entrySet()) {
|
for (Map.Entry<String, JsonElement> property : countriesJson.entrySet()) {
|
||||||
String language = property.getKey();
|
String country = property.getKey();
|
||||||
if (availableCountries.contains(language)) {
|
if (availableCountries.contains(country)) {
|
||||||
locale.territories.put(language, property.getValue().getAsString());
|
locale.territories.put(country, property.getValue().getAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void readWeekData(InputStream input) {
|
||||||
|
JsonObject root = (JsonObject)new JsonParser().parse(new InputStreamReader(input));
|
||||||
|
JsonObject weekJson = root.get("supplemental").getAsJsonObject().get("weekData").getAsJsonObject();
|
||||||
|
JsonObject minDaysJson = weekJson.get("minDays").getAsJsonObject();
|
||||||
|
for (Map.Entry<String, JsonElement> property : minDaysJson.entrySet()) {
|
||||||
|
minDaysMap.put(property.getKey(), property.getValue().getAsInt());
|
||||||
|
}
|
||||||
|
JsonObject firstDayJson = weekJson.get("firstDay").getAsJsonObject();
|
||||||
|
for (Map.Entry<String, JsonElement> property : firstDayJson.entrySet()) {
|
||||||
|
firstDayMap.put(property.getKey(), getNumericDay(property.getValue().getAsString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNumericDay(String day) {
|
||||||
|
switch (day) {
|
||||||
|
case "sun":
|
||||||
|
return 1;
|
||||||
|
case "mon":
|
||||||
|
return 2;
|
||||||
|
case "tue":
|
||||||
|
return 3;
|
||||||
|
case "wed":
|
||||||
|
return 4;
|
||||||
|
case "thu":
|
||||||
|
return 5;
|
||||||
|
case "fri":
|
||||||
|
return 6;
|
||||||
|
case "sat":
|
||||||
|
return 7;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Can't recognize day name: " + day);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||||
init();
|
init();
|
||||||
|
@ -149,6 +191,9 @@ public class LocaleSettingsNativeGenerator implements Generator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateReadCLDR(SourceWriter writer) throws IOException {
|
private void generateReadCLDR(SourceWriter writer) throws IOException {
|
||||||
|
writer.append("if (").appendClass("java.util.Locale").append("$CLDR").append("{").indent().softNewLine();
|
||||||
|
writer.append("return;").softNewLine();
|
||||||
|
writer.outdent().append("}").softNewLine();
|
||||||
writer.appendClass("java.util.Locale").append(".$CLDR = {").indent().softNewLine();
|
writer.appendClass("java.util.Locale").append(".$CLDR = {").indent().softNewLine();
|
||||||
boolean firstLocale = true;
|
boolean firstLocale = true;
|
||||||
for (Map.Entry<String, LocaleInfo> entry : knownLocales.entrySet()) {
|
for (Map.Entry<String, LocaleInfo> entry : knownLocales.entrySet()) {
|
||||||
|
|
|
@ -0,0 +1,443 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
|
import org.teavm.classlib.impl.unicode.CLDRHelper;
|
||||||
|
import org.teavm.classlib.java.io.TSerializable;
|
||||||
|
import org.teavm.classlib.java.lang.TCloneable;
|
||||||
|
import org.teavm.classlib.java.lang.TComparable;
|
||||||
|
|
||||||
|
public abstract class TCalendar implements TSerializable, TCloneable, TComparable<TCalendar> {
|
||||||
|
protected boolean areFieldsSet;
|
||||||
|
|
||||||
|
protected int[] fields;
|
||||||
|
|
||||||
|
protected boolean[] isSet;
|
||||||
|
|
||||||
|
protected boolean isTimeSet;
|
||||||
|
|
||||||
|
protected long time;
|
||||||
|
|
||||||
|
transient int lastTimeFieldSet;
|
||||||
|
|
||||||
|
transient int lastDateFieldSet;
|
||||||
|
|
||||||
|
private boolean lenient;
|
||||||
|
|
||||||
|
private int firstDayOfWeek;
|
||||||
|
|
||||||
|
private int minimalDaysInFirstWeek;
|
||||||
|
|
||||||
|
public static final int JANUARY = 0;
|
||||||
|
|
||||||
|
public static final int FEBRUARY = 1;
|
||||||
|
|
||||||
|
public static final int MARCH = 2;
|
||||||
|
|
||||||
|
public static final int APRIL = 3;
|
||||||
|
|
||||||
|
public static final int MAY = 4;
|
||||||
|
|
||||||
|
public static final int JUNE = 5;
|
||||||
|
|
||||||
|
public static final int JULY = 6;
|
||||||
|
|
||||||
|
public static final int AUGUST = 7;
|
||||||
|
|
||||||
|
public static final int SEPTEMBER = 8;
|
||||||
|
|
||||||
|
public static final int OCTOBER = 9;
|
||||||
|
|
||||||
|
public static final int NOVEMBER = 10;
|
||||||
|
|
||||||
|
public static final int DECEMBER = 11;
|
||||||
|
|
||||||
|
public static final int UNDECIMBER = 12;
|
||||||
|
|
||||||
|
public static final int SUNDAY = 1;
|
||||||
|
|
||||||
|
public static final int MONDAY = 2;
|
||||||
|
|
||||||
|
public static final int TUESDAY = 3;
|
||||||
|
|
||||||
|
public static final int WEDNESDAY = 4;
|
||||||
|
|
||||||
|
public static final int THURSDAY = 5;
|
||||||
|
|
||||||
|
public static final int FRIDAY = 6;
|
||||||
|
|
||||||
|
public static final int SATURDAY = 7;
|
||||||
|
|
||||||
|
public static final int ERA = 0;
|
||||||
|
|
||||||
|
public static final int YEAR = 1;
|
||||||
|
|
||||||
|
public static final int MONTH = 2;
|
||||||
|
|
||||||
|
public static final int WEEK_OF_YEAR = 3;
|
||||||
|
|
||||||
|
public static final int WEEK_OF_MONTH = 4;
|
||||||
|
|
||||||
|
public static final int DATE = 5;
|
||||||
|
|
||||||
|
public static final int DAY_OF_MONTH = 5;
|
||||||
|
|
||||||
|
public static final int DAY_OF_YEAR = 6;
|
||||||
|
|
||||||
|
public static final int DAY_OF_WEEK = 7;
|
||||||
|
|
||||||
|
public static final int DAY_OF_WEEK_IN_MONTH = 8;
|
||||||
|
|
||||||
|
public static final int AM_PM = 9;
|
||||||
|
|
||||||
|
public static final int HOUR = 10;
|
||||||
|
|
||||||
|
public static final int HOUR_OF_DAY = 11;
|
||||||
|
|
||||||
|
public static final int MINUTE = 12;
|
||||||
|
|
||||||
|
public static final int SECOND = 13;
|
||||||
|
|
||||||
|
public static final int MILLISECOND = 14;
|
||||||
|
|
||||||
|
public static final int ZONE_OFFSET = 15;
|
||||||
|
|
||||||
|
public static final int DST_OFFSET = 16;
|
||||||
|
|
||||||
|
public static final int FIELD_COUNT = 17;
|
||||||
|
|
||||||
|
public static final int AM = 0;
|
||||||
|
|
||||||
|
public static final int PM = 1;
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
private static String[] fieldNames = { "ERA=", "YEAR=", "MONTH=", "WEEK_OF_YEAR=", "WEEK_OF_MONTH=",
|
||||||
|
"DAY_OF_MONTH=", "DAY_OF_YEAR=", "DAY_OF_WEEK=", "DAY_OF_WEEK_IN_MONTH=", "AM_PM=", "HOUR=", "HOUR_OF_DAY",
|
||||||
|
"MINUTE=", "SECOND=", "MILLISECOND=", "ZONE_OFFSET=", "DST_OFFSET=" };
|
||||||
|
|
||||||
|
protected TCalendar() {
|
||||||
|
this(TLocale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TCalendar(TLocale locale) {
|
||||||
|
fields = new int[FIELD_COUNT];
|
||||||
|
isSet = new boolean[FIELD_COUNT];
|
||||||
|
areFieldsSet = isTimeSet = false;
|
||||||
|
setLenient(true);
|
||||||
|
initLocales();
|
||||||
|
String localeCode = CLDRHelper.getCode(locale.getLanguage(), locale.getCountry());
|
||||||
|
setFirstDayOfWeek(getFirstDayOfWeek(localeCode));
|
||||||
|
setMinimalDaysInFirstWeek(getMinimalDaysInFirstWeek(localeCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generated by JCLPlugin
|
||||||
|
private static native void initLocales();
|
||||||
|
|
||||||
|
// TODO: implement using CLDR
|
||||||
|
private static native int getFirstDayOfWeek(String localeCode);
|
||||||
|
|
||||||
|
// TODO: implement using CLDR
|
||||||
|
private static native int getMinimalDaysInFirstWeek(String localeCode);
|
||||||
|
|
||||||
|
abstract public void add(int field, int value);
|
||||||
|
|
||||||
|
public boolean after(Object calendar) {
|
||||||
|
if (!(calendar instanceof TCalendar)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getTimeInMillis() > ((TCalendar) calendar).getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean before(Object calendar) {
|
||||||
|
if (!(calendar instanceof TCalendar)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getTimeInMillis() < ((TCalendar) calendar).getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void clear() {
|
||||||
|
for (int i = 0; i < FIELD_COUNT; i++) {
|
||||||
|
fields[i] = 0;
|
||||||
|
isSet[i] = false;
|
||||||
|
}
|
||||||
|
areFieldsSet = isTimeSet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void clear(int field) {
|
||||||
|
fields[field] = 0;
|
||||||
|
isSet[field] = false;
|
||||||
|
areFieldsSet = isTimeSet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object clone() {
|
||||||
|
try {
|
||||||
|
TCalendar clone = (TCalendar) super.clone();
|
||||||
|
clone.fields = fields.clone();
|
||||||
|
clone.isSet = isSet.clone();
|
||||||
|
return clone;
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void complete() {
|
||||||
|
if (!isTimeSet) {
|
||||||
|
computeTime();
|
||||||
|
isTimeSet = true;
|
||||||
|
}
|
||||||
|
if (!areFieldsSet) {
|
||||||
|
computeFields();
|
||||||
|
areFieldsSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void computeFields();
|
||||||
|
|
||||||
|
protected abstract void computeTime();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(object instanceof TCalendar)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TCalendar cal = (TCalendar) object;
|
||||||
|
return getTimeInMillis() == cal.getTimeInMillis() && isLenient() == cal.isLenient() &&
|
||||||
|
getFirstDayOfWeek() == cal.getFirstDayOfWeek() &&
|
||||||
|
getMinimalDaysInFirstWeek() == cal.getMinimalDaysInFirstWeek();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get(int field) {
|
||||||
|
complete();
|
||||||
|
return fields[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getActualMaximum(int field) {
|
||||||
|
int value, next;
|
||||||
|
if (getMaximum(field) == (next = getLeastMaximum(field))) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
complete();
|
||||||
|
long orgTime = time;
|
||||||
|
set(field, next);
|
||||||
|
do {
|
||||||
|
value = next;
|
||||||
|
roll(field, true);
|
||||||
|
next = get(field);
|
||||||
|
} while (next > value);
|
||||||
|
time = orgTime;
|
||||||
|
areFieldsSet = false;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getActualMinimum(int field) {
|
||||||
|
int value, next;
|
||||||
|
if (getMinimum(field) == (next = getGreatestMinimum(field))) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
complete();
|
||||||
|
long orgTime = time;
|
||||||
|
set(field, next);
|
||||||
|
do {
|
||||||
|
value = next;
|
||||||
|
roll(field, false);
|
||||||
|
next = get(field);
|
||||||
|
} while (next < value);
|
||||||
|
time = orgTime;
|
||||||
|
areFieldsSet = false;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized TLocale[] getAvailableLocales() {
|
||||||
|
return TLocale.getAvailableLocales();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFirstDayOfWeek() {
|
||||||
|
return firstDayOfWeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public int getGreatestMinimum(int field);
|
||||||
|
|
||||||
|
public static synchronized TCalendar getInstance() {
|
||||||
|
return new TGregorianCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized TCalendar getInstance(TLocale locale) {
|
||||||
|
return new TGregorianCalendar(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public int getLeastMaximum(int field);
|
||||||
|
|
||||||
|
abstract public int getMaximum(int field);
|
||||||
|
|
||||||
|
public int getMinimalDaysInFirstWeek() {
|
||||||
|
return minimalDaysInFirstWeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public int getMinimum(int field);
|
||||||
|
|
||||||
|
public final TDate getTime() {
|
||||||
|
return new TDate(getTimeInMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimeInMillis() {
|
||||||
|
if (!isTimeSet) {
|
||||||
|
computeTime();
|
||||||
|
isTimeSet = true;
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (isLenient() ? 1237 : 1231) + getFirstDayOfWeek() + getMinimalDaysInFirstWeek();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final int internalGet(int field) {
|
||||||
|
return fields[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLenient() {
|
||||||
|
return lenient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isSet(int field) {
|
||||||
|
return isSet[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void roll(int field, int value) {
|
||||||
|
boolean increment = value >= 0;
|
||||||
|
int count = increment ? value : -value;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
roll(field, increment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public void roll(int field, boolean increment);
|
||||||
|
|
||||||
|
public void set(int field, int value) {
|
||||||
|
fields[field] = value;
|
||||||
|
isSet[field] = true;
|
||||||
|
areFieldsSet = isTimeSet = false;
|
||||||
|
if (field > MONTH && field < AM_PM) {
|
||||||
|
lastDateFieldSet = field;
|
||||||
|
}
|
||||||
|
if (field == HOUR || field == HOUR_OF_DAY) {
|
||||||
|
lastTimeFieldSet = field;
|
||||||
|
}
|
||||||
|
if (field == AM_PM) {
|
||||||
|
lastTimeFieldSet = HOUR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void set(int year, int month, int day) {
|
||||||
|
set(YEAR, year);
|
||||||
|
set(MONTH, month);
|
||||||
|
set(DATE, day);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void set(int year, int month, int day, int hourOfDay, int minute) {
|
||||||
|
set(year, month, day);
|
||||||
|
set(HOUR_OF_DAY, hourOfDay);
|
||||||
|
set(MINUTE, minute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void set(int year, int month, int day, int hourOfDay, int minute, int second) {
|
||||||
|
set(year, month, day, hourOfDay, minute);
|
||||||
|
set(SECOND, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstDayOfWeek(int value) {
|
||||||
|
firstDayOfWeek = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLenient(boolean value) {
|
||||||
|
lenient = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinimalDaysInFirstWeek(int value) {
|
||||||
|
minimalDaysInFirstWeek = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setTime(TDate date) {
|
||||||
|
setTimeInMillis(date.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeInMillis(long milliseconds) {
|
||||||
|
if (!isTimeSet || !areFieldsSet || time != milliseconds) {
|
||||||
|
time = milliseconds;
|
||||||
|
isTimeSet = true;
|
||||||
|
areFieldsSet = false;
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder result = new StringBuilder(getClass().getName() + "[time=" +
|
||||||
|
(isTimeSet ? String.valueOf(time) : "?") + ",areFieldsSet=" + areFieldsSet + ",lenient=" + lenient +
|
||||||
|
",firstDayOfWeek=" + firstDayOfWeek + ",minimalDaysInFirstWeek=" +
|
||||||
|
minimalDaysInFirstWeek);
|
||||||
|
for (int i = 0; i < FIELD_COUNT; i++) {
|
||||||
|
result.append(',');
|
||||||
|
result.append(fieldNames[i]);
|
||||||
|
result.append('=');
|
||||||
|
if (isSet[i]) {
|
||||||
|
result.append(fields[i]);
|
||||||
|
} else {
|
||||||
|
result.append('?');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.append(']');
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(TCalendar anotherCalendar) {
|
||||||
|
if (null == anotherCalendar) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
long timeInMillis = getTimeInMillis();
|
||||||
|
long anotherTimeInMillis = anotherCalendar.getTimeInMillis();
|
||||||
|
if (timeInMillis > anotherTimeInMillis) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (timeInMillis == anotherTimeInMillis) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,14 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.java.util;
|
package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
|
import org.teavm.classlib.java.lang.TComparable;
|
||||||
import org.teavm.classlib.java.lang.TSystem;
|
import org.teavm.classlib.java.lang.TSystem;
|
||||||
|
import org.teavm.dependency.PluggableDependency;
|
||||||
import org.teavm.javascript.ni.GeneratedBy;
|
import org.teavm.javascript.ni.GeneratedBy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class TDate {
|
public class TDate implements TComparable<TDate> {
|
||||||
private long value;
|
private long value;
|
||||||
|
|
||||||
@GeneratedBy(DateNativeGenerator.class)
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
|
@ -155,6 +157,45 @@ public class TDate {
|
||||||
return value > when.value;
|
return value > when.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof TDate)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TDate other = (TDate)obj;
|
||||||
|
return value == other.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(TDate other) {
|
||||||
|
return Long.compare(value, other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (int)value ^ (int)(value >>> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public String toLocaleString() {
|
||||||
|
return toLocaleFormat(value, "%c");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public String toGMTString() {
|
||||||
|
return toGMTString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public int getTimezoneOffset() {
|
||||||
|
return getTimezoneOffset(value);
|
||||||
|
}
|
||||||
|
|
||||||
@GeneratedBy(DateNativeGenerator.class)
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
private static native int getFullYear(double date);
|
private static native int getFullYear(double date);
|
||||||
|
|
||||||
|
@ -176,7 +217,6 @@ public class TDate {
|
||||||
@GeneratedBy(DateNativeGenerator.class)
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
private static native int getDay(double date);
|
private static native int getDay(double date);
|
||||||
|
|
||||||
|
|
||||||
@GeneratedBy(DateNativeGenerator.class)
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
private static native int getHours(double date);
|
private static native int getHours(double date);
|
||||||
|
|
||||||
|
@ -203,4 +243,20 @@ public class TDate {
|
||||||
|
|
||||||
@GeneratedBy(DateNativeGenerator.class)
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
private static native double buildNumericUTC(int year, int month, int date, int hrs, int min, int sec);
|
private static native double buildNumericUTC(int year, int month, int date, int hrs, int min, int sec);
|
||||||
|
|
||||||
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
|
@PluggableDependency(DateNativeGenerator.class)
|
||||||
|
private static native String toString(double value);
|
||||||
|
|
||||||
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
|
@PluggableDependency(DateNativeGenerator.class)
|
||||||
|
private static native String toLocaleFormat(double value, String format);
|
||||||
|
|
||||||
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
|
@PluggableDependency(DateNativeGenerator.class)
|
||||||
|
private static native String toGMTString(double value);
|
||||||
|
|
||||||
|
@GeneratedBy(DateNativeGenerator.class)
|
||||||
|
@PluggableDependency(DateNativeGenerator.class)
|
||||||
|
static native int getTimezoneOffset(double value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,927 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
|
public class TGregorianCalendar extends TCalendar {
|
||||||
|
public static final int BC = 0;
|
||||||
|
|
||||||
|
public static final int AD = 1;
|
||||||
|
|
||||||
|
private static final long defaultGregorianCutover = -12219292800000l;
|
||||||
|
|
||||||
|
private long gregorianCutover = defaultGregorianCutover;
|
||||||
|
|
||||||
|
private transient int changeYear = 1582;
|
||||||
|
|
||||||
|
private transient int julianSkew = ((changeYear - 2000) / 400) + julianError() - ((changeYear - 2000) / 100);
|
||||||
|
|
||||||
|
static byte[] DaysInMonth = new byte[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
|
private static int[] DaysInYear = new int[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||||
|
|
||||||
|
private static int[] maximums = new int[] { 1, 292278994, 11, 53, 6, 31, 366, 7, 6, 1, 11, 23, 59, 59, 999,
|
||||||
|
14 * 3600 * 1000, 7200000 };
|
||||||
|
|
||||||
|
private static int[] minimums = new int[] { 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, -13 * 3600 * 1000, 0 };
|
||||||
|
|
||||||
|
private static int[] leastMaximums = new int[] { 1, 292269054, 11, 50, 3, 28, 355, 7, 3, 1, 11, 23, 59, 59, 999,
|
||||||
|
50400000, 1200000 };
|
||||||
|
|
||||||
|
private boolean isCached;
|
||||||
|
|
||||||
|
private int cachedFields[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
private long nextMidnightMillis = 0L;
|
||||||
|
|
||||||
|
private long lastMidnightMillis = 0L;
|
||||||
|
|
||||||
|
private int currentYearSkew = 10;
|
||||||
|
|
||||||
|
private int lastYearSkew = 0;
|
||||||
|
|
||||||
|
public TGregorianCalendar() {
|
||||||
|
this(TLocale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TGregorianCalendar(int year, int month, int day) {
|
||||||
|
set(year, month, day);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TGregorianCalendar(int year, int month, int day, int hour, int minute) {
|
||||||
|
set(year, month, day, hour, minute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TGregorianCalendar(int year, int month, int day, int hour, int minute, int second) {
|
||||||
|
set(year, month, day, hour, minute, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
TGregorianCalendar(long milliseconds) {
|
||||||
|
this(false);
|
||||||
|
setTimeInMillis(milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TGregorianCalendar(TLocale locale) {
|
||||||
|
super(locale);
|
||||||
|
setTimeInMillis(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
TGregorianCalendar(@SuppressWarnings("unused") boolean ignored) {
|
||||||
|
setFirstDayOfWeek(SUNDAY);
|
||||||
|
setMinimalDaysInFirstWeek(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(int field, int value) {
|
||||||
|
if (value == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (field < 0 || field >= ZONE_OFFSET) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
isCached = false;
|
||||||
|
|
||||||
|
if (field == ERA) {
|
||||||
|
complete();
|
||||||
|
if (fields[ERA] == AD) {
|
||||||
|
if (value >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set(ERA, BC);
|
||||||
|
} else {
|
||||||
|
if (value <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set(ERA, AD);
|
||||||
|
}
|
||||||
|
complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field == YEAR || field == MONTH) {
|
||||||
|
complete();
|
||||||
|
if (field == MONTH) {
|
||||||
|
int month = fields[MONTH] + value;
|
||||||
|
if (month < 0) {
|
||||||
|
value = (month - 11) / 12;
|
||||||
|
month = 12 + (month % 12);
|
||||||
|
} else {
|
||||||
|
value = month / 12;
|
||||||
|
}
|
||||||
|
set(MONTH, month % 12);
|
||||||
|
}
|
||||||
|
set(YEAR, fields[YEAR] + value);
|
||||||
|
int days = daysInMonth(isLeapYear(fields[YEAR]), fields[MONTH]);
|
||||||
|
if (fields[DATE] > days) {
|
||||||
|
set(DATE, days);
|
||||||
|
}
|
||||||
|
complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long multiplier = 0;
|
||||||
|
getTimeInMillis(); // Update the time
|
||||||
|
switch (field) {
|
||||||
|
case MILLISECOND:
|
||||||
|
time += value;
|
||||||
|
break;
|
||||||
|
case SECOND:
|
||||||
|
time += value * 1000L;
|
||||||
|
break;
|
||||||
|
case MINUTE:
|
||||||
|
time += value * 60000L;
|
||||||
|
break;
|
||||||
|
case HOUR:
|
||||||
|
case HOUR_OF_DAY:
|
||||||
|
time += value * 3600000L;
|
||||||
|
break;
|
||||||
|
case AM_PM:
|
||||||
|
multiplier = 43200000L;
|
||||||
|
break;
|
||||||
|
case DATE:
|
||||||
|
case DAY_OF_YEAR:
|
||||||
|
case DAY_OF_WEEK:
|
||||||
|
multiplier = 86400000L;
|
||||||
|
break;
|
||||||
|
case WEEK_OF_YEAR:
|
||||||
|
case WEEK_OF_MONTH:
|
||||||
|
case DAY_OF_WEEK_IN_MONTH:
|
||||||
|
multiplier = 604800000L;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (multiplier > 0) {
|
||||||
|
int offset = getTimeZoneOffset(time);
|
||||||
|
time += value * multiplier;
|
||||||
|
int newOffset = getTimeZoneOffset(time);
|
||||||
|
// Adjust for moving over a DST boundary
|
||||||
|
if (newOffset != offset) {
|
||||||
|
time += offset - newOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
areFieldsSet = false;
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object clone() {
|
||||||
|
TGregorianCalendar thisClone = (TGregorianCalendar) super.clone();
|
||||||
|
thisClone.cachedFields = cachedFields.clone();
|
||||||
|
return thisClone;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final void fullFieldsCalc(long timeVal, int millis, int zoneOffset) {
|
||||||
|
long days = timeVal / 86400000;
|
||||||
|
|
||||||
|
if (millis < 0) {
|
||||||
|
millis += 86400000;
|
||||||
|
days--;
|
||||||
|
}
|
||||||
|
// Cannot add ZONE_OFFSET to time as it might overflow
|
||||||
|
millis += zoneOffset;
|
||||||
|
while (millis < 0) {
|
||||||
|
millis += 86400000;
|
||||||
|
days--;
|
||||||
|
}
|
||||||
|
while (millis >= 86400000) {
|
||||||
|
millis -= 86400000;
|
||||||
|
days++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dayOfYear = computeYearAndDay(days, timeVal + zoneOffset);
|
||||||
|
fields[DAY_OF_YEAR] = dayOfYear;
|
||||||
|
if (fields[YEAR] == changeYear && gregorianCutover <= timeVal + zoneOffset) {
|
||||||
|
dayOfYear += currentYearSkew;
|
||||||
|
}
|
||||||
|
int month = dayOfYear / 32;
|
||||||
|
boolean leapYear = isLeapYear(fields[YEAR]);
|
||||||
|
int date = dayOfYear - daysInYear(leapYear, month);
|
||||||
|
if (date > daysInMonth(leapYear, month)) {
|
||||||
|
date -= daysInMonth(leapYear, month);
|
||||||
|
month++;
|
||||||
|
}
|
||||||
|
fields[DAY_OF_WEEK] = mod7(days - 3) + 1;
|
||||||
|
int dstOffset = getTimeZoneOffset(timeVal);
|
||||||
|
if (fields[YEAR] > 0) {
|
||||||
|
dstOffset -= zoneOffset;
|
||||||
|
}
|
||||||
|
fields[DST_OFFSET] = dstOffset;
|
||||||
|
if (dstOffset != 0) {
|
||||||
|
long oldDays = days;
|
||||||
|
millis += dstOffset;
|
||||||
|
if (millis < 0) {
|
||||||
|
millis += 86400000;
|
||||||
|
days--;
|
||||||
|
} else if (millis >= 86400000) {
|
||||||
|
millis -= 86400000;
|
||||||
|
days++;
|
||||||
|
}
|
||||||
|
if (oldDays != days) {
|
||||||
|
dayOfYear = computeYearAndDay(days, timeVal - zoneOffset + dstOffset);
|
||||||
|
fields[DAY_OF_YEAR] = dayOfYear;
|
||||||
|
if (fields[YEAR] == changeYear && gregorianCutover <= timeVal - zoneOffset + dstOffset) {
|
||||||
|
dayOfYear += currentYearSkew;
|
||||||
|
}
|
||||||
|
month = dayOfYear / 32;
|
||||||
|
leapYear = isLeapYear(fields[YEAR]);
|
||||||
|
date = dayOfYear - daysInYear(leapYear, month);
|
||||||
|
if (date > daysInMonth(leapYear, month)) {
|
||||||
|
date -= daysInMonth(leapYear, month);
|
||||||
|
month++;
|
||||||
|
}
|
||||||
|
fields[DAY_OF_WEEK] = mod7(days - 3) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fields[MILLISECOND] = (millis % 1000);
|
||||||
|
millis /= 1000;
|
||||||
|
fields[SECOND] = (millis % 60);
|
||||||
|
millis /= 60;
|
||||||
|
fields[MINUTE] = (millis % 60);
|
||||||
|
millis /= 60;
|
||||||
|
fields[HOUR_OF_DAY] = (millis % 24);
|
||||||
|
fields[AM_PM] = fields[HOUR_OF_DAY] > 11 ? 1 : 0;
|
||||||
|
fields[HOUR] = fields[HOUR_OF_DAY] % 12;
|
||||||
|
|
||||||
|
if (fields[YEAR] <= 0) {
|
||||||
|
fields[ERA] = BC;
|
||||||
|
fields[YEAR] = -fields[YEAR] + 1;
|
||||||
|
} else {
|
||||||
|
fields[ERA] = AD;
|
||||||
|
}
|
||||||
|
fields[MONTH] = month;
|
||||||
|
fields[DATE] = date;
|
||||||
|
fields[DAY_OF_WEEK_IN_MONTH] = (date - 1) / 7 + 1;
|
||||||
|
fields[WEEK_OF_MONTH] = (date - 1 + mod7(days - date - 2 - (getFirstDayOfWeek() - 1))) / 7 + 1;
|
||||||
|
int daysFromStart = mod7(days - 3 - (fields[DAY_OF_YEAR] - 1) - (getFirstDayOfWeek() - 1));
|
||||||
|
int week = (fields[DAY_OF_YEAR] - 1 + daysFromStart) / 7 +
|
||||||
|
(7 - daysFromStart >= getMinimalDaysInFirstWeek() ? 1 : 0);
|
||||||
|
if (week == 0) {
|
||||||
|
fields[WEEK_OF_YEAR] = 7 - mod7(daysFromStart - (isLeapYear(fields[YEAR] - 1) ? 2 : 1)) >= getMinimalDaysInFirstWeek() ? 53
|
||||||
|
: 52;
|
||||||
|
} else if (fields[DAY_OF_YEAR] >= (leapYear ? 367 : 366) - mod7(daysFromStart + (leapYear ? 2 : 1))) {
|
||||||
|
fields[WEEK_OF_YEAR] = 7 - mod7(daysFromStart + (leapYear ? 2 : 1)) >= getMinimalDaysInFirstWeek() ? 1
|
||||||
|
: week;
|
||||||
|
} else {
|
||||||
|
fields[WEEK_OF_YEAR] = week;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final void cachedFieldsCheckAndGet(long timeVal, long newTimeMillis, long newTimeMillisAdjusted,
|
||||||
|
int millis, int zoneOffset) {
|
||||||
|
int dstOffset = fields[DST_OFFSET];
|
||||||
|
if (!isCached || newTimeMillis >= nextMidnightMillis || newTimeMillis <= lastMidnightMillis ||
|
||||||
|
cachedFields[4] != zoneOffset || (dstOffset == 0 && (newTimeMillisAdjusted >= nextMidnightMillis)) ||
|
||||||
|
(dstOffset != 0 && (newTimeMillisAdjusted <= lastMidnightMillis))) {
|
||||||
|
fullFieldsCalc(timeVal, millis, zoneOffset);
|
||||||
|
isCached = false;
|
||||||
|
} else {
|
||||||
|
fields[YEAR] = cachedFields[0];
|
||||||
|
fields[MONTH] = cachedFields[1];
|
||||||
|
fields[DATE] = cachedFields[2];
|
||||||
|
fields[DAY_OF_WEEK] = cachedFields[3];
|
||||||
|
fields[ERA] = cachedFields[5];
|
||||||
|
fields[WEEK_OF_YEAR] = cachedFields[6];
|
||||||
|
fields[WEEK_OF_MONTH] = cachedFields[7];
|
||||||
|
fields[DAY_OF_YEAR] = cachedFields[8];
|
||||||
|
fields[DAY_OF_WEEK_IN_MONTH] = cachedFields[9];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getTimeZoneOffset(double time) {
|
||||||
|
return TDate.getTimezoneOffset(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void computeFields() {
|
||||||
|
int zoneOffset = getTimeZoneOffset(time);
|
||||||
|
|
||||||
|
if (!isSet[ZONE_OFFSET]) {
|
||||||
|
fields[ZONE_OFFSET] = zoneOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int millis = (int) (time % 86400000);
|
||||||
|
int savedMillis = millis;
|
||||||
|
int dstOffset = fields[DST_OFFSET];
|
||||||
|
// compute without a change in daylight saving time
|
||||||
|
int offset = zoneOffset + dstOffset;
|
||||||
|
long newTime = time + offset;
|
||||||
|
|
||||||
|
if (time > 0L && newTime < 0L && offset > 0) {
|
||||||
|
newTime = 0x7fffffffffffffffL;
|
||||||
|
} else if (time < 0L && newTime > 0L && offset < 0) {
|
||||||
|
newTime = 0x8000000000000000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCached) {
|
||||||
|
if (millis < 0) {
|
||||||
|
millis += 86400000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot add ZONE_OFFSET to time as it might overflow
|
||||||
|
millis += zoneOffset;
|
||||||
|
millis += dstOffset;
|
||||||
|
|
||||||
|
if (millis < 0) {
|
||||||
|
millis += 86400000;
|
||||||
|
} else if (millis >= 86400000) {
|
||||||
|
millis -= 86400000;
|
||||||
|
}
|
||||||
|
|
||||||
|
fields[MILLISECOND] = (millis % 1000);
|
||||||
|
millis /= 1000;
|
||||||
|
fields[SECOND] = (millis % 60);
|
||||||
|
millis /= 60;
|
||||||
|
fields[MINUTE] = (millis % 60);
|
||||||
|
millis /= 60;
|
||||||
|
fields[HOUR_OF_DAY] = (millis % 24);
|
||||||
|
millis /= 24;
|
||||||
|
fields[AM_PM] = fields[HOUR_OF_DAY] > 11 ? 1 : 0;
|
||||||
|
fields[HOUR] = fields[HOUR_OF_DAY] % 12;
|
||||||
|
|
||||||
|
long newTimeAdjusted = newTime;
|
||||||
|
if (newTime > 0L && newTimeAdjusted < 0L && dstOffset == 0) {
|
||||||
|
newTimeAdjusted = 0x7fffffffffffffffL;
|
||||||
|
} else if (newTime < 0L && newTimeAdjusted > 0L && dstOffset != 0) {
|
||||||
|
newTimeAdjusted = 0x8000000000000000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedFieldsCheckAndGet(time, newTime, newTimeAdjusted, savedMillis, zoneOffset);
|
||||||
|
} else {
|
||||||
|
fullFieldsCalc(time, savedMillis, zoneOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < FIELD_COUNT; i++) {
|
||||||
|
isSet[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caching
|
||||||
|
if (!isCached && newTime != 0x7fffffffffffffffL && newTime != 0x8000000000000000L) {
|
||||||
|
int cacheMillis = 0;
|
||||||
|
|
||||||
|
cachedFields[0] = fields[YEAR];
|
||||||
|
cachedFields[1] = fields[MONTH];
|
||||||
|
cachedFields[2] = fields[DATE];
|
||||||
|
cachedFields[3] = fields[DAY_OF_WEEK];
|
||||||
|
cachedFields[4] = zoneOffset;
|
||||||
|
cachedFields[5] = fields[ERA];
|
||||||
|
cachedFields[6] = fields[WEEK_OF_YEAR];
|
||||||
|
cachedFields[7] = fields[WEEK_OF_MONTH];
|
||||||
|
cachedFields[8] = fields[DAY_OF_YEAR];
|
||||||
|
cachedFields[9] = fields[DAY_OF_WEEK_IN_MONTH];
|
||||||
|
|
||||||
|
cacheMillis += (23 - fields[HOUR_OF_DAY]) * 60 * 60 * 1000;
|
||||||
|
cacheMillis += (59 - fields[MINUTE]) * 60 * 1000;
|
||||||
|
cacheMillis += (59 - fields[SECOND]) * 1000;
|
||||||
|
nextMidnightMillis = newTime + cacheMillis;
|
||||||
|
|
||||||
|
cacheMillis = fields[HOUR_OF_DAY] * 60 * 60 * 1000;
|
||||||
|
cacheMillis += fields[MINUTE] * 60 * 1000;
|
||||||
|
cacheMillis += fields[SECOND] * 1000;
|
||||||
|
lastMidnightMillis = newTime - cacheMillis;
|
||||||
|
|
||||||
|
isCached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void computeTime() {
|
||||||
|
if (!isLenient()) {
|
||||||
|
if (isSet[HOUR_OF_DAY]) {
|
||||||
|
if (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
} else if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[MILLISECOND] && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[WEEK_OF_YEAR] && (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > 53)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[DAY_OF_WEEK] && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[DAY_OF_WEEK_IN_MONTH] && (fields[DAY_OF_WEEK_IN_MONTH] < 1 || fields[DAY_OF_WEEK_IN_MONTH] > 6)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[WEEK_OF_MONTH] && (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > 6)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (isSet[YEAR]) {
|
||||||
|
if (isSet[ERA] && fields[ERA] == BC && (fields[YEAR] < 1 || fields[YEAR] > 292269054)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
} else if (fields[YEAR] < 1 || fields[YEAR] > 292278994) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isSet[MONTH] && (fields[MONTH] < 0 || fields[MONTH] > 11)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long timeVal;
|
||||||
|
long hour = 0;
|
||||||
|
if (isSet[HOUR_OF_DAY] && lastTimeFieldSet != HOUR) {
|
||||||
|
hour = fields[HOUR_OF_DAY];
|
||||||
|
} else if (isSet[HOUR]) {
|
||||||
|
hour = (fields[AM_PM] * 12) + fields[HOUR];
|
||||||
|
}
|
||||||
|
timeVal = hour * 3600000;
|
||||||
|
|
||||||
|
if (isSet[MINUTE]) {
|
||||||
|
timeVal += ((long) fields[MINUTE]) * 60000;
|
||||||
|
}
|
||||||
|
if (isSet[SECOND]) {
|
||||||
|
timeVal += ((long) fields[SECOND]) * 1000;
|
||||||
|
}
|
||||||
|
if (isSet[MILLISECOND]) {
|
||||||
|
timeVal += fields[MILLISECOND];
|
||||||
|
}
|
||||||
|
|
||||||
|
long days;
|
||||||
|
int year = isSet[YEAR] ? fields[YEAR] : 1970;
|
||||||
|
if (isSet[ERA]) {
|
||||||
|
// Always test for valid ERA, even if the Calendar is lenient
|
||||||
|
if (fields[ERA] != BC && fields[ERA] != AD) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (fields[ERA] == BC) {
|
||||||
|
year = 1 - year;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean weekMonthSet = isSet[WEEK_OF_MONTH] || isSet[DAY_OF_WEEK_IN_MONTH];
|
||||||
|
boolean useMonth = (isSet[DATE] || isSet[MONTH] || weekMonthSet) && lastDateFieldSet != DAY_OF_YEAR;
|
||||||
|
if (useMonth && (lastDateFieldSet == DAY_OF_WEEK || lastDateFieldSet == WEEK_OF_YEAR)) {
|
||||||
|
if (isSet[WEEK_OF_YEAR] && isSet[DAY_OF_WEEK]) {
|
||||||
|
useMonth = lastDateFieldSet != WEEK_OF_YEAR && weekMonthSet && isSet[DAY_OF_WEEK];
|
||||||
|
} else if (isSet[DAY_OF_YEAR]) {
|
||||||
|
useMonth = isSet[DATE] && isSet[MONTH];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useMonth) {
|
||||||
|
int month = fields[MONTH];
|
||||||
|
year += month / 12;
|
||||||
|
month %= 12;
|
||||||
|
if (month < 0) {
|
||||||
|
year--;
|
||||||
|
month += 12;
|
||||||
|
}
|
||||||
|
boolean leapYear = isLeapYear(year);
|
||||||
|
days = daysFromBaseYear(year) + daysInYear(leapYear, month);
|
||||||
|
boolean useDate = isSet[DATE];
|
||||||
|
if (useDate &&
|
||||||
|
(lastDateFieldSet == DAY_OF_WEEK || lastDateFieldSet == WEEK_OF_MONTH || lastDateFieldSet == DAY_OF_WEEK_IN_MONTH)) {
|
||||||
|
useDate = !(isSet[DAY_OF_WEEK] && weekMonthSet);
|
||||||
|
}
|
||||||
|
if (useDate) {
|
||||||
|
if (!isLenient() && (fields[DATE] < 1 || fields[DATE] > daysInMonth(leapYear, month))) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
days += fields[DATE] - 1;
|
||||||
|
} else {
|
||||||
|
int dayOfWeek;
|
||||||
|
if (isSet[DAY_OF_WEEK]) {
|
||||||
|
dayOfWeek = fields[DAY_OF_WEEK] - 1;
|
||||||
|
} else {
|
||||||
|
dayOfWeek = getFirstDayOfWeek() - 1;
|
||||||
|
}
|
||||||
|
if (isSet[WEEK_OF_MONTH] && lastDateFieldSet != DAY_OF_WEEK_IN_MONTH) {
|
||||||
|
int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1));
|
||||||
|
days += (fields[WEEK_OF_MONTH] - 1) * 7 + mod7(skew + dayOfWeek - (days - 3)) - skew;
|
||||||
|
} else if (isSet[DAY_OF_WEEK_IN_MONTH]) {
|
||||||
|
if (fields[DAY_OF_WEEK_IN_MONTH] >= 0) {
|
||||||
|
days += mod7(dayOfWeek - (days - 3)) + (fields[DAY_OF_WEEK_IN_MONTH] - 1) * 7;
|
||||||
|
} else {
|
||||||
|
days += daysInMonth(leapYear, month) +
|
||||||
|
mod7(dayOfWeek - (days + daysInMonth(leapYear, month) - 3)) +
|
||||||
|
fields[DAY_OF_WEEK_IN_MONTH] * 7;
|
||||||
|
}
|
||||||
|
} else if (isSet[DAY_OF_WEEK]) {
|
||||||
|
int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1));
|
||||||
|
days += mod7(mod7(skew + dayOfWeek - (days - 3)) - skew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
boolean useWeekYear = isSet[WEEK_OF_YEAR] && lastDateFieldSet != DAY_OF_YEAR;
|
||||||
|
if (useWeekYear && isSet[DAY_OF_YEAR]) {
|
||||||
|
useWeekYear = isSet[DAY_OF_WEEK];
|
||||||
|
}
|
||||||
|
days = daysFromBaseYear(year);
|
||||||
|
if (useWeekYear) {
|
||||||
|
int dayOfWeek;
|
||||||
|
if (isSet[DAY_OF_WEEK]) {
|
||||||
|
dayOfWeek = fields[DAY_OF_WEEK] - 1;
|
||||||
|
} else {
|
||||||
|
dayOfWeek = getFirstDayOfWeek() - 1;
|
||||||
|
}
|
||||||
|
int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1));
|
||||||
|
days += (fields[WEEK_OF_YEAR] - 1) * 7 + mod7(skew + dayOfWeek - (days - 3)) - skew;
|
||||||
|
if (7 - skew < getMinimalDaysInFirstWeek()) {
|
||||||
|
days += 7;
|
||||||
|
}
|
||||||
|
} else if (isSet[DAY_OF_YEAR]) {
|
||||||
|
if (!isLenient() &&
|
||||||
|
(fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > (365 + (isLeapYear(year) ? 1 : 0)))) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
days += fields[DAY_OF_YEAR] - 1;
|
||||||
|
} else if (isSet[DAY_OF_WEEK]) {
|
||||||
|
days += mod7(fields[DAY_OF_WEEK] - 1 - (days - 3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastDateFieldSet = 0;
|
||||||
|
|
||||||
|
timeVal += days * 86400000;
|
||||||
|
// Use local time to compare with the gregorian change
|
||||||
|
if (year == changeYear && timeVal >= gregorianCutover + julianError() * 86400000L) {
|
||||||
|
timeVal -= julianError() * 86400000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
long timeValWithoutDST = timeVal - getTimeZoneOffset(timeVal);
|
||||||
|
this.time = timeVal;
|
||||||
|
if (timeValWithoutDST != timeVal) {
|
||||||
|
computeFields();
|
||||||
|
areFieldsSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int computeYearAndDay(long dayCount, long localTime) {
|
||||||
|
int year = 1970;
|
||||||
|
long days = dayCount;
|
||||||
|
if (localTime < gregorianCutover) {
|
||||||
|
days -= julianSkew;
|
||||||
|
}
|
||||||
|
int approxYears;
|
||||||
|
|
||||||
|
while ((approxYears = (int) (days / 365)) != 0) {
|
||||||
|
year = year + approxYears;
|
||||||
|
days = dayCount - daysFromBaseYear(year);
|
||||||
|
}
|
||||||
|
if (days < 0) {
|
||||||
|
year = year - 1;
|
||||||
|
days = days + daysInYear(year);
|
||||||
|
}
|
||||||
|
fields[YEAR] = year;
|
||||||
|
return (int) days + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long daysFromBaseYear(int iyear) {
|
||||||
|
long year = iyear;
|
||||||
|
|
||||||
|
if (year >= 1970) {
|
||||||
|
long days = (year - 1970) * 365 + ((year - 1969) / 4);
|
||||||
|
if (year > changeYear) {
|
||||||
|
days -= ((year - 1901) / 100) - ((year - 1601) / 400);
|
||||||
|
} else {
|
||||||
|
if (year == changeYear) {
|
||||||
|
days += currentYearSkew;
|
||||||
|
} else if (year == changeYear - 1) {
|
||||||
|
days += lastYearSkew;
|
||||||
|
} else {
|
||||||
|
days += julianSkew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return days;
|
||||||
|
} else if (year <= changeYear) {
|
||||||
|
return (year - 1970) * 365 + ((year - 1972) / 4) + julianSkew;
|
||||||
|
}
|
||||||
|
return (year - 1970) * 365 + ((year - 1972) / 4) - ((year - 2000) / 100) + ((year - 2000) / 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int daysInMonth() {
|
||||||
|
return daysInMonth(isLeapYear(fields[YEAR]), fields[MONTH]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int daysInMonth(boolean leapYear, int month) {
|
||||||
|
if (leapYear && month == FEBRUARY) {
|
||||||
|
return DaysInMonth[month] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DaysInMonth[month];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int daysInYear(int year) {
|
||||||
|
int daysInYear = isLeapYear(year) ? 366 : 365;
|
||||||
|
if (year == changeYear) {
|
||||||
|
daysInYear -= currentYearSkew;
|
||||||
|
}
|
||||||
|
if (year == changeYear - 1) {
|
||||||
|
daysInYear -= lastYearSkew;
|
||||||
|
}
|
||||||
|
return daysInYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int daysInYear(boolean leapYear, int month) {
|
||||||
|
if (leapYear && month > FEBRUARY) {
|
||||||
|
return DaysInYear[month] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DaysInYear[month];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
return super.equals(object) && gregorianCutover == ((TGregorianCalendar) object).gregorianCutover;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getActualMaximum(int field) {
|
||||||
|
int value;
|
||||||
|
if ((value = maximums[field]) == leastMaximums[field]) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (field) {
|
||||||
|
case WEEK_OF_YEAR:
|
||||||
|
case WEEK_OF_MONTH:
|
||||||
|
isCached = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
complete();
|
||||||
|
long orgTime = time;
|
||||||
|
int result = 0;
|
||||||
|
switch (field) {
|
||||||
|
case WEEK_OF_YEAR:
|
||||||
|
set(DATE, 31);
|
||||||
|
set(MONTH, DECEMBER);
|
||||||
|
result = get(WEEK_OF_YEAR);
|
||||||
|
if (result == 1) {
|
||||||
|
set(DATE, 31 - 7);
|
||||||
|
result = get(WEEK_OF_YEAR);
|
||||||
|
}
|
||||||
|
areFieldsSet = false;
|
||||||
|
break;
|
||||||
|
case WEEK_OF_MONTH:
|
||||||
|
set(DATE, daysInMonth());
|
||||||
|
result = get(WEEK_OF_MONTH);
|
||||||
|
areFieldsSet = false;
|
||||||
|
break;
|
||||||
|
case DATE:
|
||||||
|
return daysInMonth();
|
||||||
|
case DAY_OF_YEAR:
|
||||||
|
return daysInYear(fields[YEAR]);
|
||||||
|
case DAY_OF_WEEK_IN_MONTH:
|
||||||
|
result = get(DAY_OF_WEEK_IN_MONTH) + ((daysInMonth() - get(DATE)) / 7);
|
||||||
|
break;
|
||||||
|
case YEAR:
|
||||||
|
TGregorianCalendar clone = (TGregorianCalendar) clone();
|
||||||
|
if (get(ERA) == AD) {
|
||||||
|
clone.setTimeInMillis(Long.MAX_VALUE);
|
||||||
|
} else {
|
||||||
|
clone.setTimeInMillis(Long.MIN_VALUE);
|
||||||
|
}
|
||||||
|
result = clone.get(YEAR);
|
||||||
|
clone.set(YEAR, get(YEAR));
|
||||||
|
if (clone.before(this)) {
|
||||||
|
result--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DST_OFFSET:
|
||||||
|
result = getMaximum(DST_OFFSET);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
time = orgTime;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getActualMinimum(int field) {
|
||||||
|
return getMinimum(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getGreatestMinimum(int field) {
|
||||||
|
return minimums[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
public final TDate getGregorianChange() {
|
||||||
|
return new TDate(gregorianCutover);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLeastMaximum(int field) {
|
||||||
|
// return value for WEEK_OF_YEAR should make corresponding changes when
|
||||||
|
// the gregorian change date have been reset.
|
||||||
|
if (gregorianCutover != defaultGregorianCutover && field == WEEK_OF_YEAR) {
|
||||||
|
long currentTimeInMillis = time;
|
||||||
|
setTimeInMillis(gregorianCutover);
|
||||||
|
int actual = getActualMaximum(field);
|
||||||
|
setTimeInMillis(currentTimeInMillis);
|
||||||
|
return actual;
|
||||||
|
}
|
||||||
|
return leastMaximums[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaximum(int field) {
|
||||||
|
return maximums[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinimum(int field) {
|
||||||
|
return minimums[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return super.hashCode() + ((int) (gregorianCutover >>> 32) ^ (int) gregorianCutover);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLeapYear(int year) {
|
||||||
|
if (year > changeYear) {
|
||||||
|
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return year % 4 == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int julianError() {
|
||||||
|
return changeYear / 100 - changeYear / 400 - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int mod(int value, int mod) {
|
||||||
|
int rem = value % mod;
|
||||||
|
if (value < 0 && rem < 0) {
|
||||||
|
return rem + mod;
|
||||||
|
}
|
||||||
|
return rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int mod7(long num1) {
|
||||||
|
int rem = (int) (num1 % 7);
|
||||||
|
if (num1 < 0 && rem < 0) {
|
||||||
|
return rem + 7;
|
||||||
|
}
|
||||||
|
return rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void roll(int field, int value) {
|
||||||
|
if (value == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (field < 0 || field >= ZONE_OFFSET) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
isCached = false;
|
||||||
|
|
||||||
|
complete();
|
||||||
|
int days, day, mod, maxWeeks, newWeek;
|
||||||
|
int max = -1;
|
||||||
|
switch (field) {
|
||||||
|
case YEAR:
|
||||||
|
max = maximums[field];
|
||||||
|
break;
|
||||||
|
case WEEK_OF_YEAR:
|
||||||
|
days = daysInYear(fields[YEAR]);
|
||||||
|
day = DAY_OF_YEAR;
|
||||||
|
mod = mod7(fields[DAY_OF_WEEK] - fields[day] - (getFirstDayOfWeek() - 1));
|
||||||
|
maxWeeks = (days - 1 + mod) / 7 + 1;
|
||||||
|
newWeek = mod(fields[field] - 1 + value, maxWeeks) + 1;
|
||||||
|
if (newWeek == maxWeeks) {
|
||||||
|
int addDays = (newWeek - fields[field]) * 7;
|
||||||
|
if (fields[day] > addDays && fields[day] + addDays > days) {
|
||||||
|
set(field, 1);
|
||||||
|
} else {
|
||||||
|
set(field, newWeek - 1);
|
||||||
|
}
|
||||||
|
} else if (newWeek == 1) {
|
||||||
|
int week = (fields[day] - ((fields[day] - 1) / 7 * 7) - 1 + mod) / 7 + 1;
|
||||||
|
if (week > 1) {
|
||||||
|
set(field, 1);
|
||||||
|
} else {
|
||||||
|
set(field, newWeek);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set(field, newWeek);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WEEK_OF_MONTH:
|
||||||
|
days = daysInMonth();
|
||||||
|
day = DATE;
|
||||||
|
mod = mod7(fields[DAY_OF_WEEK] - fields[day] - (getFirstDayOfWeek() - 1));
|
||||||
|
maxWeeks = (days - 1 + mod) / 7 + 1;
|
||||||
|
newWeek = mod(fields[field] - 1 + value, maxWeeks) + 1;
|
||||||
|
if (newWeek == maxWeeks) {
|
||||||
|
if (fields[day] + (newWeek - fields[field]) * 7 > days) {
|
||||||
|
set(day, days);
|
||||||
|
} else {
|
||||||
|
set(field, newWeek);
|
||||||
|
}
|
||||||
|
} else if (newWeek == 1) {
|
||||||
|
int week = (fields[day] - ((fields[day] - 1) / 7 * 7) - 1 + mod) / 7 + 1;
|
||||||
|
if (week > 1) {
|
||||||
|
set(day, 1);
|
||||||
|
} else {
|
||||||
|
set(field, newWeek);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set(field, newWeek);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DATE:
|
||||||
|
max = daysInMonth();
|
||||||
|
break;
|
||||||
|
case DAY_OF_YEAR:
|
||||||
|
max = daysInYear(fields[YEAR]);
|
||||||
|
break;
|
||||||
|
case DAY_OF_WEEK:
|
||||||
|
max = maximums[field];
|
||||||
|
lastDateFieldSet = WEEK_OF_MONTH;
|
||||||
|
break;
|
||||||
|
case DAY_OF_WEEK_IN_MONTH:
|
||||||
|
max = (fields[DATE] + ((daysInMonth() - fields[DATE]) / 7 * 7) - 1) / 7 + 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERA:
|
||||||
|
case MONTH:
|
||||||
|
case AM_PM:
|
||||||
|
case HOUR:
|
||||||
|
case HOUR_OF_DAY:
|
||||||
|
case MINUTE:
|
||||||
|
case SECOND:
|
||||||
|
case MILLISECOND:
|
||||||
|
set(field, mod(fields[field] + value, maximums[field] + 1));
|
||||||
|
if (field == MONTH && fields[DATE] > daysInMonth()) {
|
||||||
|
set(DATE, daysInMonth());
|
||||||
|
} else if (field == AM_PM) {
|
||||||
|
lastTimeFieldSet = HOUR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (max != -1) {
|
||||||
|
set(field, mod(fields[field] - 1 + value, max) + 1);
|
||||||
|
}
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void roll(int field, boolean increment) {
|
||||||
|
roll(field, increment ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGregorianChange(TDate date) {
|
||||||
|
gregorianCutover = date.getTime();
|
||||||
|
TGregorianCalendar cal = new TGregorianCalendar();
|
||||||
|
cal.setTime(date);
|
||||||
|
changeYear = cal.get(YEAR);
|
||||||
|
if (cal.get(ERA) == BC) {
|
||||||
|
changeYear = 1 - changeYear;
|
||||||
|
}
|
||||||
|
julianSkew = ((changeYear - 2000) / 400) + julianError() - ((changeYear - 2000) / 100);
|
||||||
|
isCached = false;
|
||||||
|
int dayOfYear = cal.get(DAY_OF_YEAR);
|
||||||
|
if (dayOfYear < julianSkew) {
|
||||||
|
currentYearSkew = dayOfYear - 1;
|
||||||
|
lastYearSkew = julianSkew - dayOfYear + 1;
|
||||||
|
} else {
|
||||||
|
lastYearSkew = 0;
|
||||||
|
currentYearSkew = julianSkew;
|
||||||
|
}
|
||||||
|
isCached = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFirstDayOfWeek(int value) {
|
||||||
|
super.setFirstDayOfWeek(value);
|
||||||
|
isCached = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMinimalDaysInFirstWeek(int value) {
|
||||||
|
super.setMinimalDaysInFirstWeek(value);
|
||||||
|
isCached = false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user