code: private void populateExpandedExceptions()
     {
        if (!m_exceptions.isEmpty() && m_expandedExceptions.isEmpty())
        {
           for (ProjectCalendarException exception : m_exceptions)
           {
              RecurringData recurring = exception.getRecurring();
              if (recurring == null)
              {
                 m_expandedExceptions.add(exception);
              }
              else
              {
                 for (Date date : recurring.getDates())
                 {
                    Date startDate = DateHelper.getDayStartDate(date);
                    Date endDate = DateHelper.getDayEndDate(date);
                    ProjectCalendarException newException = new ProjectCalendarException(startDate, endDate);
                    int rangeCount = exception.getRangeCount();
                    for (int rangeIndex = 0; rangeIndex < rangeCount; rangeIndex++)
                    {
                       newException.addRange(exception.getRange(rangeIndex));
                    }
                    m_expandedExceptions.add(newException);
                 }
              }
           }
           Collections.sort(m_expandedExceptions);
        }
     }
docs: Populate the expanded exceptions list based on the main exceptions list.
  Where we find recurring exception definitions, we generate individual
  exceptions for each recurrence to ensure that we account for them correctly.