Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c16e3c063 | ||
|
|
e497b7e929 | ||
|
|
61b90d4489 | ||
|
|
29a9411b9c | ||
|
|
1d7eadf2c7 | ||
|
|
515a632251 | ||
|
|
ccfedec8a6 |
+1
-1
@@ -1,7 +1,7 @@
|
||||
apply plugin:'java'
|
||||
apply plugin: 'maven'
|
||||
defaultTasks 'build'
|
||||
version='1.9.1'
|
||||
version='1.10.0'
|
||||
description='Java implementation of the ISO 8583 protocol, focused on making the creation, edition and reading of ISO8583 messages as simple and flexible as possible.'
|
||||
sourceCompatibility=6
|
||||
targetCompatibility=6
|
||||
|
||||
@@ -19,7 +19,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
package com.solab.iso8583;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/** Defines the possible values types that can be used in the fields.
|
||||
* Some types required the length of the value to be specified (NUMERIC
|
||||
@@ -76,17 +78,23 @@ public enum IsoType {
|
||||
|
||||
/** Formats a Date if the receiver is DATE10, DATE4, DATE_EXP or TIME; throws an exception
|
||||
* otherwise. */
|
||||
public String format(Date value) {
|
||||
public String format(final Date value, final TimeZone tz) {
|
||||
final SimpleDateFormat sdf;
|
||||
if (this == DATE10) {
|
||||
return String.format("%Tm%<Td%<TH%<TM%<TS", value);
|
||||
sdf = new SimpleDateFormat("MMddHHmmss");
|
||||
} else if (this == DATE4) {
|
||||
return String.format("%Tm%<Td", value);
|
||||
sdf = new SimpleDateFormat("MMdd");
|
||||
} else if (this == DATE_EXP) {
|
||||
return String.format("%Ty%<Tm", value);
|
||||
sdf = new SimpleDateFormat("yyMM");
|
||||
} else if (this == TIME) {
|
||||
return String.format("%TH%<TM%<TS", value);
|
||||
}
|
||||
throw new IllegalArgumentException("Cannot format date as " + this);
|
||||
sdf = new SimpleDateFormat("HHmmss");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot format date as " + this);
|
||||
}
|
||||
if (tz != null) {
|
||||
sdf.setTimeZone(tz);
|
||||
}
|
||||
return sdf.format(value);
|
||||
}
|
||||
|
||||
/** Formats the string to the given length (length is only useful if type is ALPHA, NUMERIC or BINARY). */
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import com.solab.iso8583.util.Bcd;
|
||||
import com.solab.iso8583.util.HexCodec;
|
||||
@@ -42,6 +43,7 @@ public class IsoValue<T> implements Cloneable {
|
||||
private CustomField<T> encoder;
|
||||
private int length;
|
||||
private String encoding;
|
||||
private TimeZone tz;
|
||||
|
||||
public IsoValue(IsoType t, T value) {
|
||||
this(t, value, null);
|
||||
@@ -172,6 +174,14 @@ public class IsoValue<T> implements Cloneable {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/** Sets the timezone, useful for date fields. */
|
||||
public void setTimeZone(TimeZone value) {
|
||||
tz = value;
|
||||
}
|
||||
public TimeZone getTimeZone() {
|
||||
return tz;
|
||||
}
|
||||
|
||||
/** Returns the formatted value as a String. The formatting depends on the type of the
|
||||
* receiver. */
|
||||
public String toString() {
|
||||
@@ -195,7 +205,7 @@ public class IsoValue<T> implements Cloneable {
|
||||
} else if (type == IsoType.LLVAR || type == IsoType.LLLVAR) {
|
||||
return encoder == null ? value.toString() : encoder.encodeField(value);
|
||||
} else if (value instanceof Date) {
|
||||
return type.format((Date)value);
|
||||
return type.format((Date)value, tz);
|
||||
} else if (type == IsoType.BINARY) {
|
||||
if (value instanceof byte[]) {
|
||||
final byte[] _v = (byte[])value;
|
||||
|
||||
@@ -21,14 +21,9 @@ package com.solab.iso8583;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import com.solab.iso8583.parse.DateTimeParseInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -275,6 +270,20 @@ public class MessageFactory<T extends IsoMessage> {
|
||||
return resp;
|
||||
}
|
||||
|
||||
/** Sets the timezone for the specified FieldParseInfo, if it's indeed for parsing dates. */
|
||||
public void setTimezoneForParseGuide(int messageType, int field, TimeZone tz) {
|
||||
Map<Integer, FieldParseInfo> guide = parseMap.get(messageType);
|
||||
if (guide != null) {
|
||||
FieldParseInfo fpi = guide.get(field);
|
||||
if (fpi instanceof DateTimeParseInfo) {
|
||||
((DateTimeParseInfo) fpi).setTimeZone(tz);
|
||||
return;
|
||||
}
|
||||
}
|
||||
log.warn("Field {} for message type {} is not for dates, cannot set timezone",
|
||||
field, messageType);
|
||||
}
|
||||
|
||||
/** Creates a new message instance from the buffer, which must contain a valid ISO8583
|
||||
* message. If the factory is set to use binary messages then it will try to parse
|
||||
* a binary message.
|
||||
|
||||
@@ -31,13 +31,8 @@ import com.solab.iso8583.IsoValue;
|
||||
*
|
||||
* @author Enrique Zamudio
|
||||
*/
|
||||
public class Date10ParseInfo extends FieldParseInfo {
|
||||
public class Date10ParseInfo extends DateTimeParseInfo {
|
||||
|
||||
private static final long FUTURE_TOLERANCE;
|
||||
|
||||
static {
|
||||
FUTURE_TOLERANCE = Long.parseLong(System.getProperty("j8583.future.tolerance", "900000"));
|
||||
}
|
||||
public Date10ParseInfo() {
|
||||
super(IsoType.DATE10, 10);
|
||||
}
|
||||
@@ -72,6 +67,9 @@ public class Date10ParseInfo extends FieldParseInfo {
|
||||
cal.set(Calendar.SECOND, ((buf[pos + 8] - 48) * 10) + buf[pos + 9] - 48);
|
||||
}
|
||||
cal.set(Calendar.MILLISECOND,0);
|
||||
if (tz != null) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
adjustWithFutureTolerance(cal);
|
||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
||||
}
|
||||
@@ -103,17 +101,11 @@ public class Date10ParseInfo extends FieldParseInfo {
|
||||
cal.set(Calendar.MINUTE, tens[3]);
|
||||
cal.set(Calendar.SECOND, tens[4]);
|
||||
cal.set(Calendar.MILLISECOND,0);
|
||||
if (tz != null) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
adjustWithFutureTolerance(cal);
|
||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
||||
}
|
||||
|
||||
public static void adjustWithFutureTolerance(Calendar cal) {
|
||||
//We need to handle a small tolerance into the future (a couple of minutes)
|
||||
long now = System.currentTimeMillis();
|
||||
long then = cal.getTimeInMillis();
|
||||
if (then > now && then-now > FUTURE_TOLERANCE) {
|
||||
cal.add(Calendar.YEAR, -1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.solab.iso8583.IsoValue;
|
||||
*
|
||||
* @author Enrique Zamudio
|
||||
*/
|
||||
public class Date4ParseInfo extends FieldParseInfo {
|
||||
public class Date4ParseInfo extends DateTimeParseInfo {
|
||||
|
||||
public Date4ParseInfo() {
|
||||
super(IsoType.DATE4, 4);
|
||||
@@ -61,6 +61,9 @@ public class Date4ParseInfo extends FieldParseInfo {
|
||||
} else {
|
||||
cal.set(Calendar.MONTH, ((buf[pos] - 48) * 10) + buf[pos + 1] - 49);
|
||||
cal.set(Calendar.DATE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48);
|
||||
}
|
||||
if (tz != null) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
Date10ParseInfo.adjustWithFutureTolerance(cal);
|
||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
||||
@@ -87,7 +90,10 @@ public class Date4ParseInfo extends FieldParseInfo {
|
||||
cal.set(Calendar.MONTH, tens[0] - 1);
|
||||
cal.set(Calendar.DATE, tens[1]);
|
||||
cal.set(Calendar.MILLISECOND,0);
|
||||
Date10ParseInfo.adjustWithFutureTolerance(cal);
|
||||
if (tz != null) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
DateTimeParseInfo.adjustWithFutureTolerance(cal);
|
||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.solab.iso8583.IsoValue;
|
||||
*
|
||||
* @author Enrique Zamudio
|
||||
*/
|
||||
public class DateExpParseInfo extends FieldParseInfo {
|
||||
public class DateExpParseInfo extends DateTimeParseInfo {
|
||||
|
||||
public DateExpParseInfo() {
|
||||
super(IsoType.DATE_EXP, 4);
|
||||
@@ -63,6 +63,9 @@ public class DateExpParseInfo extends FieldParseInfo {
|
||||
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - (cal.get(Calendar.YEAR) % 100)
|
||||
+ ((buf[pos] - 48) * 10) + buf[pos + 1] - 48);
|
||||
cal.set(Calendar.MONTH, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 49);
|
||||
}
|
||||
if (tz != null) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
||||
}
|
||||
@@ -93,6 +96,9 @@ public class DateExpParseInfo extends FieldParseInfo {
|
||||
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR)
|
||||
- (cal.get(Calendar.YEAR) % 100) + tens[0]);
|
||||
cal.set(Calendar.MONTH, tens[1] - 1);
|
||||
if (tz != null) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.solab.iso8583.parse;
|
||||
|
||||
import com.solab.iso8583.IsoType;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Abstract class for date/time parsers.
|
||||
*
|
||||
* @author Enrique Zamudio
|
||||
* Date: 18/12/13 18:21
|
||||
*/
|
||||
public abstract class DateTimeParseInfo extends FieldParseInfo {
|
||||
|
||||
protected static final long FUTURE_TOLERANCE;
|
||||
protected TimeZone tz;
|
||||
|
||||
static {
|
||||
FUTURE_TOLERANCE = Long.parseLong(System.getProperty("j8583.future.tolerance", "900000"));
|
||||
}
|
||||
|
||||
protected DateTimeParseInfo(IsoType type, int length) {
|
||||
super(type, length);
|
||||
}
|
||||
|
||||
public void setTimeZone(TimeZone value) {
|
||||
tz = value;
|
||||
}
|
||||
public TimeZone getTimeZone() {
|
||||
return tz;
|
||||
}
|
||||
|
||||
public static void adjustWithFutureTolerance(Calendar cal) {
|
||||
//We need to handle a small tolerance into the future (a couple of minutes)
|
||||
long now = System.currentTimeMillis();
|
||||
long then = cal.getTimeInMillis();
|
||||
if (then > now && then-now > FUTURE_TOLERANCE) {
|
||||
cal.add(Calendar.YEAR, -1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import com.solab.iso8583.IsoValue;
|
||||
*
|
||||
* @author Enrique Zamudio
|
||||
*/
|
||||
public class TimeParseInfo extends FieldParseInfo {
|
||||
public class TimeParseInfo extends DateTimeParseInfo {
|
||||
|
||||
|
||||
public TimeParseInfo() {
|
||||
@@ -58,6 +58,9 @@ public class TimeParseInfo extends FieldParseInfo {
|
||||
cal.set(Calendar.HOUR_OF_DAY, ((buf[pos] - 48) * 10) + buf[pos + 1] - 48);
|
||||
cal.set(Calendar.MINUTE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48);
|
||||
cal.set(Calendar.SECOND, ((buf[pos + 4] - 48) * 10) + buf[pos + 5] - 48);
|
||||
}
|
||||
if (tz != null) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
||||
}
|
||||
@@ -82,6 +85,9 @@ public class TimeParseInfo extends FieldParseInfo {
|
||||
cal.set(Calendar.HOUR_OF_DAY, tens[0]);
|
||||
cal.set(Calendar.MINUTE, tens[1]);
|
||||
cal.set(Calendar.SECOND, tens[2]);
|
||||
if (tz != null) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ public class TestDates {
|
||||
today.set(GregorianCalendar.MINUTE,0);
|
||||
today.set(GregorianCalendar.SECOND,0);
|
||||
today.set(GregorianCalendar.MILLISECOND,0);
|
||||
byte[] buf = IsoType.DATE4.format(soon).getBytes();
|
||||
byte[] buf = IsoType.DATE4.format(soon, null).getBytes();
|
||||
IsoValue<Date> comp = new Date4ParseInfo().parse(0, buf, 0, null);
|
||||
Assert.assertEquals(comp.getValue(), today.getTime());
|
||||
//Now with the binary
|
||||
@@ -40,7 +40,7 @@ public class TestDates {
|
||||
@Test
|
||||
public void testDate10FutureTolerance() throws ParseException, IOException {
|
||||
Date soon = new Date(System.currentTimeMillis() + 50000);
|
||||
byte[] buf = IsoType.DATE10.format(soon).getBytes();
|
||||
byte[] buf = IsoType.DATE10.format(soon, null).getBytes();
|
||||
IsoValue<Date> comp = new Date10ParseInfo().parse(0, buf, 0, null);
|
||||
assert comp.getValue().after(new Date());
|
||||
//Now with the binary
|
||||
|
||||
@@ -2,7 +2,9 @@ package j8583;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.solab.iso8583.IsoType;
|
||||
@@ -13,14 +15,26 @@ import com.solab.iso8583.IsoType;
|
||||
*/
|
||||
public class TestFormats {
|
||||
|
||||
private Date date = new Date(96867296000l);
|
||||
private final Date date = new Date(96867296000l);
|
||||
|
||||
@Test
|
||||
public void testDateFormats() {
|
||||
assert IsoType.DATE10.format(date).equals("0125213456");
|
||||
assert IsoType.DATE4.format(date).equals("0125");
|
||||
assert IsoType.DATE_EXP.format(date).equals("7301");
|
||||
assert IsoType.TIME.format(date).equals("213456");
|
||||
assert IsoType.DATE10.format(date, null).equals("0125213456");
|
||||
assert IsoType.DATE4.format(date, null).equals("0125");
|
||||
assert IsoType.DATE_EXP.format(date, null).equals("7301");
|
||||
assert IsoType.TIME.format(date, null).equals("213456");
|
||||
//Now with GMT
|
||||
TimeZone gmt = TimeZone.getTimeZone("GMT");
|
||||
Assert.assertEquals("0126033456", IsoType.DATE10.format(date, gmt));
|
||||
Assert.assertEquals("0126", IsoType.DATE4.format(date, gmt));
|
||||
Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, gmt));
|
||||
Assert.assertEquals("033456", IsoType.TIME.format(date, gmt));
|
||||
//And now with GMT+1
|
||||
gmt = TimeZone.getTimeZone("GMT+0100");
|
||||
Assert.assertEquals("0126043456", IsoType.DATE10.format(date, gmt));
|
||||
Assert.assertEquals("0126", IsoType.DATE4.format(date, gmt));
|
||||
Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, gmt));
|
||||
Assert.assertEquals("043456", IsoType.TIME.format(date, gmt));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -3,6 +3,10 @@ package j8583;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import com.solab.iso8583.IsoMessage;
|
||||
import com.solab.iso8583.IsoValue;
|
||||
@@ -120,4 +124,32 @@ public class TestParsing {
|
||||
Assert.assertEquals("12345", f.getObjectValue(2));
|
||||
Assert.assertEquals(".", f.getObjectValue(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDates() throws ParseException, UnsupportedEncodingException {
|
||||
IsoMessage m = mf.parseMessage("060002000000000000000125213456".getBytes(), 0);
|
||||
Assert.assertNotNull(m);
|
||||
Date f = m.getObjectValue(7);
|
||||
Assert.assertNotNull(f);
|
||||
GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTime(f);
|
||||
Assert.assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH));
|
||||
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
||||
Assert.assertEquals(21, cal.get(Calendar.HOUR_OF_DAY));
|
||||
mf.setTimezoneForParseGuide(0x600, 7, TimeZone.getTimeZone("GMT"));
|
||||
m = mf.parseMessage("060002000000000000000125213456".getBytes(), 0);
|
||||
f = m.getObjectValue(7);
|
||||
cal.setTime(f);
|
||||
Assert.assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH));
|
||||
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
||||
Assert.assertEquals(15, cal.get(Calendar.HOUR_OF_DAY));
|
||||
mf.setTimezoneForParseGuide(0x600, 7, TimeZone.getTimeZone("GMT+0100"));
|
||||
m = mf.parseMessage("060002000000000000000125213456".getBytes(), 0);
|
||||
f = m.getObjectValue(7);
|
||||
cal.setTime(f);
|
||||
Assert.assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH));
|
||||
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
||||
Assert.assertEquals(14, cal.get(Calendar.HOUR_OF_DAY));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user