Skip to content

Commit

Permalink
Merge pull request opentelecoms-org#4 from pmoerenhout/master
Browse files Browse the repository at this point in the history
SMPP 3.4 Relative Time Format
  • Loading branch information
dpocock committed Jan 15, 2015
2 parents 1d9d2f8 + b7b47bd commit a2c0c7c
Show file tree
Hide file tree
Showing 3 changed files with 342 additions and 173 deletions.
136 changes: 76 additions & 60 deletions jsmpp/src/main/java/org/jsmpp/util/RelativeTimeFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,71 +20,87 @@
import java.util.TimeZone;

/**
* Relative time formatter is {@link TimeFormatter} implementation referred to
* SMPP Protocol Specification v3.4 point 7.1.1.
*
* @author uudashr
* Relative time formatter is {@link TimeFormatter} implementation referred to SMPP Protocol Specification v3.4 point
* 7.1.1.
*
* @author pmoerenhout
*/
public class RelativeTimeFormatter implements TimeFormatter {
private final TimeZone timezone;

/**
* Time/Date ASCII format for Absolute Time Format is:
*
* YYMMDDhhmmsstnnp (refer for SMPP Protocol Specification v3.4)
*/
private static final String DATE_FORMAT = "{0,number,00}{1,number,00}{2,number,00}{3,number,00}{4,number,00}{5,number,00}000R";

/**
* Construct with default timezone.
*/
public RelativeTimeFormatter() {
this(TimeZone.getDefault());
}

/**
* Construct with specified SMSC timezone.
*
* @param timezone is the SMSC timezone.
*/
public RelativeTimeFormatter(TimeZone timezone) {
this.timezone = timezone;

private static TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");

/**
* Time/Date ASCII format for Relative Time Format is:
*
* YYMMDDhhmmss000R (refer for SMPP Protocol Specification v3.4)
*/
private static final String DATE_FORMAT = "{0,number,00}{1,number,00}{2,number,00}{3,number,00}{4,number,00}{5,number,00}000R";

/**
* Construct
*/
public RelativeTimeFormatter() {
}

/**
* Return the relative time against current (SMSC) datetime.
*
* @param calendar the datetime.
* @return The relative time between the calendar date and the SMSC calendar date.
*/
public String format(Calendar calendar) {
// As the relative period is calculated on epoch (timeInMillis), no TimeZone information is needed
Calendar smscCalendar = Calendar.getInstance();
return format(calendar, smscCalendar);
}

/**
* Return the relative time from the calendar datetime against the SMSC datetime.
*
* @param calendar the date.
* @param smscCalendar the SMSC date.
* @return The relative time between the calendar date and the SMSC calendar date.
*/
public String format(Calendar calendar, Calendar smscCalendar) {
if (calendar == null || smscCalendar == null) {
return null;
}

public String format(Calendar calendar) {
if (calendar == null) {
return null;
}

long relativeTime = calendar.getTimeInMillis()
- calendar.getTimeZone().getOffset(calendar.getTimeInMillis())
+ timezone.getOffset(calendar.getTimeInMillis());

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(relativeTime);
int year = cal.get(Calendar.YEAR) - 2000;
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DAY_OF_MONTH);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);

return format(year, month, day, hour, minute, second);

long diffTimeInMillis = calendar.getTimeInMillis() - smscCalendar.getTimeInMillis();
if (diffTimeInMillis < 0) {
throw new IllegalArgumentException("The requested relative time has already past.");
}

public String format(Date date) {
if (date == null) {
return null;
}
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return format(cal);

// calculate period from epoch, this is not as accurate as Joda-Time Period class or Java 8 Period
Calendar offsetEpoch = Calendar.getInstance(utcTimeZone);
offsetEpoch.setTimeInMillis(diffTimeInMillis);
int years = offsetEpoch.get(Calendar.YEAR) - 1970;
int months = offsetEpoch.get(Calendar.MONTH);
int days = offsetEpoch.get(Calendar.DAY_OF_MONTH) - 1;
int hours = offsetEpoch.get(Calendar.HOUR);
int minutes = offsetEpoch.get(Calendar.MINUTE);
int seconds = offsetEpoch.get(Calendar.SECOND);

if (years >= 100) {
throw new IllegalArgumentException("The requested relative time is more then a century (" + years + " years).");
}

public static final String format(Integer year, Integer month,
Integer day, Integer hour, Integer minute, Integer second) {
Object[] args = new Object[] {year, month, day, hour, minute, second};
return MessageFormat.format(DATE_FORMAT, args);

return format(years, months, days, hours, minutes, seconds);
}

public String format(Date date) {
if (date == null) {
return null;
}
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return format(cal);
}

public static final String format(Integer year, Integer month,
Integer day, Integer hour, Integer minute, Integer second) {
Object[] args = new Object[]{ year, month, day, hour, minute, second };
return MessageFormat.format(DATE_FORMAT, args);
}

}
198 changes: 85 additions & 113 deletions jsmpp/src/test/java/org/jsmpp/util/DateFormatterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,130 +14,102 @@
*/
package org.jsmpp.util;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import static org.testng.Assert.*;

import org.testng.annotations.Test;


/**
* @author uudashr
*
*/
public class DateFormatterTest {

@Test(groups="checkintest")
public void testStaticAbsoluteFormatter() {
String formatted = AbsoluteTimeFormatter.format(07, 12, 26, 11, 37, 03, 8, 45, '+');
assertEquals(formatted, "071226113703845+");
}

@Test(groups="checkintest")
public void testStaticRelativeFormatter() {
String formatted = RelativeTimeFormatter.format(07, 12, 26, 12, 46, 10);
assertEquals(formatted, "071226124610000R");
}

@Test(groups="checkintest")
public void formatNullDate() {
TimeFormatter timeFormatter = new AbsoluteTimeFormatter();
assertNull(timeFormatter.format((Date)null));
assertNull(timeFormatter.format((Calendar)null));

timeFormatter = new RelativeTimeFormatter();
assertNull(timeFormatter.format((Date)null));
assertNull(timeFormatter.format((Calendar)null));
}

@Test(groups="checkintest")
public void validateAbsoluteDate() throws Exception {
String formatted = AbsoluteTimeFormatter.format(07, 12, 26, 11, 37, 03, 8, 45, '+');
StringValidator.validateString(formatted, StringParameter.SCHEDULE_DELIVERY_TIME);
StringValidator.validateString(formatted, StringParameter.VALIDITY_PERIOD);
StringValidator.validateString(formatted, StringParameter.FINAL_DATE);
}

@Test(groups="checkintest")
public void validateRelativeDate() throws Exception {
String formatted = RelativeTimeFormatter.format(07, 12, 26, 12, 46, 10);
StringValidator.validateString(formatted, StringParameter.SCHEDULE_DELIVERY_TIME);
StringValidator.validateString(formatted, StringParameter.VALIDITY_PERIOD);
StringValidator.validateString(formatted, StringParameter.FINAL_DATE);
}

@Test(groups="checkintest")
public void formatAbsoluteDate() {
TimeFormatter timeFormatter = new AbsoluteTimeFormatter();

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY);
date.set(Calendar.YEAR, 2013);
date.set(Calendar.MONTH, Calendar.JANUARY);
date.set(Calendar.DAY_OF_MONTH, 1);
date.set(Calendar.HOUR_OF_DAY, 1);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);

assertEquals(timeFormatter.format(date), "130101010000004+");

date.set(Calendar.MONTH, Calendar.JULY);

// because of daylight saving time, we have a different offset
assertEquals(timeFormatter.format(date), "130701010000008+");
}

@Test(groups="checkintest")
public void formatAbsoluteDateRussia() {
TimeFormatter timeFormatter = new AbsoluteTimeFormatter();

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("Asia/Yekaterinburg"), new Locale("ru", "RU"));
date.set(Calendar.YEAR, 2013);
date.set(Calendar.MONTH, Calendar.JANUARY);
date.set(Calendar.DAY_OF_MONTH, 1);
date.set(Calendar.HOUR_OF_DAY, 1);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);

