Merge pull request #82 from dscho/dates

Implement date parsing / formatting
This commit is contained in:
Joshua Warner 2013-10-21 09:36:46 -07:00
commit e485a468f0
5 changed files with 207 additions and 0 deletions

View File

@ -0,0 +1,24 @@
/* Copyright (c) 2008-2013, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.text;
public class ParseException extends Exception {
private int errorOffset;
public ParseException(String message, int errorOffset) {
super(message);
this.errorOffset = errorOffset;
}
public int getErrorOffset() {
return errorOffset;
}
}

View File

@ -0,0 +1,39 @@
/* Copyright (c) 2008-2013, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.text;
public class ParsePosition {
private int index, errorIndex = -1;
public ParsePosition(int index) {
this.index = index;
}
public int getErrorIndex() {
return errorIndex;
}
public int getIndex() {
return index;
}
public void setErrorIndex(int i) {
errorIndex = i;
}
public void setIndex(int i) {
index = i;
}
public String toString() {
return "index: " + index + "(error index: " + errorIndex + ")";
}
}

View File

@ -0,0 +1,98 @@
/* Copyright (c) 2008-2013, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.text;
import java.util.Calendar;
import java.util.Date;
public class SimpleDateFormat {
private String pattern;
public SimpleDateFormat(String pattern) {
this.pattern = pattern;
if (! "yyyy-MM-dd'T'HH:mm:ss".equals(pattern)) {
throw new UnsupportedOperationException("Unsupported pattern: " + pattern);
}
}
public StringBuffer format(Date date, StringBuffer buffer, FieldPosition position) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
pad(buffer, calendar.get(Calendar.YEAR), 4);
buffer.append('-');
pad(buffer, calendar.get(Calendar.MONTH) + 1, 2);
buffer.append('-');
pad(buffer, calendar.get(Calendar.DAY_OF_MONTH), 2);
buffer.append("T");
pad(buffer, calendar.get(Calendar.HOUR_OF_DAY), 2);
buffer.append(':');
pad(buffer, calendar.get(Calendar.MINUTE), 2);
buffer.append(':');
pad(buffer, calendar.get(Calendar.SECOND), 2);
return buffer;
}
public Date parse(String text) {
return parse(text, new ParsePosition(0));
}
public Date parse(String text, ParsePosition position) {
int index = position.getIndex();
try {
Calendar calendar = Calendar.getInstance();
index = parseField(text, index, 4, calendar, Calendar.YEAR, 0);
index = expectPrefix(text, index, "-");
index = parseField(text, index, 2, calendar, Calendar.MONTH, -1);
index = expectPrefix(text, index, "-");
index = parseField(text, index, 2, calendar, Calendar.DAY_OF_MONTH, 0);
index = expectPrefix(text, index, "T");
index = parseField(text, index, 2, calendar, Calendar.HOUR_OF_DAY, 0);
index = expectPrefix(text, index, ":");
index = parseField(text, index, 2, calendar, Calendar.MINUTE, 0);
index = expectPrefix(text, index, ":");
index = parseField(text, index, 2, calendar, Calendar.SECOND, 0);
position.setIndex(index);
return calendar.getTime();
} catch (ParseException e) {
position.setErrorIndex(index);
return null;
}
}
private static void pad(StringBuffer buffer, int value, int digits) {
int i = value == 0 ? 1 : value;
while (i > 0) {
i /= 10;
--digits;
}
while (digits-- > 0) {
buffer.append('0');
}
buffer.append(value);
}
private static int parseField(String text, int offset, int length, Calendar calendar, int field, int adjustment) throws ParseException {
if (text.length() < offset + length) throw new ParseException("Short date: " + text, offset);
try {
int value = Integer.parseInt(text.substring(offset, offset + length), 10);
calendar.set(field, value + adjustment);
} catch (NumberFormatException e) {
throw new ParseException("Not a number: " + text, offset);
}
return offset + length;
}
private static int expectPrefix(String text, int offset, String prefix) throws ParseException {
if (text.length() <= offset) throw new ParseException("Short date: " + text, offset);
if (! text.substring(offset).startsWith(prefix)) throw new ParseException("Parse error: " + text, offset);
return offset + prefix.length();
}
}

View File

@ -55,6 +55,10 @@ public abstract class Calendar {
time = date.getTime();
}
public Date getTime() {
return new Date(time);
}
public abstract void roll(int field, boolean up);
public abstract void add(int field, int amount);
@ -102,6 +106,23 @@ public abstract class Calendar {
parseIntoFields(this.time);
}
public Date getTime() {
long days = fields[DAY_OF_MONTH] - 1;
long years = fields[YEAR] - EPOCH_LEAP_YEAR;
days += years * 365 + years / 4 + 1 - DAYS_TO_EPOCH;
for (int month = 0; month < fields[MONTH]; month++) {
days += DAYS_IN_MONTH[0][month];
}
if (fields[MONTH] < 2 && isLeapYear(fields[YEAR])) {
days--;
}
long time = MILLIS_PER_DAY * days
+ MILLIS_PER_HOUR * fields[HOUR_OF_DAY]
+ MILLIS_PER_MINUTE * fields[MINUTE]
+ MILLIS_PER_SECOND * fields[SECOND];
return new Date(time);
}
private static boolean isLeapYear(int year) {
return (year%4 == 0) && (year%100 != 0) || (year%400 == 0);
}

25
test/Dates.java Normal file
View File

@ -0,0 +1,25 @@
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Dates {
private final static long EPOCH = 1234567890;
private final static String TEXT = "2009-02-13T23:31:30";
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
public static void main(String[] args) throws Exception {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date date = format.parse("1970-01-01T00:00:00");
expect(0 == date.getTime());
date = new Date(EPOCH * 1000l);
String actual = format.format(date, new StringBuffer(), new FieldPosition(0)).toString();
expect(TEXT.equals(actual));
date = format.parse(TEXT);
expect(EPOCH == date.getTime() / 1000l);
}
}