This method breaks down spans of time into individual days.

@param calendar current project calendar
@param list list of assignment data
489984
private void splitDays(ProjectCalendar calendar, LinkedList<TimephasedCost> list)
   {
      LinkedList<TimephasedCost> result = new LinkedList<TimephasedCost>();
      boolean remainderInserted = false;

      for (TimephasedCost assignment : list)
      {
         if (remainderInserted)
         {
            assignment.setStart(DateHelper.addDays(assignment.getStart(), 1));
            remainderInserted = false;
         }

         while (assignment != null)
         {
            Date startDay = DateHelper.getDayStartDate(assignment.getStart());
            Date finishDay = DateHelper.getDayStartDate(assignment.getFinish());

            // special case - when the finishday time is midnight, it's really the previous day...
            if (assignment.getFinish().getTime() == finishDay.getTime())
            {
               finishDay = DateHelper.addDays(finishDay, -1);
            }

            if (startDay.getTime() == finishDay.getTime())
            {
               result.add(assignment);
               break;
            }

            TimephasedCost[] split = splitFirstDay(calendar, assignment);
            if (split[0] != null)
            {
               result.add(split[0]);
            }

            if (assignment.equals(split[1]))
            {
               break;
            }

            assignment = split[1];
         }
      }
      
      list.clear();
      list.addAll(result);
   }
127247
private void addCalendarDay(MpxjTreeNode parentNode, ProjectCalendar calendar, final Day day)
   {
      MpxjTreeNode dayNode = new MpxjTreeNode(day)
      {
         @Override public String toString()
         {
            return day.name();
         }
      };
      parentNode.add(dayNode);
      addHours(dayNode, calendar.getHours(day));
   }
186733
private TimephasedWork[] splitFirstDay(ProjectCalendar calendar, TimephasedWork assignment)
   {
      TimephasedWork[] result = new TimephasedWork[2];

      //
      // Retrieve data used to calculate the pro-rata work split
      //
      Date assignmentStart = assignment.getStart();
      Date assignmentFinish = assignment.getFinish();
      Duration calendarWork = calendar.getWork(assignmentStart, assignmentFinish, TimeUnit.MINUTES);
      Duration assignmentWork = assignment.getTotalAmount();

      if (calendarWork.getDuration() != 0)
      {
         //
         // Split the first day
         //
         Date splitFinish;
         double splitMinutes;
         if (calendar.isWorkingDate(assignmentStart))
         {
            Date splitStart = assignmentStart;
            Date splitFinishTime = calendar.getFinishTime(splitStart);
            splitFinish = DateHelper.setTime(splitStart, splitFinishTime);

            Duration calendarSplitWork = calendar.getWork(splitStart, splitFinish, TimeUnit.MINUTES);
            Duration calendarWorkPerDay = calendar.getWork(splitStart, TimeUnit.MINUTES);
            Duration assignmentWorkPerDay = assignment.getAmountPerDay();
            Duration splitWork;

            if (calendarSplitWork.durationComponentEquals(calendarWorkPerDay))
            {
               {
                  if (calendarSplitWork.durationComponentEquals(assignmentWorkPerDay))
                  {
                     splitWork = assignmentWorkPerDay;
                     splitMinutes = splitWork.getDuration();
                  }
                  else
                  {
                     splitMinutes = assignmentWorkPerDay.getDuration();
                     splitMinutes *= calendarSplitWork.getDuration();
                     splitMinutes /= (8 * 60); // this appears to be a fixed value
                     splitWork = Duration.getInstance(splitMinutes, TimeUnit.MINUTES);
                  }
               }
            }
            else
            {
               splitMinutes = assignmentWorkPerDay.getDuration();
               splitMinutes *= calendarSplitWork.getDuration();
               splitMinutes /= (8 * 60); // this appears to be a fixed value
               splitWork = Duration.getInstance(splitMinutes, TimeUnit.MINUTES);
            }

            TimephasedWork split = new TimephasedWork();
            split.setStart(splitStart);
            split.setFinish(splitFinish);
            split.setTotalAmount(splitWork);

            result[0] = split;
         }
         else
         {
            splitFinish = assignmentStart;
            splitMinutes = 0;
         }

         //
         // Split the remainder
         //
         Date splitStart = calendar.getNextWorkStart(splitFinish);
         splitFinish = assignmentFinish;
         TimephasedWork split;
         if (splitStart.getTime() > splitFinish.getTime())
         {
            split = null;
         }
         else
         {
            splitMinutes = assignmentWork.getDuration() - splitMinutes;
            Duration splitWork = Duration.getInstance(splitMinutes, TimeUnit.MINUTES);

            split = new TimephasedWork();
            split.setStart(splitStart);
            split.setFinish(splitFinish);
            split.setTotalAmount(splitWork);
            split.setAmountPerDay(assignment.getAmountPerDay());
         }

         result[1] = split;
      }
      return result;
   }
