mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-09 08:24:10 -08:00
Implement Java time zone
This commit is contained in:
parent
c154a55ed5
commit
55212cbfe6
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.tz;
|
||||||
|
|
||||||
|
import org.teavm.classlib.impl.Base46;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class AliasDateTimeZone extends StorableDateTimeZone {
|
||||||
|
private DateTimeZone innerZone;
|
||||||
|
|
||||||
|
public AliasDateTimeZone(String id, DateTimeZone innerZone) {
|
||||||
|
super(id);
|
||||||
|
this.innerZone = innerZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOffset(long instant) {
|
||||||
|
return innerZone.getOffset(instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStandardOffset(long instant) {
|
||||||
|
return innerZone.getStandardOffset(instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFixed() {
|
||||||
|
return innerZone.isFixed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long nextTransition(long instant) {
|
||||||
|
return innerZone.nextTransition(instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long previousTransition(long instant) {
|
||||||
|
return innerZone.previousTransition(instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(StringBuilder sb) {
|
||||||
|
Base46.encode(sb, ALIAS);
|
||||||
|
sb.append(innerZone.getID());
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,7 +52,7 @@ public class DateTimeZoneProvider {
|
||||||
CharFlow flow = new CharFlow(data.toCharArray());
|
CharFlow flow = new CharFlow(data.toCharArray());
|
||||||
if (Base46.decode(flow) == StorableDateTimeZone.ALIAS) {
|
if (Base46.decode(flow) == StorableDateTimeZone.ALIAS) {
|
||||||
String aliasId = data.substring(flow.pointer);
|
String aliasId = data.substring(flow.pointer);
|
||||||
return getTimeZone(aliasId);
|
return new AliasDateTimeZone(id, getTimeZone(aliasId));
|
||||||
} else {
|
} else {
|
||||||
return StorableDateTimeZone.read(id, data);
|
return StorableDateTimeZone.read(id, data);
|
||||||
}
|
}
|
||||||
|
@ -173,11 +173,11 @@ public class DateTimeZoneProvider {
|
||||||
areaName = "";
|
areaName = "";
|
||||||
locationName = id;
|
locationName = id;
|
||||||
}
|
}
|
||||||
ResourceMap<TimeZoneResource> area = getResource().get(areaName);
|
if (!getResource().has(areaName)) {
|
||||||
if (area == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return area.get(locationName);
|
ResourceMap<TimeZoneResource> area = getResource().get(areaName);
|
||||||
|
return area.has(locationName) ? area.get(locationName) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JSBody(params = "instant", script = "return new Date(instant).getTimezoneOffset();")
|
@JSBody(params = "instant", script = "return new Date(instant).getTimezoneOffset();")
|
||||||
|
|
|
@ -19,11 +19,9 @@ import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import org.teavm.classlib.impl.Base46;
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.platform.metadata.MetadataGenerator;
|
import org.teavm.platform.metadata.MetadataGenerator;
|
||||||
import org.teavm.platform.metadata.MetadataGeneratorContext;
|
import org.teavm.platform.metadata.MetadataGeneratorContext;
|
||||||
|
@ -72,7 +70,6 @@ public class TimeZoneGenerator implements MetadataGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, StorableDateTimeZone> zoneMap = compiler.compile();
|
Map<String, StorableDateTimeZone> zoneMap = compiler.compile();
|
||||||
Map<StorableDateTimeZone, String> zones = new HashMap<>();
|
|
||||||
for (String id : zoneMap.keySet()) {
|
for (String id : zoneMap.keySet()) {
|
||||||
int sepIndex = id.indexOf('/');
|
int sepIndex = id.indexOf('/');
|
||||||
String areaName;
|
String areaName;
|
||||||
|
@ -93,14 +90,7 @@ public class TimeZoneGenerator implements MetadataGenerator {
|
||||||
StorableDateTimeZone tz = zoneMap.get(id);
|
StorableDateTimeZone tz = zoneMap.get(id);
|
||||||
TimeZoneResource tzRes = context.createResource(TimeZoneResource.class);
|
TimeZoneResource tzRes = context.createResource(TimeZoneResource.class);
|
||||||
StringBuilder data = new StringBuilder();
|
StringBuilder data = new StringBuilder();
|
||||||
String knownId = zones.get(tz);
|
tz.write(data);
|
||||||
if (knownId == null) {
|
|
||||||
tz.write(data);
|
|
||||||
zones.put(tz, id);
|
|
||||||
} else {
|
|
||||||
Base46.encode(data, StorableDateTimeZone.ALIAS);
|
|
||||||
data.append(knownId);
|
|
||||||
}
|
|
||||||
tzRes.setData(data.toString());
|
tzRes.setData(data.toString());
|
||||||
area.put(locationName, tzRes);
|
area.put(locationName, tzRes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ public class ZoneInfoCompiler {
|
||||||
alias + "' to");
|
alias + "' to");
|
||||||
}*/
|
}*/
|
||||||
} else {
|
} else {
|
||||||
map.put(alias, tz);
|
map.put(alias, new AliasDateTimeZone(alias, tz));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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 org.teavm.classlib.impl.tz.DateTimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
class TIANATimeZone extends TTimeZone {
|
||||||
|
private static final long serialVersionUID = -8196006595542230951L;
|
||||||
|
private DateTimeZone underlyingZone;
|
||||||
|
private int rawOffset;
|
||||||
|
|
||||||
|
public TIANATimeZone(DateTimeZone underlyingZone) {
|
||||||
|
super(underlyingZone.getID());
|
||||||
|
this.underlyingZone = underlyingZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOffset(int era, int year, int month, int day, int dayOfWeek, int time) {
|
||||||
|
TCalendar calendar = new TGregorianCalendar(year, month, day);
|
||||||
|
calendar.set(TCalendar.ERA, era);
|
||||||
|
calendar.set(TCalendar.DAY_OF_WEEK, dayOfWeek);
|
||||||
|
calendar.add(TCalendar.MILLISECOND, time);
|
||||||
|
return getOffset(calendar.getTimeInMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOffset(long time) {
|
||||||
|
return rawOffset + underlyingZone.getOffset(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRawOffset() {
|
||||||
|
return rawOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean inDaylightTime(TDate time) {
|
||||||
|
return underlyingZone.getOffset(time.getTime()) != underlyingZone.getStandardOffset(time.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRawOffset(int offset) {
|
||||||
|
this.rawOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useDaylightTime() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TIANATimeZone clone() {
|
||||||
|
TIANATimeZone copy = (TIANATimeZone)super.clone();
|
||||||
|
copy.rawOffset = rawOffset;
|
||||||
|
copy.underlyingZone = underlyingZone;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,473 @@
|
||||||
|
/*
|
||||||
|
* 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 java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import org.teavm.classlib.impl.tz.DateTimeZone;
|
||||||
|
import org.teavm.classlib.impl.tz.DateTimeZoneProvider;
|
||||||
|
import org.teavm.classlib.impl.tz.FixedDateTimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code TimeZone} represents a time zone offset, taking into account
|
||||||
|
* daylight savings.
|
||||||
|
* <p>
|
||||||
|
* Typically, you get a {@code TimeZone} using {@code getDefault}
|
||||||
|
* which creates a {@code TimeZone} based on the time zone where the
|
||||||
|
* program is running. For example, for a program running in Japan,
|
||||||
|
* {@code getDefault} creates a {@code TimeZone} object based on
|
||||||
|
* Japanese Standard Time.
|
||||||
|
* <p>
|
||||||
|
* You can also get a {@code TimeZone} using {@code getTimeZone}
|
||||||
|
* along with a time zone ID. For instance, the time zone ID for the U.S.
|
||||||
|
* Pacific Time zone is "America/Los_Angeles". So, you can get a U.S. Pacific
|
||||||
|
* Time {@code TimeZone} object with the following: <blockquote>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* </blockquote> You can use the {@code getAvailableIDs} method to iterate
|
||||||
|
* through all the supported time zone IDs. You can then choose a supported ID
|
||||||
|
* to get a {@code TimeZone}. If the time zone you want is not
|
||||||
|
* represented by one of the supported IDs, then you can create a custom time
|
||||||
|
* zone ID with the following syntax: <blockquote>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* GMT[+|-]hh[[:]mm]
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* </blockquote> For example, you might specify GMT+14:00 as a custom time zone
|
||||||
|
* ID. The {@code TimeZone} that is returned when you specify a custom
|
||||||
|
* time zone ID does not include daylight savings time.
|
||||||
|
* <p>
|
||||||
|
* For compatibility with JDK 1.1.x, some other three-letter time zone IDs (such
|
||||||
|
* as "PST", "CTT", "AST") are also supported. However, <strong>their use is
|
||||||
|
* deprecated</strong> because the same abbreviation is often used for multiple
|
||||||
|
* time zones (for example, "CST" could be U.S. "Central Standard Time" and
|
||||||
|
* "China Standard Time"), and the Java platform can then only recognize one of
|
||||||
|
* them.
|
||||||
|
* <p>
|
||||||
|
* Please note the type returned by factory methods, i.e. {@code getDefault()}
|
||||||
|
* and {@code getTimeZone(String)}, is implementation dependent, so it may
|
||||||
|
* introduce serialization incompatibility issues between different
|
||||||
|
* implementations.
|
||||||
|
*
|
||||||
|
* @see GregorianCalendar
|
||||||
|
* @see TSimpleTimeZone
|
||||||
|
*/
|
||||||
|
public abstract class TTimeZone implements Serializable, Cloneable {
|
||||||
|
private static final long serialVersionUID = 3581463369166924961L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SHORT display name style.
|
||||||
|
*/
|
||||||
|
public static final int SHORT = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LONG display name style.
|
||||||
|
*/
|
||||||
|
public static final int LONG = 1;
|
||||||
|
|
||||||
|
private static TTimeZone Default;
|
||||||
|
|
||||||
|
static TTimeZone GMT = new TIANATimeZone(new FixedDateTimeZone("GMT", 0, 0));
|
||||||
|
|
||||||
|
private String ID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of this class.
|
||||||
|
*/
|
||||||
|
public TTimeZone() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TTimeZone(String id) {
|
||||||
|
this.ID = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@code TimeZone} with the same ID, {@code rawOffset} and daylight savings
|
||||||
|
* time rules as this {@code TimeZone}.
|
||||||
|
*
|
||||||
|
* @return a shallow copy of this {@code TimeZone}.
|
||||||
|
* @see java.lang.Cloneable
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object clone() {
|
||||||
|
try {
|
||||||
|
TTimeZone zone = (TTimeZone) super.clone();
|
||||||
|
return zone;
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the available time zone IDs. Any one of these IDs can be passed to
|
||||||
|
* {@code get()} to create the corresponding {@code TimeZone} instance.
|
||||||
|
*
|
||||||
|
* @return an array of time zone ID strings.
|
||||||
|
*/
|
||||||
|
public static String[] getAvailableIDs() {
|
||||||
|
return DateTimeZoneProvider.getIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the available time zone IDs which match the specified offset from
|
||||||
|
* GMT. Any one of these IDs can be passed to {@code get()} to create the corresponding
|
||||||
|
* {@code TimeZone} instance.
|
||||||
|
*
|
||||||
|
* @param offset
|
||||||
|
* the offset from GMT in milliseconds.
|
||||||
|
* @return an array of time zone ID strings.
|
||||||
|
*/
|
||||||
|
public static String[] getAvailableIDs(int offset) {
|
||||||
|
String[] all = DateTimeZoneProvider.getIds();
|
||||||
|
String[] result = new String[all.length];
|
||||||
|
int i = 0;
|
||||||
|
for (String id : all) {
|
||||||
|
DateTimeZone jodaTz = DateTimeZoneProvider.getTimeZone(id);
|
||||||
|
if (jodaTz.getStandardOffset(System.currentTimeMillis()) == offset) {
|
||||||
|
result[i++] = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Arrays.copyOf(result, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default time zone.
|
||||||
|
*
|
||||||
|
* @return the default time zone.
|
||||||
|
*/
|
||||||
|
public static TTimeZone getDefault() {
|
||||||
|
if (Default == null) {
|
||||||
|
Default = new TIANATimeZone(DateTimeZoneProvider.detectTimezone());
|
||||||
|
}
|
||||||
|
return (TTimeZone) Default.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the LONG name for this {@code TimeZone} for the default {@code Locale} in standard
|
||||||
|
* time. If the name is not available, the result is in the format
|
||||||
|
* {@code GMT[+-]hh:mm}.
|
||||||
|
*
|
||||||
|
* @return the {@code TimeZone} name.
|
||||||
|
*/
|
||||||
|
public final String getDisplayName() {
|
||||||
|
return getDisplayName(false, LONG, TLocale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the LONG name for this {@code TimeZone} for the specified {@code Locale} in standard
|
||||||
|
* time. If the name is not available, the result is in the format
|
||||||
|
* {@code GMT[+-]hh:mm}.
|
||||||
|
*
|
||||||
|
* @param locale
|
||||||
|
* the {@code Locale}.
|
||||||
|
* @return the {@code TimeZone} name.
|
||||||
|
*/
|
||||||
|
public final String getDisplayName(TLocale locale) {
|
||||||
|
return getDisplayName(false, LONG, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the specified style of name ({@code LONG} or {@code SHORT}) for this {@code TimeZone} for
|
||||||
|
* the default {@code Locale} in either standard or daylight time as specified. If
|
||||||
|
* the name is not available, the result is in the format {@code GMT[+-]hh:mm}.
|
||||||
|
*
|
||||||
|
* @param daylightTime
|
||||||
|
* {@code true} for daylight time, {@code false} for standard
|
||||||
|
* time.
|
||||||
|
* @param style
|
||||||
|
* either {@code LONG} or {@code SHORT}.
|
||||||
|
* @return the {@code TimeZone} name.
|
||||||
|
*/
|
||||||
|
public final String getDisplayName(boolean daylightTime, int style) {
|
||||||
|
return getDisplayName(daylightTime, style, TLocale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the specified style of name ({@code LONG} or {@code SHORT}) for this {@code TimeZone} for
|
||||||
|
* the specified {@code Locale} in either standard or daylight time as specified. If
|
||||||
|
* the name is not available, the result is in the format {@code GMT[+-]hh:mm}.
|
||||||
|
*
|
||||||
|
* @param daylightTime
|
||||||
|
* {@code true} for daylight time, {@code false} for standard
|
||||||
|
* time.
|
||||||
|
* @param style
|
||||||
|
* either LONG or SHORT.
|
||||||
|
* @param locale
|
||||||
|
* either {@code LONG} or {@code SHORT}.
|
||||||
|
* @return the {@code TimeZone} name.
|
||||||
|
*/
|
||||||
|
public String getDisplayName(boolean daylightTime, int style, TLocale locale) {
|
||||||
|
// TODO: implement via CLDR
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ID of this {@code TimeZone}.
|
||||||
|
*
|
||||||
|
* @return the time zone ID string.
|
||||||
|
*/
|
||||||
|
public String getID() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the daylight savings offset in milliseconds for this {@code TimeZone}.
|
||||||
|
* <p>
|
||||||
|
* This implementation returns 3600000 (1 hour), or 0 if the time zone does
|
||||||
|
* not observe daylight savings.
|
||||||
|
* <p>
|
||||||
|
* Subclasses may override to return daylight savings values other than 1
|
||||||
|
* hour.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @return the daylight savings offset in milliseconds if this {@code TimeZone}
|
||||||
|
* observes daylight savings, zero otherwise.
|
||||||
|
*/
|
||||||
|
public int getDSTSavings() {
|
||||||
|
if (useDaylightTime()) {
|
||||||
|
return 3600000;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset from GMT of this {@code TimeZone} for the specified date. The
|
||||||
|
* offset includes daylight savings time if the specified date is within the
|
||||||
|
* daylight savings time period.
|
||||||
|
*
|
||||||
|
* @param time
|
||||||
|
* the date in milliseconds since January 1, 1970 00:00:00 GMT
|
||||||
|
* @return the offset from GMT in milliseconds.
|
||||||
|
*/
|
||||||
|
public int getOffset(long time) {
|
||||||
|
return inDaylightTime(new TDate(time)) ? getRawOffset() + getDSTSavings() : getRawOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset from GMT of this {@code TimeZone} for the specified date and
|
||||||
|
* time. The offset includes daylight savings time if the specified date and
|
||||||
|
* time are within the daylight savings time period.
|
||||||
|
*
|
||||||
|
* @param era
|
||||||
|
* the {@code GregorianCalendar} era, either {@code GregorianCalendar.BC} or
|
||||||
|
* {@code GregorianCalendar.AD}.
|
||||||
|
* @param year
|
||||||
|
* the year.
|
||||||
|
* @param month
|
||||||
|
* the {@code Calendar} month.
|
||||||
|
* @param day
|
||||||
|
* the day of the month.
|
||||||
|
* @param dayOfWeek
|
||||||
|
* the {@code Calendar} day of the week.
|
||||||
|
* @param time
|
||||||
|
* the time of day in milliseconds.
|
||||||
|
* @return the offset from GMT in milliseconds.
|
||||||
|
*/
|
||||||
|
abstract public int getOffset(int era, int year, int month, int day,
|
||||||
|
int dayOfWeek, int time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset for standard time from GMT for this {@code TimeZone}.
|
||||||
|
*
|
||||||
|
* @return the offset from GMT in milliseconds.
|
||||||
|
*/
|
||||||
|
abstract public int getRawOffset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@code TimeZone} with the specified ID.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* a time zone string ID.
|
||||||
|
* @return the {@code TimeZone} with the specified ID or null if no {@code TimeZone} with
|
||||||
|
* the specified ID exists.
|
||||||
|
*/
|
||||||
|
public static TTimeZone getTimeZone(String name) {
|
||||||
|
DateTimeZone jodaZone = DateTimeZoneProvider.getTimeZone(name);
|
||||||
|
if (jodaZone != null) {
|
||||||
|
return new TIANATimeZone(jodaZone);
|
||||||
|
}
|
||||||
|
if (name.startsWith("GMT") && name.length() > 3) {
|
||||||
|
char sign = name.charAt(3);
|
||||||
|
if (sign == '+' || sign == '-') {
|
||||||
|
int[] position = new int[1];
|
||||||
|
String formattedName = formatTimeZoneName(name, 4);
|
||||||
|
int hour = parseNumber(formattedName, 4, position);
|
||||||
|
if (hour < 0 || hour > 23) {
|
||||||
|
return (TTimeZone) GMT.clone();
|
||||||
|
}
|
||||||
|
int index = position[0];
|
||||||
|
if (index != -1) {
|
||||||
|
int raw = hour * 3600000;
|
||||||
|
if (index < formattedName.length()
|
||||||
|
&& formattedName.charAt(index) == ':') {
|
||||||
|
int minute = parseNumber(formattedName, index + 1,
|
||||||
|
position);
|
||||||
|
if (position[0] == -1 || minute < 0 || minute > 59) {
|
||||||
|
return (TTimeZone) GMT.clone();
|
||||||
|
}
|
||||||
|
raw += minute * 60000;
|
||||||
|
} else if (hour >= 30 || index > 6) {
|
||||||
|
raw = (hour / 100 * 3600000) + (hour % 100 * 60000);
|
||||||
|
}
|
||||||
|
if (sign == '-') {
|
||||||
|
raw = -raw;
|
||||||
|
}
|
||||||
|
return new TIANATimeZone(new FixedDateTimeZone(formattedName, raw, raw));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (TTimeZone) GMT.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatTimeZoneName(String name, int offset) {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
int index = offset, length = name.length();
|
||||||
|
buf.append(name.substring(0, offset));
|
||||||
|
|
||||||
|
while (index < length) {
|
||||||
|
if (Character.digit(name.charAt(index), 10) != -1) {
|
||||||
|
buf.append(name.charAt(index));
|
||||||
|
if ((length - (index + 1)) == 2) {
|
||||||
|
buf.append(':');
|
||||||
|
}
|
||||||
|
} else if (name.charAt(index) == ':') {
|
||||||
|
buf.append(':');
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.toString().indexOf(":") == -1) {
|
||||||
|
buf.append(':');
|
||||||
|
buf.append("00");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.toString().indexOf(":") == 5) {
|
||||||
|
buf.insert(4, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the specified {@code TimeZone} has the same raw offset as this
|
||||||
|
* {@code TimeZone}.
|
||||||
|
*
|
||||||
|
* @param zone
|
||||||
|
* a {@code TimeZone}.
|
||||||
|
* @return {@code true} when the {@code TimeZone} have the same raw offset, {@code false}
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasSameRules(TTimeZone zone) {
|
||||||
|
if (zone == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getRawOffset() == zone.getRawOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the specified {@code Date} is in the daylight savings time period for
|
||||||
|
* this {@code TimeZone}.
|
||||||
|
*
|
||||||
|
* @param time
|
||||||
|
* a {@code Date}.
|
||||||
|
* @return {@code true} when the {@code Date} is in the daylight savings time period, {@code false}
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
abstract public boolean inDaylightTime(TDate time);
|
||||||
|
|
||||||
|
private static int parseNumber(String string, int offset, int[] position) {
|
||||||
|
int index = offset, length = string.length(), digit, result = 0;
|
||||||
|
while (index < length
|
||||||
|
&& (digit = Character.digit(string.charAt(index), 10)) != -1) {
|
||||||
|
index++;
|
||||||
|
result = result * 10 + digit;
|
||||||
|
}
|
||||||
|
position[0] = index == offset ? -1 : index;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default time zone. If passed {@code null}, then the next
|
||||||
|
* time {@link #getDefault} is called, the default time zone will be
|
||||||
|
* determined. This behavior is slightly different than the canonical
|
||||||
|
* description of this method, but it follows the spirit of it.
|
||||||
|
*
|
||||||
|
* @param timezone
|
||||||
|
* a {@code TimeZone} object.
|
||||||
|
*/
|
||||||
|
public static void setDefault(TTimeZone timezone) {
|
||||||
|
Default = timezone != null ? (TTimeZone)timezone.clone() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID of this {@code TimeZone}.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* a string which is the time zone ID.
|
||||||
|
*/
|
||||||
|
public void setID(String name) {
|
||||||
|
if (name == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
ID = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the offset for standard time from GMT for this {@code TimeZone}.
|
||||||
|
*
|
||||||
|
* @param offset
|
||||||
|
* the offset from GMT in milliseconds.
|
||||||
|
*/
|
||||||
|
abstract public void setRawOffset(int offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this {@code TimeZone} has a daylight savings time period.
|
||||||
|
*
|
||||||
|
* @return {@code true} if this {@code TimeZone} has a daylight savings time period, {@code false}
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
abstract public boolean useDaylightTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name and the details of the user-selected TimeZone on the
|
||||||
|
* device.
|
||||||
|
*
|
||||||
|
* @param tzinfo
|
||||||
|
* int array of 10 elements to be filled with the TimeZone
|
||||||
|
* information. Once filled, the contents of the array are
|
||||||
|
* formatted as follows: tzinfo[0] -> the timezone offset;
|
||||||
|
* tzinfo[1] -> the dst adjustment; tzinfo[2] -> the dst start
|
||||||
|
* hour; tzinfo[3] -> the dst start day of week; tzinfo[4] -> the
|
||||||
|
* dst start week of month; tzinfo[5] -> the dst start month;
|
||||||
|
* tzinfo[6] -> the dst end hour; tzinfo[7] -> the dst end day of
|
||||||
|
* week; tzinfo[8] -> the dst end week of month; tzinfo[9] -> the
|
||||||
|
* dst end month;
|
||||||
|
* @param isCustomTimeZone
|
||||||
|
* boolean array of size 1 that indicates if a timezone match is
|
||||||
|
* found
|
||||||
|
* @return the name of the TimeZone or null if error occurs in native
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
private static native String getCustomTimeZone(int[] tzinfo,
|
||||||
|
boolean[] isCustomTimeZone);
|
||||||
|
}
|
|
@ -1,21 +1,136 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotSame;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.teavm.classlib.impl.tz.DateTimeZone;
|
|
||||||
import org.teavm.classlib.impl.tz.DateTimeZoneProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class TimeZoneTest {
|
public class TimeZoneTest {
|
||||||
|
private static final int ONE_HOUR = 3600000;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resourceProvided() {
|
public void test_getDefault() {
|
||||||
DateTimeZone tz = DateTimeZoneProvider.getTimeZone("Europe/Moscow");
|
assertNotSame("returns identical", TimeZone.getDefault(), TimeZone.getDefault());
|
||||||
assertEquals(1414274399999L, tz.previousTransition(1431781727159L));
|
}
|
||||||
assertEquals(1301183999999L, tz.previousTransition(1414274399999L));
|
|
||||||
assertEquals(1288479599999L, tz.previousTransition(1301183999999L));
|
@Test
|
||||||
System.out.println(DateTimeZoneProvider.detectTimezone().getID());
|
public void test_getOffset_long() {
|
||||||
|
// Test for method int java.util.TimeZone.getOffset(long time)
|
||||||
|
|
||||||
|
// test on subclass SimpleTimeZone
|
||||||
|
TimeZone st1 = TimeZone.getTimeZone("EST");
|
||||||
|
long time1 = new GregorianCalendar(1998, Calendar.NOVEMBER, 11).getTimeInMillis();
|
||||||
|
assertEquals("T1. Incorrect offset returned", -(5 * ONE_HOUR), st1.getOffset(time1));
|
||||||
|
|
||||||
|
long time2 = new GregorianCalendar(1998, Calendar.JUNE, 11).getTimeInMillis();
|
||||||
|
st1 = TimeZone.getTimeZone("EST");
|
||||||
|
assertEquals("T2. Incorrect offset returned", -(5 * ONE_HOUR), st1.getOffset(time2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getTimeZoneLjava_lang_String() {
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone id SMT-8.", "GMT", TimeZone.getTimeZone("SMT-8")
|
||||||
|
.getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+28:70.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+28:70").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+28:30.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+28:30").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+8:70.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+8:70").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+3:.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+3:").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+3:0.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+3:0").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+2360.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+2360").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+892.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+892").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+082.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+082").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+28.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+28").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT+30.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT+30").getID());
|
||||||
|
assertEquals("Must return GMT when given TimeZone GMT.", "GMT", TimeZone.getTimeZone("GMT").getID());
|
||||||
|
assertEquals("Must return GMT when given TimeZone GMT+.", "GMT", TimeZone.getTimeZone("GMT+").getID());
|
||||||
|
assertEquals("Must return GMT when given TimeZone GMT-.", "GMT", TimeZone.getTimeZone("GMT-").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT-8.45.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT-8.45").getID());
|
||||||
|
assertEquals("Must return GMT when given an invalid TimeZone time GMT-123:23.", "GMT",
|
||||||
|
TimeZone.getTimeZone("GMT-123:23").getID());
|
||||||
|
assertEquals("Must return proper GMT formatted string for GMT+8:30 (eg. GMT+08:20).", "GMT+08:30", TimeZone
|
||||||
|
.getTimeZone("GMT+8:30").getID());
|
||||||
|
assertEquals("Must return proper GMT formatted string for GMT+3 (eg. GMT+08:20).", "GMT+03:00", TimeZone
|
||||||
|
.getTimeZone("GMT+3").getID());
|
||||||
|
assertEquals("Must return proper GMT formatted string for GMT+3:02 (eg. GMT+08:20).", "GMT+03:02", TimeZone
|
||||||
|
.getTimeZone("GMT+3:02").getID());
|
||||||
|
assertEquals("Must return proper GMT formatted string for GMT+2359 (eg. GMT+08:20).", "GMT+23:59", TimeZone
|
||||||
|
.getTimeZone("GMT+2359").getID());
|
||||||
|
assertEquals("Must return proper GMT formatted string for GMT+520 (eg. GMT+08:20).", "GMT+05:20", TimeZone
|
||||||
|
.getTimeZone("GMT+520").getID());
|
||||||
|
assertEquals("Must return proper GMT formatted string for GMT+052 (eg. GMT+08:20).", "GMT+00:52", TimeZone
|
||||||
|
.getTimeZone("GMT+052").getID());
|
||||||
|
// GMT-0 is an available ID in ICU, so replace it with GMT-00
|
||||||
|
assertEquals("Must return proper GMT formatted string for GMT-00 (eg. GMT+08:20).", "GMT-00:00", TimeZone
|
||||||
|
.getTimeZone("GMT-00").getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getDisplayNameLjava_util_Locale() {
|
||||||
|
TimeZone timezone = TimeZone.getTimeZone("Asia/Shanghai");
|
||||||
|
assertEquals("\u4e2d\u56fd\u6807\u51c6\u65f6\u95f4", timezone.getDisplayName(Locale.CHINA));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_GetTimezoneOffset() {
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("America/Toronto");
|
||||||
|
Date date = new GregorianCalendar(2006, 2, 24).getTime();
|
||||||
|
assertEquals(-300 * 60_000, tz.getOffset(date.getTime()));
|
||||||
|
date = new GregorianCalendar(1999, 8, 1).getTime();
|
||||||
|
assertEquals(-240 * 60_000, tz.getOffset(date.getTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getDisplayName() {
|
||||||
|
TimeZone defaultZone = TimeZone.getDefault();
|
||||||
|
Locale defaulLocal = Locale.getDefault();
|
||||||
|
String defaultName = defaultZone.getDisplayName();
|
||||||
|
String expectedName = defaultZone.getDisplayName(defaulLocal);
|
||||||
|
assertEquals("getDispalyName() did not return the default Locale suitable name", expectedName, defaultName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getDisplayName_ZI() {
|
||||||
|
TimeZone defaultZone = TimeZone.getDefault();
|
||||||
|
Locale defaultLocale = Locale.getDefault();
|
||||||
|
String actualName = defaultZone.getDisplayName(false, TimeZone.LONG);
|
||||||
|
String expectedName = defaultZone.getDisplayName(false, TimeZone.LONG, defaultLocale);
|
||||||
|
assertEquals("getDisplayName(daylight,style) did not return the default locale suitable name", expectedName,
|
||||||
|
actualName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user