assertEquals(timeFormatter.format(date), "130101010000024+");

date.set(Calendar.MONTH, Calendar.JULY);

// we have the same offset because of the absent of daylight saving time
assertEquals(timeFormatter.format(date), "130701010000024+");
}

@Test(groups="checkintest",enabled=false) // FIXME - enable again after fixing issues below
public void formatRelativeDate() {
RelativeTimeFormatter timeFormatter = new RelativeTimeFormatter(TimeZone.getTimeZone("America/Denver"));

// at this date neither Denver nor Germany has daylight saving time
GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY);
date.set(Calendar.YEAR, 2013);
date.set(Calendar.MONTH, Calendar.JANUARY);
date.set(Calendar.DAY_OF_MONTH, 1);
date.set(Calendar.HOUR_OF_DAY, 1);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);

assertEquals(timeFormatter.format(date), "130101050000000R"); // FIXME - should be a relative time but looks like an absolute value

// at this date Denver has already daylight saving time but not Germany
date.set(Calendar.MONTH, Calendar.MARCH);
date.set(Calendar.DAY_OF_MONTH, 20);

assertEquals(timeFormatter.format(date), "130320060000000R"); // FIXME - should be a relative time but looks like an absolute value

// at this date Denver and Germany has daylight saving time
date.set(Calendar.MONTH, Calendar.APRIL);
date.set(Calendar.DAY_OF_MONTH, 1);