314613
private void writeCalendar(ProjectCalendar record) throws IOException
   {
      //
      // Test used to ensure that we don't write the default calendar used for the "Unassigned" resource
      //
      if (record.getParent() == null || record.getResource() != null)
      {
         m_buffer.setLength(0);

         if (record.getParent() == null)
         {
            m_buffer.append(MPXConstants.BASE_CALENDAR_RECORD_NUMBER);
            m_buffer.append(m_delimiter);
            if (record.getName() != null)
            {
               m_buffer.append(record.getName());
            }
         }
         else
         {
            m_buffer.append(MPXConstants.RESOURCE_CALENDAR_RECORD_NUMBER);
            m_buffer.append(m_delimiter);
            m_buffer.append(record.getParent().getName());
         }

         for (DayType day : record.getDays())
         {
            if (day == null)
            {
               day = DayType.DEFAULT;
            }
            m_buffer.append(m_delimiter);
            m_buffer.append(day.getValue());
         }

         m_buffer.append(MPXConstants.EOL);
         m_writer.write(m_buffer.toString());

         ProjectCalendarHours[] hours = record.getHours();
         for (int loop = 0; loop < hours.length; loop++)
         {
            if (hours[loop] != null)
            {
               writeCalendarHours(record, hours[loop]);
            }
         }

         if (!record.getCalendarExceptions().isEmpty())
         {
            //
            // A quirk of MS Project is that these exceptions must be
            // in date order in the file, otherwise they are ignored.
            // The getCalendarExceptions method now guarantees that
            // the exceptions list is sorted when retrieved.
            //
            for (ProjectCalendarException ex : record.getCalendarExceptions())
            {
               writeCalendarException(record, ex);
            }
         }

         m_eventManager.fireCalendarWrittenEvent(record);
      }
   }
79377
private void processCalendarDays(ProjectCalendar calendar, Record root)
   {
      // Retrieve working hours ...
      Record daysOfWeek = root.getChild("DaysOfWeek");
      if (daysOfWeek != null)
      {
         for (Record dayRecord : daysOfWeek.getChildren())
         {
            processCalendarHours(calendar, dayRecord);
         }
      }
   }
451558
public static List<Date> toDateList(final List<Calendar> dates) {
        return dates.stream().map(Calendar::getTime).collect(Collectors.toList());
    }
1215209
private void processCalendars() throws SQLException
   {
      List<Row> rows = getTable("EXCEPTIONN");
      Map<Integer, DayType> exceptionMap = m_reader.createExceptionTypeMap(rows);

      rows = getTable("WORK_PATTERN");
      Map<Integer, Row> workPatternMap = m_reader.createWorkPatternMap(rows);

      rows = new LinkedList<Row>();// getTable("WORK_PATTERN_ASSIGNMENT"); // Need to generate an example
      Map<Integer, List<Row>> workPatternAssignmentMap = m_reader.createWorkPatternAssignmentMap(rows);

      rows = getTable("EXCEPTION_ASSIGNMENT");
      Map<Integer, List<Row>> exceptionAssignmentMap = m_reader.createExceptionAssignmentMap(rows);

      rows = getTable("TIME_ENTRY");
      Map<Integer, List<Row>> timeEntryMap = m_reader.createTimeEntryMap(rows);

      rows = getTable("CALENDAR");
      Collections.sort(rows, CALENDAR_COMPARATOR);
      for (Row row : rows)
      {
         m_reader.processCalendar(row, workPatternMap, workPatternAssignmentMap, exceptionAssignmentMap, timeEntryMap, exceptionMap);
      }

      //
      // Update unique counters at this point as we will be generating
      // resource calendars, and will need to auto generate IDs
      //
      m_reader.getProject().getProjectConfig().updateUniqueCounters();
   }
