Lamma I/O

Heads up! These docs are for v1.1.3, which is no longer officially supported. Check out the latest version of Lamma!

Tutorial 2: Advanced Sequence Generation

All code used in this tutorial can be found here: Scala / Java

Some of the below problems might occur to you after Tutorial 1: Basic Sequence Generation:

  • You need to manually adjust start date (or end date for backward patterns).
    For example, if we want to generate something like all Fridays for the next 3 months starting from today, then we will have to first figure out the first Friday (if not today), and then use that Friday as from date.
  • Not able to handle irregular recurring pattern. For example, if we want to generate last Monday of every month:
    • Months(1) cannot be used because not every month's last Monday are on the same day of month
    • Weeks(4) cannot be used because some months have 5 Mondays

To solve all the above, Lamma introduces a new concept called positioning. Weekly position Weekday can be applied to Weeks / WeeksBackward, monthly position PositionOfMonth can be applied to Months / MonthsBackward, and yearly position PositionOfYear can be applied to Years / YearsBackward recurrence patterns.

Following examples are demos of how to use the positioning concept to overcome these limitations.


Generate a date sequence of a specific day of a week within a certain period

Generate dates on Tuesday for every third week from 2014-05-10 to 2014-07-01

Lamma.sequence(Date(2014, 5, 10), Date(2014, 7, 1), Weeks(3, Tuesday))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 5, 10), date(2014, 7, 1), weeks(3, TUESDAY));

Result: Lamma will position the first specified Tuesday first, and then recur for every 3 weeks.

List(2014-05-13, 2014-06-03, 2014-06-24)


Generate a date sequence on the nth day of a month

Generate the tenth day of every month from 2014-05-01 to 2014-07-30

Lamma.sequence(Date(2014, 5, 1), Date(2014, 7, 30), Months(1, NthDayOfMonth(10)))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 5, 1), date(2014, 7, 30), months(1, nthDayOfMonth(10)));

Result: Lamma will first position the 10th of May first, and then recur every month.

List(2014-05-10, 2014-06-10, 2014-07-10)


Generate a date sequence on the nth weekday of a month

Generate every second Friday of every two moths from 2014-05-01 to 2014-09-30

Lamma.sequence(Date(2014, 5, 1), Date(2014, 9, 30), Months(2, NthWeekdayOfMonth(2, Friday)))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 5, 1), date(2014, 9, 30), months(2, nthWeekdayOfMonth(2, FRIDAY)));

Result: Lamma will position the first Second Friday of the Month on or after the starting date (in this case, May), then recur every two months.

List(2014-05-09, 2014-07-11, 2014-09-12)


Generate a date sequence by position of year

Generate the last Tuesday of each year from 2014-01-01 to 2016-12-31

Lamma.sequence(Date(2014, 1, 1), Date(2016, 12, 31), Years(1, LastWeekdayOfYear(Tuesday)))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 1, 1), date(2016, 12, 31), years(1, lastWeekdayOfYear(TUESDAY)));

Result: Lamma will position the next last Tuesday of the year and then recur every one year.

List(2014-12-30, 2015-12-29, 2016-12-27)


A more complicated example combining things together

Generate all the third Friday of February for every 3 years in 2010s

Lamma.sequence(Date(2010, 1, 1), Date(2019, 12, 31), Years(3, NthMonthOfYear(February, NthWeekdayOfMonth(3, Friday))))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2010, 1, 1), date(2019, 12, 31), years(3, nthMonthOfYear(FEBRUARY, nthWeekdayOfMonth(3, FRIDAY))));

Result: Again, Lamma will automatically find the first occurrence of the third Friday of Feb, and then recur every 3 years

List(2010-02-19, 2013-02-15, 2016-02-19, 2019-02-15)


Customize PositionOfMonth and PositionOfYear

By implementing io.lamma.PositionOfMonth or io.lamma.PositionOfYear, one can easily customize the positioning behavior.


A sample of customised PositionOfMonth

Generate a sequence containing the first day in February and the third day for other months from 2014-01-01 to 2014-03-30

case object MyPositionOfMonth extends PositionOfMonth {
  override def isValidDOM(d: Date) = {
    if (d.month == February) {
      d.dd == 1
    } else {
      d.dd == 3
    }
  }
}

