Skip to content

Commit ca16635

Browse files
authored
Merge pull request #134 from quickfix-j/weekdays-session-integration
Integrated changes done by Arthur McGibbon @Arthurm1 in #133 into DefaultSessionSchedule
2 parents 39183ce + 37b97fb commit ca16635

File tree

7 files changed

+577
-1036
lines changed

7 files changed

+577
-1036
lines changed

quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java

Lines changed: 109 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -31,38 +31,60 @@
3131
/**
3232
* Corresponds to SessionTime in C++ code
3333
*/
34-
public class DefaultSessionSchedule implements SessionSchedule {
34+
public class DefaultSessionSchedule implements SessionSchedule {
3535
private static final int NOT_SET = -1;
3636
private static final Pattern TIME_PATTERN = Pattern.compile("(\\d{2}):(\\d{2}):(\\d{2})(.*)");
3737
private final TimeEndPoint startTime;
3838
private final TimeEndPoint endTime;
39-
private final boolean nonStopSession;
40-
protected final static Logger log = LoggerFactory.getLogger(DefaultSessionSchedule.class);
39+
private final boolean isNonStopSession;
40+
private final boolean isWeekdaySession;
41+
private final int[] weekdayOffsets;
42+
protected static final Logger LOG = LoggerFactory.getLogger(DefaultSessionSchedule.class);
4143

4244
public DefaultSessionSchedule(SessionSettings settings, SessionID sessionID) throws ConfigError,
4345
FieldConvertError {
4446

45-
nonStopSession = settings.isSetting(sessionID, Session.SETTING_NON_STOP_SESSION) && settings.getBool(sessionID, Session.SETTING_NON_STOP_SESSION);
47+
isNonStopSession = settings.isSetting(sessionID, Session.SETTING_NON_STOP_SESSION) && settings.getBool(sessionID, Session.SETTING_NON_STOP_SESSION);
4648
TimeZone defaultTimeZone = getDefaultTimeZone(settings, sessionID);
47-
if (nonStopSession) {
49+
if (isNonStopSession) {
50+
isWeekdaySession = false;
51+
weekdayOffsets = new int[0];
4852
startTime = endTime = new TimeEndPoint(NOT_SET, 0, 0, 0, defaultTimeZone);
4953
return;
54+
} else {
55+
isWeekdaySession = settings.isSetting(sessionID, Session.SETTING_WEEKDAYS);
5056
}
5157

5258
boolean startDayPresent = settings.isSetting(sessionID, Session.SETTING_START_DAY);
5359
boolean endDayPresent = settings.isSetting(sessionID, Session.SETTING_END_DAY);
5460

55-
if (startDayPresent && !endDayPresent) {
56-
throw new ConfigError("Session " + sessionID + ": StartDay used without EndDay");
57-
}
61+
if (isWeekdaySession) {
62+
if (startDayPresent || endDayPresent )
63+
throw new ConfigError("Session " + sessionID + ": usage of StartDay or EndDay is not compatible with setting " + Session.SETTING_WEEKDAYS);
5864

59-
if (endDayPresent && !startDayPresent) {
60-
throw new ConfigError("Session " + sessionID + ": EndDay used without StartDay");
61-
}
65+
String weekdayNames = settings.getString(sessionID, Session.SETTING_WEEKDAYS);
66+
if (weekdayNames.isEmpty())
67+
throw new ConfigError("Session " + sessionID + ": " + Session.SETTING_WEEKDAYS + " is empty");
68+
69+
String[] weekdayNameArray = weekdayNames.split(",");
70+
weekdayOffsets = new int[weekdayNameArray.length];
71+
for (int i = 0; i < weekdayNameArray.length; i++) {
72+
weekdayOffsets[i] = DayConverter.toInteger(weekdayNameArray[i]);
73+
}
74+
} else {
75+
weekdayOffsets = new int[0];
76+
77+
if (startDayPresent && !endDayPresent) {
78+
throw new ConfigError("Session " + sessionID + ": StartDay used without EndDay");
79+
}
6280

81+
if (endDayPresent && !startDayPresent) {
82+
throw new ConfigError("Session " + sessionID + ": EndDay used without StartDay");
83+
}
84+
}
6385
startTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_START_TIME, Session.SETTING_START_DAY);
6486
endTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_END_TIME, Session.SETTING_END_DAY);
65-
log.info("[" + sessionID + "] " + toString());
87+
LOG.info("[" + sessionID + "] " + toString());
6688
}
6789

6890
private TimeEndPoint getTimeEndPoint(SessionSettings settings, SessionID sessionID,
@@ -75,7 +97,8 @@ private TimeEndPoint getTimeEndPoint(SessionSettings settings, SessionID session
7597
+ settings.getString(sessionID, timeSetting) + "'.");
7698
}
7799

78-
return new TimeEndPoint(getDay(settings, sessionID, daySetting, NOT_SET),
100+
return new TimeEndPoint(
101+
getDay(settings, sessionID, daySetting, NOT_SET),
79102
Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)),
80103
Integer.parseInt(matcher.group(3)), getTimeZone(matcher.group(4), defaultTimeZone));
81104
}
@@ -100,7 +123,7 @@ private TimeZone getTimeZone(String tz, TimeZone defaultZone) {
100123
return "".equals(tz) ? defaultZone : TimeZone.getTimeZone(tz.trim());
101124
}
102125