1315595
private void getWeeklyDates(Calendar calendar, int frequency, List<Date> dates)
   {
      int currentDay = calendar.get(Calendar.DAY_OF_WEEK);

      while (moreDates(calendar, dates))
      {
         int offset = 0;
         for (int dayIndex = 0; dayIndex < 7; dayIndex++)
         {
            if (getWeeklyDay(Day.getInstance(currentDay)))
            {
               if (offset != 0)
               {
                  calendar.add(Calendar.DAY_OF_YEAR, offset);
                  offset = 0;
               }
               if (!moreDates(calendar, dates))
               {
                  break;
               }
               dates.add(calendar.getTime());
            }

            ++offset;
            ++currentDay;

            if (currentDay > 7)
            {
               currentDay = 1;
            }
         }

         if (frequency > 1)
         {
            offset += (7 * (frequency - 1));
         }
         calendar.add(Calendar.DAY_OF_YEAR, offset);
      }
   }
255445
public void setCalendar(ProjectCalendar calendar)
   {
      set(TaskField.CALENDAR, calendar);
      setCalendarUniqueID(calendar == null ? null : calendar.getUniqueID());
   }
17602
private void processCalendars()
   {
      List<Row> rows = getRows("calendar", null, null);
      m_reader.processCalendars(rows);
   }
180761
function CalendarList(_super) {
  _super(this, {
     flexGrow: 1,
     alignSelf: FlexLayout.AlignSelf.STRETCH,
     backgroundColor: Color.GREEN, 
  });
  
  this.init();
}
1226491
private void processRanges(List<DateRange> ranges, ProjectCalendarDateRanges container)
   {
      if (ranges != null)
      {
         for (DateRange range : ranges)
         {
            container.addRange(range);
         }
      }
   }
87163
private void readCalendars()
   {
      //
      // Create the calendars
      //
      for (MapRow row : getTable("NCALTAB"))
      {
         ProjectCalendar calendar = m_projectFile.addCalendar();
         calendar.setUniqueID(row.getInteger("UNIQUE_ID"));
         calendar.setName(row.getString("NAME"));
         calendar.setWorkingDay(Day.SUNDAY, row.getBoolean("SUNDAY"));
         calendar.setWorkingDay(Day.MONDAY, row.getBoolean("MONDAY"));
         calendar.setWorkingDay(Day.TUESDAY, row.getBoolean("TUESDAY"));
         calendar.setWorkingDay(Day.WEDNESDAY, row.getBoolean("WEDNESDAY"));
         calendar.setWorkingDay(Day.THURSDAY, row.getBoolean("THURSDAY"));
         calendar.setWorkingDay(Day.FRIDAY, row.getBoolean("FRIDAY"));
         calendar.setWorkingDay(Day.SATURDAY, row.getBoolean("SATURDAY"));

         for (Day day : Day.values())
         {
            if (calendar.isWorkingDay(day))
            {
               // TODO: this is an approximation
               calendar.addDefaultCalendarHours(day);
            }
         }
      }

      //
      // Set up the hierarchy and add exceptions
      //
      Table exceptionsTable = getTable("CALXTAB");
      for (MapRow row : getTable("NCALTAB"))
      {
         ProjectCalendar child = m_projectFile.getCalendarByUniqueID(row.getInteger("UNIQUE_ID"));
         ProjectCalendar parent = m_projectFile.getCalendarByUniqueID(row.getInteger("BASE_CALENDAR_ID"));
         if (child != null && parent != null)
         {
            child.setParent(parent);
         }

         addCalendarExceptions(exceptionsTable, child, row.getInteger("FIRST_CALENDAR_EXCEPTION_ID"));

         m_eventManager.fireCalendarReadEvent(child);
      }
   }
