diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormatElement.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormatElement.java index 0df9d256f..9f882fd6c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormatElement.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormatElement.java @@ -16,6 +16,7 @@ package org.teavm.classlib.java.text; import org.teavm.classlib.java.util.TCalendar; +import org.teavm.classlib.java.util.TGregorianCalendar; /** * @@ -157,4 +158,122 @@ abstract class DateFormatElement { } } } + + public static class Numeric extends DateFormatElement { + private int field; + private int length; + private int offset; + + public Numeric(int field, int length, int offset) { + this.field = field; + this.length = length; + this.offset = offset; + } + + @Override + public void format(TCalendar date, StringBuffer buffer) { + int number = date.get(field) + offset; + String str = Integer.toString(number); + for (int i = str.length(); i < length; ++i) { + buffer.append('0'); + } + buffer.append(str); + } + + @Override + public void parse(String text, TCalendar date, TParsePosition position) { + int num = 0; + int i = 0; + int pos = position.getIndex(); + while (position.getIndex() < text.length() && i < length) { + char c = text.charAt(pos); + if (c >= '0' && c <= '9') { + num = num * 10 + (c - '0'); + ++pos; + ++i; + } else { + break; + } + } + if (i == 0) { + position.setErrorIndex(position.getIndex()); + return; + } + position.setIndex(pos); + date.set(field, num - offset); + } + } + + public static class Year extends DateFormatElement { + private int field; + + public Year(int field) { + this.field = field; + } + + @Override + public void format(TCalendar date, StringBuffer buffer) { + int number = date.get(field); + if (number < 10) { + buffer.append(number); + } else { + buffer.append((char)((number % 100 / 10) + '0')); + buffer.append((char)((number % 10) + '0')); + } + } + + @Override + public void parse(String text, TCalendar date, TParsePosition position) { + int num = 0; + int pos = position.getIndex(); + char c = text.charAt(pos++); + if (c < '0' || c > '9') { + position.setErrorIndex(position.getErrorIndex()); + return; + } + num = c - '0'; + c = text.charAt(pos); + if (c >= '0' && c <= '9') { + num = num * 10 + (c - '0'); + ++pos; + } + position.setIndex(pos); + TCalendar calendar = new TGregorianCalendar(); + int currentYear = calendar.get(TCalendar.YEAR); + int currentShortYear = currentYear % 100; + int century = currentYear / 100; + if (currentShortYear > 80) { + if (num < currentShortYear - 80) { + century++; + } + } else { + if (num > currentShortYear + 20) { + --century; + } + } + date.set(field, num + century * 100); + } + } + + public static class ConstantText extends DateFormatElement { + private String textConstant; + + public ConstantText(String textConstant) { + this.textConstant = textConstant; + } + + @Override + public void format(TCalendar date, StringBuffer buffer) { + buffer.append(textConstant); + } + + @Override + public void parse(String text, TCalendar date, TParsePosition position) { + if (matches(text, position.getIndex(), textConstant)) { + position.setIndex(position.getIndex() + textConstant.length()); + } else { + position.setErrorIndex(position.getIndex()); + } + } + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/SimpleDatePatternParser.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/SimpleDatePatternParser.java new file mode 100644 index 000000000..00cabbb9a --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/SimpleDatePatternParser.java @@ -0,0 +1,120 @@ +/* + * 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.text; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Alexey Andreev + */ +class SimpleDatePatternParser { + private TDateFormatSymbols symbols; + private List elements = new ArrayList<>(); + private int index; + private String pattern; + + public SimpleDatePatternParser(TDateFormatSymbols symbols) { + this.symbols = symbols; + } + + public void parsePattern(String pattern) { + this.pattern = pattern; + for (index = 0; index < pattern.length(); ++index) { + char c = pattern.charAt(index); + switch (c) { + case '\'': { + ++index; + parseQuoted(); + break; + } + case 'G': + parseRepetitions(); + elements.add(new DateFormatElement.EraText(symbols)); + break; + case 'y': + break; + default: { + StringBuilder sb = new StringBuilder(); + while (index < pattern.length() && isControl(pattern.charAt(index))) { + sb.append(pattern.charAt(index++)); + } + break; + } + } + } + } + + private boolean isControl(char c) { + switch (c) { + case '\'': + case 'G': + case 'y': + case 'Y': + case 'M': + case 'w': + case 'W': + case 'D': + case 'd': + case 'F': + case 'E': + case 'u': + case 'a': + case 'H': + case 'k': + case 'K': + case 'h': + case 'm': + case 's': + case 'S': + case 'z': + case 'Z': + case 'X': + return true; + default: + return false; + } + } + + private void parseQuoted() { + StringBuilder sb = new StringBuilder(); + while (index < pattern.length()) { + char c = pattern.charAt(index++); + if (c == '\'') { + if (index < pattern.length() && pattern.charAt(index) == '\'') { + sb.append('\''); + ++index; + } else { + break; + } + } else { + sb.append(c); + } + } + elements.add(new DateFormatElement.ConstantText(sb.toString())); + } + + private int parseRepetitions() { + int count = 1; + char orig = pattern.charAt(index++); + while (index < pattern.length() && pattern.charAt(index) == orig) { + ++index; + ++count; + } + return count; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TSimpleDateFormat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TSimpleDateFormat.java new file mode 100644 index 000000000..7854dde11 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TSimpleDateFormat.java @@ -0,0 +1,55 @@ +/* + * 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.text; + +import org.teavm.classlib.java.util.TCalendar; +import org.teavm.classlib.java.util.TDate; +import org.teavm.classlib.java.util.TGregorianCalendar; + +/** + * + * @author Alexey Andreev + */ +public class TSimpleDateFormat extends TDateFormat { + private DateFormatElement[] elements; + + @Override + public StringBuffer format(TDate date, StringBuffer buffer, TFieldPosition field) { + TCalendar calendar = new TGregorianCalendar(); + calendar.setTime(date); + for (DateFormatElement element : elements) { + element.format(calendar, buffer); + } + return buffer; + } + + @Override + public TDate parse(String string, TParsePosition position) { + TCalendar calendar = new TGregorianCalendar(); + calendar.set(0, 0, 0, 0, 0, 0); + for (DateFormatElement element : elements) { + if (position.getIndex() > string.length()) { + position.setErrorIndex(position.getErrorIndex()); + return null; + } + element.parse(string, calendar, position); + if (position.getErrorIndex() >= 0) { + return null; + } + } + return calendar.getTime(); + } +}