103-
private class TimeEndPoint {
126+
private static class TimeEndPoint {
104127
private final int weekDay;
105128
private final int hour;
106129
private final int minute;
@@ -117,34 +140,19 @@ public TimeEndPoint(int day, int hour, int minute, int second, TimeZone tz) {
117140
timeInSeconds = timeInSeconds(hour, minute, second);
118141
}
119142

120-
public int getHour() {
143+
int getHour() {
121144
return hour;
122145
}
123146

124-
public int getMinute() {
147+
int getMinute() {
125148
return minute;
126149
}
127150

128-
public int getSecond() {
151+
int getSecond() {
129152
return second;
130153
}
131154

132-
public String toString() {
133-
try {
134-
Calendar calendar = Calendar.getInstance(tz);
135-
calendar.set(Calendar.HOUR_OF_DAY, hour);
136-
calendar.set(Calendar.MINUTE, minute);
137-
calendar.set(Calendar.SECOND, second);
138-
final SimpleDateFormat utc = new SimpleDateFormat("HH:mm:ss");
139-
utc.setTimeZone(TimeZone.getTimeZone("UTC"));
140-
return (isSet(weekDay) ? DayConverter.toString(weekDay) + "," : "")
141-
+ utc.format(calendar.getTime()) + "-" + utc.getTimeZone().getID();
142-
} catch (ConfigError e) {
143-
return "ERROR: " + e;
144-
}
145-
}
146-
147-
public int getDay() {
155+
int getDay() {
148156
return weekDay;
149157
}
150158

@@ -164,11 +172,17 @@ public int hashCode() {
164172
return 0;
165173
}
166174

167-
public TimeZone getTimeZone() {
175+
TimeZone getTimeZone() {
168176
return tz;
169177
}
170178
}
171179

180+
/**
181+
* find the most recent session date/time range on or before t
182+
* if t is in a session then that session will be returned
183+
* @param t specific date/time
184+
* @return relevant session date/time range
185+
*/
172186
private TimeInterval theMostRecentIntervalBefore(Calendar t) {
173187
TimeInterval timeInterval = new TimeInterval();
174188
Calendar intervalStart = timeInterval.getStart();
@@ -187,24 +201,37 @@ private TimeInterval theMostRecentIntervalBefore(Calendar t) {
187201
intervalEnd.set(Calendar.SECOND, endTime.getSecond());
188202
intervalEnd.set(Calendar.MILLISECOND, 0);
189203

190-
if (isSet(startTime.getDay())) {
191-
intervalStart.set(Calendar.DAY_OF_WEEK, startTime.getDay());
192-
if (intervalStart.getTimeInMillis() > t.getTimeInMillis()) {
193-
intervalStart.add(Calendar.WEEK_OF_YEAR, -1);
194-
intervalEnd.add(Calendar.WEEK_OF_YEAR, -1);
204+
if (isWeekdaySession) {
205+
while (intervalStart.getTimeInMillis() > t.getTimeInMillis() ||
206+
!validDayOfWeek(intervalStart)) {
207+
intervalStart.add(Calendar.DAY_OF_WEEK, -1);
208+
intervalEnd.add(Calendar.DAY_OF_WEEK, -1);
195209
}
196-
} else if (intervalStart.getTimeInMillis() > t.getTimeInMillis()) {
197-
intervalStart.add(Calendar.DAY_OF_YEAR, -1);
198-
intervalEnd.add(Calendar.DAY_OF_YEAR, -1);
199-
}
200210

201-
if (isSet(endTime.getDay())) {
202-
intervalEnd.set(Calendar.DAY_OF_WEEK, endTime.getDay());
203211
if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) {
204-
intervalEnd.add(Calendar.WEEK_OF_MONTH, 1);
212+
intervalEnd.add(Calendar.DAY_OF_WEEK, 1);
213+
}
214+
215+
} else {
216+
if (isSet(startTime.getDay())) {
217+
intervalStart.set(Calendar.DAY_OF_WEEK, startTime.getDay());
218+
if (intervalStart.getTimeInMillis() > t.getTimeInMillis()) {
219+
intervalStart.add(Calendar.WEEK_OF_YEAR, -1);
220+
intervalEnd.add(Calendar.WEEK_OF_YEAR, -1);
221+
}
222+
} else if (intervalStart.getTimeInMillis() > t.getTimeInMillis()) {
223+
intervalStart.add(Calendar.DAY_OF_YEAR, -1);
224+
intervalEnd.add(Calendar.DAY_OF_YEAR, -1);
225+
}
226+
227+
if (isSet(endTime.getDay())) {
228+
intervalEnd.set(Calendar.DAY_OF_WEEK, endTime.getDay());
229+
if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) {
230+
intervalEnd.add(Calendar.WEEK_OF_MONTH, 1);
231+
}
232+
} else if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) {
233+
intervalEnd.add(Calendar.DAY_OF_WEEK, 1);
205234
}
206-
} else if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) {
207-
intervalEnd.add(Calendar.DAY_OF_WEEK, 1);
208235
}
209236

210237
return timeInterval;
@@ -214,7 +241,7 @@ private static class TimeInterval {
214241
private final Calendar start = SystemTime.getUtcCalendar();
215242
private final Calendar end = SystemTime.getUtcCalendar();
216243

217-
public boolean isContainingTime(Calendar t) {
244+
boolean isContainingTime(Calendar t) {
218245
return t.compareTo(start) >= 0 && t.compareTo(end) <= 0;
219246
}
220247

@@ -238,17 +265,18 @@ public int hashCode() {
238265
return 0;
239266
}
240267

241-
public Calendar getStart() {
268+
Calendar getStart() {
242269
return start;
243270
}
244271

245-
public Calendar getEnd() {
272+
Calendar getEnd() {
246273
return end;
247274
}
248275
}
249276

277+
@Override
250278
public boolean isSameSession(Calendar time1, Calendar time2) {
251-
if (nonStopSession)
279+
if (isNonStopSession())
252280
return true;
253281
TimeInterval interval1 = theMostRecentIntervalBefore(time1);
254282
if (!interval1.isContainingTime(time1)) {
@@ -258,16 +286,18 @@ public boolean isSameSession(Calendar time1, Calendar time2) {
258286
return interval2.isContainingTime(time2) && interval1.equals(interval2);
259287
}
260288

289+
@Override
261290
public boolean isNonStopSession() {
262-
return nonStopSession;
291+
return isNonStopSession;
263292
}
264293

265294
private boolean isDailySession() {
266295
return !isSet(startTime.getDay()) && !isSet(endTime.getDay());
267296
}
268-
297+
298+
@Override
269299
public boolean isSessionTime() {
270-
if(nonStopSession) {
300+
if(isNonStopSession()) {
271301
return true;
272302
}
273303
Calendar now = SystemTime.getUtcCalendar();
@@ -301,7 +331,16 @@ public String toString() {
301331

302332
private void formatTimeInterval(StringBuilder buf, TimeInterval timeInterval,
303333
SimpleDateFormat timeFormat, boolean local) {
304-
if (!isDailySession()) {
334+
if (isWeekdaySession) {
335+
try {
336+
for (int i = 0; i < weekdayOffsets.length; i++) {
337+
buf.append(DayConverter.toString(weekdayOffsets[i]));
338+
buf.append(", ");
339+
}
340+
} catch (ConfigError ex) {
341+
// this can't happen as these are created using DayConverter.toInteger
342+
}
343+
} else if (!isDailySession()) {
305344
buf.append("weekly, ");
306345
formatDayOfWeek(buf, startTime.getDay());
307346
buf.append(" ");
@@ -349,7 +388,20 @@ private boolean isSet(int value) {
349388
return value != NOT_SET;
350389
}
351390

352-
private int timeInSeconds(int hour, int minute, int second) {
391+
private static int timeInSeconds(int hour, int minute, int second) {
353392
return (hour * 3600) + (minute * 60) + second;
354393
}
394+
395+
/**
396+
* is the startDateTime a valid day based on the permitted days of week
397+
* @param startDateTime time to test
398+
* @return flag indicating if valid
399+
*/
400+
private boolean validDayOfWeek(Calendar startDateTime) {
401+
int dow = startDateTime.get(Calendar.DAY_OF_WEEK);
402+
for (int i = 0; i < weekdayOffsets.length; i++)
403+
if (weekdayOffsets[i] == dow)
404+
return true;
405+
return false;
406+
}
355407
}

quickfixj-core/src/main/java/quickfix/Session.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ public class Session implements Closeable {
148148
public static final String SETTING_END_TIME = "EndTime";
149149

150150
/**
151-
* Session scheduling setting to specify active days of the week when using a WeekdaySessionSchedule.
151+
* Session scheduling setting to specify active days of the week.
152152
*/
153153
public static final String SETTING_WEEKDAYS = "Weekdays";
154154

155155
/**
156156
* Session setting to indicate whether a data dictionary should be used. If
157-
* a data dictionary is not used then message validation is not possble.
157+
* a data dictionary is not used then message validation is not possible.
158158
*/
159159
public static final String SETTING_USE_DATA_DICTIONARY = "UseDataDictionary";
160160

quickfixj-core/src/main/java/quickfix/SessionSchedule.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,21 @@
2626
*/
2727
public interface SessionSchedule {
2828

29+
/**
30+
* Predicate for determining if the two times are in the same session
31+
* @param time1 test time 1
32+
* @param time2 test time 2
33+
* @return return true if in the same session
34+
*/
2935
boolean isSameSession(Calendar time1, Calendar time2);
3036

3137
boolean isNonStopSession();
3238

39+
/**
40+
* Predicate for determining if the session should be active at the current time.
41+
*
42+
* @return true if session should be active, false otherwise.
43+
*/
3344
boolean isSessionTime();
45+
3446
}

0 commit comments

Comments
 (0)