assertEquals(timeFormatter.format(date), "130401050000000R"); // FIXME - should be a relative time but looks like an absolute value
}

@Test(groups = "checkintest")
public void testStaticAbsoluteFormatter() {
String formatted = AbsoluteTimeFormatter.format(07, 12, 26, 11, 37, 03, 8, 45, '+');
assertEquals(formatted, "071226113703845+");
}

@Test(groups = "checkintest")
public void testStaticRelativeFormatter() {
String formatted = RelativeTimeFormatter.format(07, 12, 26, 12, 46, 10);
assertEquals(formatted, "071226124610000R");
}

@Test(groups = "checkintest")
public void formatNullDate() {
TimeFormatter timeFormatter = new AbsoluteTimeFormatter();
assertNull(timeFormatter.format((Date) null));
assertNull(timeFormatter.format((Calendar) null));

timeFormatter = new RelativeTimeFormatter();
assertNull(timeFormatter.format((Date) null));
assertNull(timeFormatter.format((Calendar) null));
}

@Test(groups = "checkintest")
public void validateAbsoluteDate() throws Exception {
String formatted = AbsoluteTimeFormatter.format(07, 12, 26, 11, 37, 03, 8, 45, '+');
StringValidator.validateString(formatted, StringParameter.SCHEDULE_DELIVERY_TIME);
StringValidator.validateString(formatted, StringParameter.VALIDITY_PERIOD);
StringValidator.validateString(formatted, StringParameter.FINAL_DATE);
}

@Test(groups = "checkintest")
public void validateRelativeDate() throws Exception {
String formatted = RelativeTimeFormatter.format(07, 12, 26, 12, 46, 10);
StringValidator.validateString(formatted, StringParameter.SCHEDULE_DELIVERY_TIME);
StringValidator.validateString(formatted, StringParameter.VALIDITY_PERIOD);
StringValidator.validateString(formatted, StringParameter.FINAL_DATE);
}

@Test(groups = "checkintest")
public void formatAbsoluteDate() {
TimeFormatter timeFormatter = new AbsoluteTimeFormatter();

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY);
date.set(Calendar.YEAR, 2013);
date.set(Calendar.MONTH, Calendar.JANUARY);
date.set(Calendar.DAY_OF_MONTH, 1);
date.set(Calendar.HOUR_OF_DAY, 1);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);

assertEquals(timeFormatter.format(date), "130101010000004+");

date.set(Calendar.MONTH, Calendar.JULY);

// because of daylight saving time, we have a different offset
assertEquals(timeFormatter.format(date), "130701010000008+");
}

@Test(groups = "checkintest")
public void formatAbsoluteDateRussia() {
TimeFormatter timeFormatter = new AbsoluteTimeFormatter();

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("Asia/Yekaterinburg"), new Locale("ru", "RU"));
date.set(Calendar.YEAR, 2013);
date.set(Calendar.MONTH, Calendar.JANUARY);
date.set(Calendar.DAY_OF_MONTH, 1);
date.set(Calendar.HOUR_OF_DAY, 1);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);

assertEquals(timeFormatter.format(date), "130101010000024+");

date.set(Calendar.MONTH, Calendar.JULY);

// we have the same offset because of the absent of daylight saving time
assertEquals(timeFormatter.format(date), "130701010000024+");
}

}
Loading

0 comments on commit a2c0c7c

Please sign in to comment.