From 21d8824045688cc8329737e4eee5b0420b767397 Mon Sep 17 00:00:00 2001 From: Jan Pomahac Date: Mon, 27 Jun 2016 12:57:16 +0200 Subject: [PATCH] added DATE14 --- src/main/java/com/solab/iso8583/IsoType.java | 6 +- src/main/java/com/solab/iso8583/IsoValue.java | 3 +- .../com/solab/iso8583/MessageFactory.java | 4 +- .../solab/iso8583/codecs/CompositeField.java | 2 +- .../solab/iso8583/parse/Date14ParseInfo.java | 98 +++++++++++++++++++ .../solab/iso8583/parse/FieldParseInfo.java | 2 + .../java/com/solab/iso8583/TestFormats.java | 3 + .../com/solab/iso8583/parse/TestDates.java | 13 +++ 8 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/solab/iso8583/parse/Date14ParseInfo.java diff --git a/src/main/java/com/solab/iso8583/IsoType.java b/src/main/java/com/solab/iso8583/IsoType.java index ae6555d..4fc8d18 100644 --- a/src/main/java/com/solab/iso8583/IsoType.java +++ b/src/main/java/com/solab/iso8583/IsoType.java @@ -41,6 +41,8 @@ public enum IsoType { LLVAR(false, 0), /** A variable length alphanumeric value with a 3-digit header length. */ LLLVAR(false, 0), + /** A date in format YYYYMMddHHmmss */ + DATE14(false, 14), /** A date in format MMddHHmmss */ DATE10(false, 10), /** A date in format MMdd */ @@ -82,7 +84,7 @@ public enum IsoType { return length; } - /** Formats a Date if the receiver is DATE10, DATE4, DATE_EXP, DATE12 or TIME; throws an exception + /** Formats a Date if the receiver is DATE10, DATE4, DATE_EXP, DATE12, DATE14 or TIME; throws an exception * otherwise. */ public String format(final Date value, final TimeZone tz) { final SimpleDateFormat sdf; @@ -96,6 +98,8 @@ public enum IsoType { sdf = new SimpleDateFormat("HHmmss"); } else if (this == DATE12) { sdf = new SimpleDateFormat("yyMMddHHmmss"); + } else if (this == DATE14) { + sdf = new SimpleDateFormat("YYYYMMddHHmmss"); } else { throw new IllegalArgumentException("Cannot format date as " + this); } diff --git a/src/main/java/com/solab/iso8583/IsoValue.java b/src/main/java/com/solab/iso8583/IsoValue.java index f74c9cb..c3de47d 100644 --- a/src/main/java/com/solab/iso8583/IsoValue.java +++ b/src/main/java/com/solab/iso8583/IsoValue.java @@ -334,7 +334,8 @@ public class IsoValue implements Cloneable { } else if (type == IsoType.AMOUNT) { buf = new byte[6]; } else if (type == IsoType.DATE10 || type == IsoType.DATE4 || - type == IsoType.DATE_EXP || type == IsoType.TIME || type == IsoType.DATE12) { + type == IsoType.DATE_EXP || type == IsoType.TIME || + type == IsoType.DATE12 || type == IsoType.DATE14) { buf = new byte[length / 2]; } //Encode in BCD if it's one of these types diff --git a/src/main/java/com/solab/iso8583/MessageFactory.java b/src/main/java/com/solab/iso8583/MessageFactory.java index f0c5182..e5ac23a 100644 --- a/src/main/java/com/solab/iso8583/MessageFactory.java +++ b/src/main/java/com/solab/iso8583/MessageFactory.java @@ -446,7 +446,9 @@ public class MessageFactory { m.setField(i, val); if (val != null) { if (val.getType() == IsoType.NUMERIC || val.getType() == IsoType.DATE10 - || val.getType() == IsoType.DATE4 || val.getType() == IsoType.DATE12 + || val.getType() == IsoType.DATE4 + || val.getType() == IsoType.DATE12 + || val.getType() == IsoType.DATE14 || val.getType() == IsoType.DATE_EXP || val.getType() == IsoType.AMOUNT || val.getType() == IsoType.TIME) { diff --git a/src/main/java/com/solab/iso8583/codecs/CompositeField.java b/src/main/java/com/solab/iso8583/codecs/CompositeField.java index 2babf98..bd62253 100644 --- a/src/main/java/com/solab/iso8583/codecs/CompositeField.java +++ b/src/main/java/com/solab/iso8583/codecs/CompositeField.java @@ -87,7 +87,7 @@ public class CompositeField implements CustomBinaryField { if (v.getType() == IsoType.NUMERIC || v.getType() == IsoType.DATE10 || v.getType() == IsoType.DATE4 || v.getType() == IsoType.DATE_EXP || v.getType() == IsoType.AMOUNT || v.getType() == IsoType.TIME - || v.getType() == IsoType.DATE12) { + || v.getType() == IsoType.DATE12 || v.getType() == IsoType.DATE14) { pos += (v.getLength() / 2) + (v.getLength() % 2); } else { pos += v.getLength(); diff --git a/src/main/java/com/solab/iso8583/parse/Date14ParseInfo.java b/src/main/java/com/solab/iso8583/parse/Date14ParseInfo.java new file mode 100644 index 0000000..be81fe1 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/Date14ParseInfo.java @@ -0,0 +1,98 @@ +package com.solab.iso8583.parse; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +import java.io.UnsupportedEncodingException; +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; + +/** + * Blabla. + * + * @author Enrique Zamudio + * Date: 06/01/16 10:52 AM + */ +public class Date14ParseInfo extends DateTimeParseInfo { + + public Date14ParseInfo() { + super(IsoType.DATE14, 14); + } + + @Override + public IsoValue parse(final int field, final byte[] buf, + final int pos, final CustomField custom) + throws ParseException, UnsupportedEncodingException { + if (pos < 0) { + throw new ParseException(String.format("Invalid DATE14 field %d position %d", + field, pos), pos); + } + if (pos+14 > buf.length) { + throw new ParseException(String.format("Insufficient data for DATE14 field %d, pos %d", + field, pos), pos); + } + //A SimpleDateFormat in the case of dates won't help because of the missing data + //we have to use the current date for reference and change what comes in the buffer + Calendar cal = Calendar.getInstance(); + //Set the month in the date + if (forceStringDecoding) { + cal.set(Calendar.YEAR, Integer.parseInt(new String(buf, pos, 4, getCharacterEncoding()), 10)); + cal.set(Calendar.MONTH, Integer.parseInt(new String(buf, pos, 2, getCharacterEncoding()), 10)-1); + cal.set(Calendar.DATE, Integer.parseInt(new String(buf, pos+2, 2, getCharacterEncoding()), 10)); + cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(new String(buf, pos+4, 2, getCharacterEncoding()), 10)); + cal.set(Calendar.MINUTE, Integer.parseInt(new String(buf, pos+6, 2, getCharacterEncoding()), 10)); + cal.set(Calendar.SECOND, Integer.parseInt(new String(buf, pos+8, 2, getCharacterEncoding()), 10)); + } else { + cal.set(Calendar.YEAR, ((buf[pos] - 48) * 1000) + ((buf[pos + 1] - 48) * 100) + ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48); + cal.set(Calendar.MONTH, ((buf[pos+4] - 48) * 10) + buf[pos + 5] - 49); + cal.set(Calendar.DATE, ((buf[pos + 6] - 48) * 10) + buf[pos + 7] - 48); + cal.set(Calendar.HOUR_OF_DAY, ((buf[pos + 8] - 48) * 10) + buf[pos + 9] - 48); + cal.set(Calendar.MINUTE, ((buf[pos + 10] - 48) * 10) + buf[pos + 11] - 48); + cal.set(Calendar.SECOND, ((buf[pos + 12] - 48) * 10) + buf[pos + 13] - 48); + } + cal.set(Calendar.MILLISECOND,0); + if (tz != null) { + cal.setTimeZone(tz); + } + adjustWithFutureTolerance(cal); + return new IsoValue<>(type, cal.getTime(), null); + } + + @Override + public IsoValue parseBinary(final int field, final byte[] buf, + final int pos, final CustomField custom) + throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid DATE14 field %d position %d", + field, pos), pos); + } + if (pos+7 > buf.length) { + throw new ParseException(String.format("Insufficient data for DATE14 field %d, pos %d", + field, pos), pos); + } + int[] tens = new int[7]; + int start = 0; + for (int i = pos; i < pos + tens.length; i++) { + tens[start++] = (((buf[i] & 0xf0) >> 4) * 10) + (buf[i] & 0x0f); + } + Calendar cal = Calendar.getInstance(); + //A SimpleDateFormat in the case of dates won't help because of the missing data + //we have to use the current date for reference and change what comes in the buffer + //Set the month in the date + cal.set(Calendar.YEAR, (tens[0] * 100) + tens[1]); + cal.set(Calendar.MONTH, tens[2] - 1); + cal.set(Calendar.DATE, tens[3]); + cal.set(Calendar.HOUR_OF_DAY, tens[4]); + cal.set(Calendar.MINUTE, tens[5]); + cal.set(Calendar.SECOND, tens[6]); + cal.set(Calendar.MILLISECOND,0); + if (tz != null) { + cal.setTimeZone(tz); + } + adjustWithFutureTolerance(cal); + return new IsoValue<>(type, cal.getTime(), null); + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/FieldParseInfo.java b/src/main/java/com/solab/iso8583/parse/FieldParseInfo.java index bbccf53..cca8b47 100644 --- a/src/main/java/com/solab/iso8583/parse/FieldParseInfo.java +++ b/src/main/java/com/solab/iso8583/parse/FieldParseInfo.java @@ -113,6 +113,8 @@ public abstract class FieldParseInfo { fpi = new Date10ParseInfo(); } else if (t == IsoType.DATE12) { fpi = new Date12ParseInfo(); + } else if (t == IsoType.DATE14) { + fpi = new Date14ParseInfo(); } else if (t == IsoType.DATE4) { fpi = new Date4ParseInfo(); } else if (t == IsoType.DATE_EXP) { diff --git a/src/test/java/com/solab/iso8583/TestFormats.java b/src/test/java/com/solab/iso8583/TestFormats.java index 5248a14..9b21686 100644 --- a/src/test/java/com/solab/iso8583/TestFormats.java +++ b/src/test/java/com/solab/iso8583/TestFormats.java @@ -22,6 +22,7 @@ public class TestFormats { Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, null)); Assert.assertEquals("213456", IsoType.TIME.format(date, null)); Assert.assertEquals("730125213456", IsoType.DATE12.format(date, null)); + Assert.assertEquals("19730125213456", IsoType.DATE14.format(date, null)); //Now with GMT TimeZone gmt = TimeZone.getTimeZone("GMT"); Assert.assertEquals("0126033456", IsoType.DATE10.format(date, gmt)); @@ -29,6 +30,7 @@ public class TestFormats { Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, gmt)); Assert.assertEquals("033456", IsoType.TIME.format(date, gmt)); Assert.assertEquals("730126033456", IsoType.DATE12.format(date, gmt)); + Assert.assertEquals("19730126033456", IsoType.DATE14.format(date, gmt)); //And now with GMT+1 gmt = TimeZone.getTimeZone("GMT+0100"); Assert.assertEquals("0126043456", IsoType.DATE10.format(date, gmt)); @@ -36,6 +38,7 @@ public class TestFormats { Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, gmt)); Assert.assertEquals("043456", IsoType.TIME.format(date, gmt)); Assert.assertEquals("730126043456", IsoType.DATE12.format(date, gmt)); + Assert.assertEquals("19730126043456", IsoType.DATE14.format(date, gmt)); } @Test diff --git a/src/test/java/com/solab/iso8583/parse/TestDates.java b/src/test/java/com/solab/iso8583/parse/TestDates.java index 7269285..cf64d98 100644 --- a/src/test/java/com/solab/iso8583/parse/TestDates.java +++ b/src/test/java/com/solab/iso8583/parse/TestDates.java @@ -61,4 +61,17 @@ public class TestDates { Assert.assertEquals(comp.getValue().getTime(), bin.getValue().getTime()); } + @Test + public void testDate14FutureTolerance() throws ParseException, IOException { + Date soon = new Date(System.currentTimeMillis() + 50000); + byte[] buf = IsoType.DATE14.format(soon, null).getBytes(); + IsoValue comp = new Date14ParseInfo().parse(0, buf, 0, null); + assert comp.getValue().after(new Date()); + //Now with the binary + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + comp.write(bout, true, false); + IsoValue bin = new Date14ParseInfo().parseBinary(0, bout.toByteArray(), 0, null); + Assert.assertEquals(comp.getValue().getTime(), bin.getValue().getTime()); + } + }