Lamma.sequence(Date(2014, 1, 1), Date(2014, 3, 31), Months(1, MyPositionOfMonth))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

class MyPositionOfMonth implements PositionOfMonth {
    @Override
    public boolean isValidDOM(Date d) {
        return d.month() == FEBRUARY ? d.dd() == 1 : d.dd() == 3;
    }
}

Lamma4j.sequence(date(2014, 1, 1), date(2014, 3, 31), months(1, new MyPositionOfMonth()));

Result: Customised PositionOfMonth is now used to position different recurring dates of different months.

List(2014-01-03, 2014-02-01, 2014-03-03)


Shifting and Selecting generated result

You can further shift and select dates based on the generated results.


Generate a list of dates and then shift by calendar days

Select the third last day of each month from January to March 2014

Lamma.sequence(Date(2014, 1, 1), Date(2014, 3, 31), Months(1, LastDayOfMonth), ShiftCalendarDays(-2))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 1, 1), date(2014, 3, 31), months(1, lastDayOfMonth()), shiftCalendarDays(-2));

Result: last dates of each month will first be generated by Months(1, LastDayOfMonth), and then each of them will be shifted by -2 days

List(2014-01-29, 2014-02-26, 2014-03-29)


Shift by working days example

Generate the second last working day before the end of each month from January to March 2014

Lamma.sequence(Date(2014, 1, 1), Date(2014, 3, 31), Months(1, LastDayOfMonth), ShiftWorkingDays(-2, WeekendCalendar))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 1, 1), date(2014, 3, 31), months(1, lastDayOfMonth()), shiftWorkingDays(-2, weekendCalendar()));

Result: last dates of each month will first be generated by Months(1, LastDayOfMonth), then each of them will be shifted by -2 working days. Note the last date generated here is different from the previous example.

List(2014-01-29, 2014-02-26, 2014-03-27)


Select shifted dates

Generate the third last day of each month from January to March 2014 and then select with Forward convention

Lamma.sequence(Date(2014, 1, 1), Date(2014, 3, 31), Months(1, LastDayOfMonth), ShiftCalendarDays(-2), Forward(WeekendCalendar))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 1, 1), date(2014, 3, 31), months(1, lastDayOfMonth()), shiftCalendarDays(-2), forward(weekendCalendar()));

Result: dates are generated and shifted as previous examples, and then Forward convention will be applied to make sure the result dates are working days. Note the last date is different from previous two examples.

List(2014-01-29, 2014-02-26, 2014-03-31)


Edge cases on sequence generation


Very long recurring period for forward generation pattern

Generate dates from 2014-01-01 to 2014-03-31 for every 6 months

Lamma.sequence(Date(2014, 1, 1), Date(2014, 3, 31), Months(6))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 1, 1), date(2014, 3, 31), months(6));

Result: The first recurrence day 2014-07-01 is already after to date, in this case only from date is returned.

List(2014-01-01)


Very long recurring period for backward generation pattern

Generate dates from 2014-03-31 to 2014-01-01 for every 6 months in backward direction

Lamma.sequence(Date(2014, 1, 1), Date(2014, 3, 31), MonthsBackward(6))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 1, 1), date(2014, 3, 31), monthsBackward(6));

Result: The first recurrence day 2013-09-31 is already before from date, so in this case only to date is returned.

List(2014-03-31)


From date equals to To date

Generate dates from 2014-01-01 to 2014-01-01 for every 6 months

Lamma.sequence(Date(2014, 1, 1), Date(2014, 1, 1), MonthsBackward(6))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 1, 1), date(2014, 1, 1), months(6));

Result: Simply return a single date list

List(2014-01-01)


From date is after to date

Generate every day from 2014-01-01 to 2013-12-31 in forward direction

Lamma.sequence(Date(2014, 1, 1), Date(2013, 12, 31))
// always import these two lines when using Java, this will make our life a lot easier
import static io.lamma.LammaConversion.*;
import static io.lamma.LammaConst.*;

Lamma4j.sequence(date(2014, 1, 1), date(2013, 12, 31));

Result: An exception will be thrown.

IllegalArgumentException: from date Date(2014, 1, 1) must be on or before to date Date(2013, 12, 31)