1252015
private void processExceptionDays(ProjectCalendar mpxjCalendar, List<net.sf.mpxj.planner.schema.Day> dayList)
   {
      for (ProjectCalendarException mpxjCalendarException : mpxjCalendar.getCalendarExceptions())
      {
         Date rangeStartDay = mpxjCalendarException.getFromDate();
         Date rangeEndDay = mpxjCalendarException.getToDate();
         if (DateHelper.getDayStartDate(rangeStartDay).getTime() == DateHelper.getDayEndDate(rangeEndDay).getTime())
         {
            //
            // Exception covers a single day
            //
            net.sf.mpxj.planner.schema.Day day = m_factory.createDay();
            dayList.add(day);
            day.setType("day-type");
            day.setDate(getDateString(mpxjCalendarException.getFromDate()));
            day.setId(mpxjCalendarException.getWorking() ? "0" : "1");
         }
         else
         {
            //
            // Exception covers a range of days
            //
            Calendar cal = DateHelper.popCalendar(rangeStartDay);

            while (cal.getTime().getTime() < rangeEndDay.getTime())
            {
               net.sf.mpxj.planner.schema.Day day = m_factory.createDay();
               dayList.add(day);
               day.setType("day-type");
               day.setDate(getDateString(cal.getTime()));
               day.setId(mpxjCalendarException.getWorking() ? "0" : "1");
               cal.add(Calendar.DAY_OF_YEAR, 1);
            }
            
            DateHelper.pushCalendar(cal);
         }

         /**
          * @TODO we need to deal with date ranges here
          */
      }
   }
638543
public void deleteCalendar(GoogleCalendar calendar) throws IOException {
        dao.calendars().delete(calendar.getId()).execute();
    }
375002
private void processCalendarHours(ProjectCalendar calendar, Row row, int dayIndex)
   {
      Day day = Day.getInstance(dayIndex);
      boolean working = row.getInt("CD_WORKING") != 0;
      calendar.setWorkingDay(day, working);
      if (working == true)
      {
         ProjectCalendarHours hours = calendar.addCalendarHours(day);

         Date start = row.getDate("CD_FROM_TIME1");
         Date end = row.getDate("CD_TO_TIME1");
         if (start != null && end != null)
         {
            hours.addRange(new DateRange(start, end));
         }

         start = row.getDate("CD_FROM_TIME2");
         end = row.getDate("CD_TO_TIME2");
         if (start != null && end != null)
         {
            hours.addRange(new DateRange(start, end));
         }

         start = row.getDate("CD_FROM_TIME3");
         end = row.getDate("CD_TO_TIME3");
         if (start != null && end != null)
         {
            hours.addRange(new DateRange(start, end));
         }

         start = row.getDate("CD_FROM_TIME4");
         end = row.getDate("CD_TO_TIME4");
         if (start != null && end != null)
         {
            hours.addRange(new DateRange(start, end));
         }

         start = row.getDate("CD_FROM_TIME5");
         end = row.getDate("CD_TO_TIME5");
         if (start != null && end != null)
         {
            hours.addRange(new DateRange(start, end));
         }
      }
   }
316300
private boolean isSplit(ProjectCalendar calendar, List<TimephasedWork> list)
   {
      boolean result = false;
      for (TimephasedWork assignment : list)
      {
         if (calendar != null && assignment.getTotalAmount().getDuration() == 0)
         {
            Duration calendarWork = calendar.getWork(assignment.getStart(), assignment.getFinish(), TimeUnit.MINUTES);
            if (calendarWork.getDuration() != 0)
            {
               result = true;
               break;
            }
         }
      }
      return result;
   }