From 401d42616342405e8612e6d80a8c7738c4a6daa7 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 19 May 2016 14:02:46 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20date?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- program.own | 10 + src/com/annimon/ownlang/lib/modules/date.java | 304 ++++++++++++++++++ .../ownlang/lib/modules/package-info.java | 1 + tests.own | 40 +++ 4 files changed, 355 insertions(+) create mode 100644 src/com/annimon/ownlang/lib/modules/date.java diff --git a/program.own b/program.own index e0406c4..5d8bb3c 100644 --- a/program.own +++ b/program.own @@ -243,3 +243,13 @@ println 1 :: 2 :: 3 println "\u042a" include "visitor.own" + + +use "date" +d = newDate(); +println d +println formatDate(d) +println formatDate(d, newFormat("yyyy-MM-dd HH:mm:ss, EEEE")) +println parseDate("2016/05/10", newFormat("yyyy/MM/dd")) +println toTimestamp(d) +println newDate(toTimestamp(d) - 100000) \ No newline at end of file diff --git a/src/com/annimon/ownlang/lib/modules/date.java b/src/com/annimon/ownlang/lib/modules/date.java new file mode 100644 index 0000000..0ab1f72 --- /dev/null +++ b/src/com/annimon/ownlang/lib/modules/date.java @@ -0,0 +1,304 @@ +package com.annimon.ownlang.lib.modules; + +import com.annimon.ownlang.exceptions.TypeException; +import com.annimon.ownlang.lib.*; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +/** + * + * @author aNNiMON + */ +public final class date implements Module { + + private static final int DATE_DATE_FORMAT = 9829; + + private static final StringValue + YEAR = new StringValue("year"), + MONTH = new StringValue("month"), + DAY = new StringValue("day"), + HOUR = new StringValue("hour"), + MINUTE = new StringValue("minute"), + SECOND = new StringValue("second"), + MILLISECOND = new StringValue("millisecond"); + + @Override + public void init() { + Variables.set("STYLE_FULL", NumberValue.of(DateFormat.FULL)); + Variables.set("STYLE_LONG", NumberValue.of(DateFormat.LONG)); + Variables.set("STYLE_MEDIUM", NumberValue.of(DateFormat.MEDIUM)); + Variables.set("STYLE_SHORT", NumberValue.of(DateFormat.SHORT)); + + Functions.set("newDate", new date_newDate()); + Functions.set("newFormat", new date_newFormat()); + Functions.set("formatDate", new date_format()); + Functions.set("parseDate", new date_parse()); + Functions.set("toTimestamp", new date_toTimestamp()); + } + + // + private static class DateValue extends MapValue { + + private static DateValue from(Date date) { + final Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + return from(calendar); + } + + private static DateValue from(Calendar calendar) { + final DateValue value = new DateValue(calendar); + value.set(YEAR, NumberValue.of(calendar.get(Calendar.YEAR))); + value.set(MONTH, NumberValue.of(calendar.get(Calendar.MONTH))); + value.set(DAY, NumberValue.of(calendar.get(Calendar.DAY_OF_MONTH))); + value.set(HOUR, NumberValue.of(calendar.get(Calendar.HOUR))); + value.set(MINUTE, NumberValue.of(calendar.get(Calendar.MINUTE))); + value.set(SECOND, NumberValue.of(calendar.get(Calendar.SECOND))); + value.set(MILLISECOND, NumberValue.of(calendar.get(Calendar.MILLISECOND))); + return value; + } + + private final Calendar value; + + private DateValue(Calendar value) { + super(8); + this.value = value; + } + + @Override + public Object raw() { + return value; + } + + @Override + public int asInt() { + throw new TypeException("Cannot cast Date to integer"); + } + + @Override + public double asNumber() { + throw new TypeException("Cannot cast Date to number"); + } + + @Override + public String asString() { + return String.format("%04d-%02d-%02d %02d:%02d:%02d.%03d", + get(YEAR).asInt(), get(MONTH).asInt(), get(DAY).asInt(), + get(HOUR).asInt(), get(MINUTE).asInt(), get(SECOND).asInt(), + get(MILLISECOND).asInt()); + } + + @Override + public int compareTo(Value o) { + if (o.type() == Types.MAP && (o.raw() instanceof Calendar)) { + return value.compareTo((Calendar) o.raw()); + } + return asString().compareTo(o.asString()); + } + } + + private static class DateFormatValue implements Value { + + private final DateFormat value; + + public DateFormatValue(DateFormat value) { + this.value = value; + } + + @Override + public Object raw() { + return value; + } + + @Override + public int asInt() { + throw new TypeException("Cannot cast DateFormat to integer"); + } + + @Override + public double asNumber() { + throw new TypeException("Cannot cast DateFormat to number"); + } + + @Override + public String asString() { + return value.toString(); + } + + @Override + public int type() { + return DATE_DATE_FORMAT; + } + + @Override + public int compareTo(Value o) { + return 0; + } + + @Override + public String toString() { + return "DateFormat " + value.toString(); + } + } +// + + private static class date_newDate implements Function { + + @Override + public Value execute(Value... args) { + final Calendar calendar = Calendar.getInstance(); + calendar.clear(); + switch (args.length) { + case 0: + // date() + calendar.setTimeInMillis(System.currentTimeMillis()); + break; + case 1: + // date(timestamp) + // date("date") + date(calendar, args[0]); + break; + case 2: + // date("pattern", "date") + date(calendar, args[0], args[1]); + break; + case 3: + case 4: + // date(year, month, day) + calendar.set(args[0].asInt(), args[1].asInt(), args[2].asInt()); + break; + case 5: + // date(year, month, day, hour, minute) + calendar.set(args[0].asInt(), args[1].asInt(), args[2].asInt(), + args[3].asInt(), args[4].asInt()); + break; + case 6: + default: + // date(year, month, day, hour, minute, second) + calendar.set(args[0].asInt(), args[1].asInt(), args[2].asInt(), + args[3].asInt(), args[4].asInt(), args[5].asInt()); + break; + } + return DateValue.from(calendar); + } + + private static void date(Calendar calendar, Value arg1) { + if (arg1.type() == Types.NUMBER) { + calendar.setTimeInMillis(((NumberValue) arg1).asLong()); + return; + } + try { + calendar.setTime(DateFormat.getDateTimeInstance().parse(arg1.asString())); + } catch (ParseException ex) { } + } + + private static void date(Calendar calendar, Value arg1, Value arg2) { + if (arg1.type() == Types.NUMBER) { + date(calendar, arg1); + return; + } + try { + calendar.setTime(new SimpleDateFormat(arg1.asString()).parse(arg2.asString())); + } catch (ParseException ex) { } + } + } + + private static class date_newFormat implements Function { + + @Override + public Value execute(Value... args) { + if (args.length == 0) { + return new DateFormatValue(new SimpleDateFormat()); + } + if (args.length == 1) { + if (args[0].type() == Types.STRING) { + return new DateFormatValue(new SimpleDateFormat(args[0].asString())); + } + switch (args[0].asInt()) { + case 0: + return new DateFormatValue(DateFormat.getInstance()); + case 1: + return new DateFormatValue(DateFormat.getDateInstance()); + case 2: + return new DateFormatValue(DateFormat.getTimeInstance()); + case 3: + default: + return new DateFormatValue(DateFormat.getDateTimeInstance()); + } + } + + if (args[0].type() == Types.STRING) { + return new DateFormatValue(new SimpleDateFormat(args[0].asString(), new Locale(args[1].asString()))); + } + switch (args[0].asInt()) { + case 0: + return new DateFormatValue(DateFormat.getInstance()); + case 1: + return new DateFormatValue(DateFormat.getDateInstance(args[1].asInt())); + case 2: + return new DateFormatValue(DateFormat.getTimeInstance(args[1].asInt())); + case 3: + default: + int dateStyle = args[1].asInt(); + int timeStyle = (args.length > 2) ? args[2].asInt() : dateStyle; + return new DateFormatValue(DateFormat.getDateTimeInstance(dateStyle, timeStyle)); + } + } + } + + private static class date_parse implements Function { + + @Override + public Value execute(Value... args) { + Arguments.checkOrOr(1, 2, args.length); + + final DateFormat format; + if (args.length == 1) { + format = new SimpleDateFormat(); + } else { + if (args[1].type() != DATE_DATE_FORMAT) { + throw new TypeException("DateFormat expected, found " + Types.typeToString(args[1].type())); + } + format = (DateFormat) args[1].raw(); + } + + try { + return DateValue.from(format.parse(args[0].asString())); + } catch (ParseException ex) { + throw new RuntimeException(ex); + } + } + } + + private static class date_format implements Function { + + @Override + public Value execute(Value... args) { + Arguments.checkOrOr(1, 2, args.length); + + final DateFormat format; + if (args.length == 1) { + format = new SimpleDateFormat(); + } else { + if (args[1].type() != DATE_DATE_FORMAT) { + throw new TypeException("DateFormat expected, found " + Types.typeToString(args[1].type())); + } + format = (DateFormat) args[1].raw(); + } + + return new StringValue(format.format( ((Calendar) args[0].raw()).getTime() )); + } + } + + private static class date_toTimestamp implements Function { + + @Override + public Value execute(Value... args) { + Arguments.check(1, args.length); + return NumberValue.of(((Calendar) args[0].raw()).getTimeInMillis() ); + } + } +} diff --git a/src/com/annimon/ownlang/lib/modules/package-info.java b/src/com/annimon/ownlang/lib/modules/package-info.java index 3846917..aafa2e5 100644 --- a/src/com/annimon/ownlang/lib/modules/package-info.java +++ b/src/com/annimon/ownlang/lib/modules/package-info.java @@ -1,6 +1,7 @@ @Modules(modules = { canvas.class, canvasfx.class, + date.class, files.class, functional.class, http.class, diff --git a/tests.own b/tests.own index dcf5f73..620ac4c 100644 --- a/tests.own +++ b/tests.own @@ -1,5 +1,6 @@ use "ounit" use "functional" +use "date" def testAdditionOnNumbers() { assertEquals(6, 0 + 1 + 2 + 3) @@ -67,4 +68,43 @@ def testFunctionalChain() { assertEquals([8,6,4,2], result) } +def testDateParse() { + d = parseDate("2016/05/10", newFormat("yyyy/MM/dd")) + assertEquals(2016, d.year) + assertEquals(4, d.month) + assertEquals(10, d.day) + assertEquals(0, d.hour) +} + +// --- Date +def testNewDate() { + d = newDate(2016, 04, 10) + assertEquals(2016, d.year) + assertEquals(4, d.month) + assertEquals(10, d.day) + assertEquals(0, d.hour) + assertEquals(0, d.minute) + assertEquals(0, d.second) + assertEquals(0, d.millisecond) +} + +def testCompareDates() { + assertTrue(newDate(2016, 04, 10) > newDate(2015, 03, 11)) + assertTrue(newDate(2012, 04, 10) < newDate(2015, 03, 11)) + assertTrue(newDate(2015, 03, 11, 0, 0, 0) == newDate(2015, 03, 11)) +} + +def testDateFormat() { + d = formatDate(newDate(2016, 04, 10), newFormat("yyyy/MM/dd HH:mm:ss")) + assertEquals("2016/05/10 00:00:00", d) +} + +def testDateParse() { + d = parseDate("2016/05/10", newFormat("yyyy/MM/dd")) + assertEquals(2016, d.year) + assertEquals(4, d.month) + assertEquals(10, d.day) + assertEquals(0, d.hour) +} + println runTests() \ No newline at end of file