Question

I'm having some hard time building my own period class, i know that there are some already made classes out there but due to internal restrictions i will have to implement my own. The constructor (code below) basically accepts 2 dates, a start and an end, the method makeWeeks(), will devide this period into weeks, i developed this according to the "head-tail" principle that i learned when i was studying lists.

heres the code (the essentials)

public class Period implements Serializable
{
  private static final long serialVersionUID = 1L;

  private Calendar          start;

  private Calendar          end;

  private long              durationMillis;

  private long              startMillis;

  private long              endMillis;

  private long              MAX              = 604800000; //A week in millis

  private long              DAY              = 86400000;

  private long              SIX              = 518400000;

  private ArrayList<Week>   weeks;


  public Period(Calendar start, Calendar end)
  {

    this.start = start;
    this.end = end;
    startMillis = start.getTimeInMillis();
    endMillis = end.getTimeInMillis();
    durationMillis = endMillis - startMillis;
    int startWeek = start.get(Calendar.WEEK_OF_YEAR);
    int endWeek = end.get(Calendar.WEEK_OF_YEAR);
    weeks = new ArrayList<Week>();

  }

  /**
   * Construct the weeks in this period
   * 
   * @return
   */
  public ArrayList<Week> makeWeeks()
  {
    long borderLine;

    if ((durationMillis < MAX) || (endMillis < startMillis))
    {
      return null;
    }
    Calendar endHead = Calendar.getInstance();
    //If first week is not Monday then count the days that have been completed
    if (start.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY)
    {
      int days = 0;
      start = adjustCalendar(start);//Set time to 0:0:0:0
      days = getDaysToMonday(start.get(Calendar.DAY_OF_WEEK));
      endHead.setTimeInMillis(start.getTimeInMillis());
      endHead.add(Calendar.DAY_OF_YEAR, days - 1);
      weeks.add(new Week(start, endHead, days, calcCompletion(days), setWeekNumber(start)));//was endHead
      borderLine = endHead.getTimeInMillis() + DAY;
    }//head week set

    else
    {
      start = adjustCalendar(start);
      endHead.setTimeInMillis(start.getTimeInMillis());//Successful
      borderLine = endHead.getTimeInMillis();
    }

    long endMillis = 0;

    while ((((borderLine + SIX)) < (end.getTimeInMillis() + 1)))
    {

      Calendar endNext = Calendar.getInstance();
      Calendar begin = Calendar.getInstance();
      begin.setTimeInMillis(borderLine);
      endNext.setTimeInMillis(borderLine + SIX);

      weeks.add(new Week(begin, endNext, 7, true, setWeekNumber(begin)));
      borderLine += MAX;
      endMillis = endNext.getTimeInMillis();
    }
    //adjust Tail

    Calendar tail = Calendar.getInstance();
    tail.setTimeInMillis(endMillis + DAY);//the beginning of the tail

    tail = adjustCalendar(tail);//set to 00:00:00

    int daysTail = getDaysToTail(end.get(Calendar.DAY_OF_WEEK) + 1);
    if (daysTail != 0)
    {
      weeks.add(new Week(tail, end, daysTail, calcCompletion(daysTail), setWeekNumber(end)));
    }
    return weeks;
  }//EOF makeweeks


  private int setWeekNumber(Calendar cal)
  {

    return cal.get(Calendar.WEEK_OF_YEAR);
  }

  /**
   * This method returns the amount of days between the given day and the next coming Monday
   */
  private int getDaysToMonday(int currentDay)
  {

    switch (currentDay)
    {

      case 1://sunday
        return 1;

      case 2://monday
        return 0;

      case 3://tuesday
        return 6;

      case 4://wednesday
        return 5;

      case 5://thursday
        return 4;

      case 6://friday
        return 3;

      case 7://saturday
        return 2;
    }
    return 0;

  }//EOF method

  /**
   * Returns the day to the end of the final week, always start counting from a Monday
   * 
   * @return
   */
  private int getDaysToTail(int tailDay)
  {

    switch (tailDay)
    {

      case 1://sunday
        return 0;

      case 2://monday
        return 1;

      case 3://tuesday
        return 2;

      case 4://wednesday
        return 3;

      case 5://thursday
        return 4;

      case 6://friday
        return 5;

      case 7://saturday
        return 6;
    }

    return 0;

  }

  /**
   * Returns the amount of weeks stored in this period, completed and non
   * 
   * @return
   */
  public int totalWeeks()
  {
    return weeks.size();
  }

  /**
   * Tells us if the selected period is at least one week
   * will return no result.
   * 
   * @return
   */
  public boolean isAtleastWeek()
  {
    long diff = end.getTimeInMillis() - start.getTimeInMillis();
    if (diff < MAX)
    {
      return false;
    }
    return true;
  }



  /**
   * Provided a week-number, gives back a Week marked by that week-number, if existing.
   * 
   * @param weekNumber
   * @return
   */
  public Week getWeek(Double weekNumber)
  {

    int weekNumberInt = weekNumber.intValue();
    for (Week week : weeks)
    {
      if (weekNumberInt == week.getWeekNumber())
      {
        return week;
      }
    }
    return null;
  }

  /**
   * This method will set the calendars time (H:M:S:M) to 0:0:0:0 so to be able to calculate a precise start and End,
   * dates will remain unaltered
   * 
   * @param cal
   * @return
   */
  private Calendar adjustCalendar(Calendar nu)
  {

    nu.set(Calendar.HOUR, 0);
    nu.set(Calendar.MINUTE, 0);
    nu.set(Calendar.SECOND, 0);
    nu.set(Calendar.MILLISECOND, 0);

    return nu;
  }

I'm afraid there is something wrong, this works fine in most cases but in some cases, (like November and December 2011) the second week is not collected, and in March 2012 the last week is not collected if you set as endDate 31/Mar/2012 but it is if you select as end 30/Mar/2012. Do you have any advice?

Was it helpful?

Solution

Solved!

public class Period implements Serializable
{
  private static final long serialVersionUID = 1L;

  private Calendar          start;

  private Calendar          end;

  private Calendar          startClone;

  private Calendar          endClone;

  private long              durationMillis;

  private long              startMillis;

  private long              endMillis;

  private long              MAX              = 604800000; //A week in millis

  private long              DAY              = 86400000;

  private long              SIX              = 518400000;

  private ArrayList<Week>   weeks;

  /**
   * Constructor accepts 2 Calendars
   * 
   * @param start
   * @param end
   */
  public Period(Calendar start, Calendar end)
  {

    this.start = start;
    this.end = end;
    startClone = (Calendar)start.clone();
    endClone = (Calendar)end.clone();
    startMillis = start.getTimeInMillis();
    endMillis = end.getTimeInMillis();
    durationMillis = endMillis - startMillis;
    int startWeek = start.get(Calendar.WEEK_OF_YEAR);
    int endWeek = end.get(Calendar.WEEK_OF_YEAR);
    weeks = new ArrayList<Week>();

  }

  /**
   * Construct the weeks in this period
   * 
   * @return
   */
  public ArrayList<Week> makeWeeks()
  {
    Calendar borderLine;
    //The meaning of this is to report on weeks, so shorter periods wont be taken in consideration
    if ((durationMillis < MAX) || (endMillis < startMillis))
    {
      return null;
    }
    Calendar endHead = Calendar.getInstance();
    //If first week is not Monday then count the days that have been completed
    if (start.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY)
    {
      int days = 0;
      start = adjustCalendar(start);//Set time to 0:0:0:0
      days = getDaysToMonday(start.get(Calendar.DAY_OF_WEEK));
      endHead = (Calendar)start.clone();
      endHead.add(Calendar.DAY_OF_YEAR, days - 1);
      weeks.add(new Week(start, endHead, days, calcCompletion(days), setWeekNumber(start)));//was endHead
      //borderLine = endHead.getTimeInMillis() + DAY;
      Calendar vector = endHead;
      vector.add(Calendar.DAY_OF_YEAR, 1);
      borderLine = vector;
    }//head week set

    else
    {
      start = adjustCalendar(start);
      endHead = (Calendar)start.clone();//Successful
      borderLine = (Calendar)endHead.clone();
    }

    long endMillis = 0;

    while ((((borderLine.getTimeInMillis() + SIX)) < (end.getTimeInMillis() + 1)))
    {

      Calendar endNext = Calendar.getInstance();
      Calendar begin = Calendar.getInstance();
      begin = (Calendar)borderLine.clone();
      endNext = (Calendar)borderLine.clone();
      endNext.add(Calendar.DAY_OF_YEAR, 6);
      weeks.add(new Week(begin, endNext, 7, true, setWeekNumber(begin)));
      borderLine.add(Calendar.DAY_OF_YEAR, 7);
      endMillis = endNext.getTimeInMillis();
    }
    //adjust Tail

    Calendar tail = Calendar.getInstance();
    tail.setTimeInMillis(endMillis);

    tail.add(Calendar.DAY_OF_YEAR, 1);//the beginning of the tail

    if (!(tail.get(Calendar.DAY_OF_YEAR) >= end.get(Calendar.DAY_OF_YEAR)))
    {
      tail = adjustCalendar(tail);//set to 00:00:00

      int daysTail = getDaysToTail(end.get(Calendar.DAY_OF_WEEK));
      if (daysTail != 0)
      {
        weeks.add(new Week(tail, end, daysTail, calcCompletion(daysTail), setWeekNumber(end)));
      }
    }
    return weeks;
  }//EOF makeweeks

  /**
   * Get the weekNumber
   * 
   * @return
   */
  private double setWeekNumber(Calendar cal)
  {

    Integer week = cal.get(Calendar.WEEK_OF_YEAR);
    Double clone = week.doubleValue();
    return clone;
  }

  /**
   * This method returns the amount of days between the given day and the next coming Monday
   */
  private int getDaysToMonday(int currentDay)
  {

    switch (currentDay)
    {

      case 1://sunday
        return 1;

      case 2://monday
        return 0;

      case 3://tuesday
        return 6;

      case 4://wednesday
        return 5;

      case 5://thursday
        return 4;

      case 6://friday
        return 3;

      case 7://saturday
        return 2;
    }
    return 0;

  }//EOF method

  /**
   * Returns the day to the end of the final week, always start counting from a Monday
   * 
   * @return
   */
  private int getDaysToTail(int tailDay)
  {

    switch (tailDay)
    {

      case 1://sunday
        return 0;

      case 2://monday
        return 1;

      case 3://tuesday
        return 2;

      case 4://wednesday
        return 3;

      case 5://thursday
        return 4;

      case 6://friday
        return 5;

      case 7://saturday
        return 6;
    }

    return 0;

  }

  /**
   * Returns the amount of weeks stored in this period, completed and non
   * 
   * @return
   */
  public int totalWeeks()
  {
    return weeks.size();
  }

  /**
   * Tells us if the selected period is at least one week, since this is a weekly report, selecting less then a week
   * will return no result.
   * 
   * @return
   */
  public boolean isAtleastWeek()
  {
    long diff = endClone.getTimeInMillis() - startClone.getTimeInMillis();
    if (diff < MAX)
    {
      return false;
    }
    return true;
  }

  /**
   * Provide the dates(start and end of a week) in the form of a String
   * 
   * @param weekNumber
   * @return
   */
  public String getDates(Double weekNumber)
  {

    int weekNumberInt = weekNumber.intValue();

    String vector = new String();

    for (Week week : weeks)
    {
      if (week.getWeekNumber() == weekNumberInt)
      {
        vector += week.getStart().get(Calendar.DAY_OF_MONTH) + "/";
        vector += (week.getStart().get(Calendar.MONTH) + 1) + "/";
        vector += week.getStart().get(Calendar.YEAR) + "-";
        vector += (week.getEnd().get(Calendar.DAY_OF_MONTH)) + "/";
        vector += (week.getEnd().get(Calendar.MONTH) + 1) + "/";
        vector += week.getEnd().get(Calendar.YEAR);
      }
    }
    return vector;
  }

  /**
   * Provided a week-number, gives back a Week marked by that week-number, if existing.
   * 
   * @param weekNumber
   * @return
   */
  public Week getWeek(Double weekNumber)
  {

    int weekNumberInt = weekNumber.intValue();
    for (Week week : weeks)
    {
      if (weekNumberInt == week.getWeekNumber())
      {
        return week;
      }
    }
    return null;
  }

  /**
   * This method will set the calendars time (H:M:S:M) to 0:0:0:0 so to be able to calculate a precise start and End,
   * dates will remain unaltered
   * 
   * @param cal
   * @return
   */
  private Calendar adjustCalendar(Calendar nu)
  {

    nu.set(Calendar.HOUR, 0);
    nu.set(Calendar.MINUTE, 0);
    nu.set(Calendar.SECOND, 0);
    nu.set(Calendar.MILLISECOND, 0);

    return nu;
  }

  /**
   * BBC defines a week "complete" only if 4 or more days of that week have passed.
   * 
   * @param days
   * @return
   */
  private boolean calcCompletion(int days)
  {
    if (days < 4)
    {
      return false;
    }
    return true;
  }

  /**
   * @return
   */
  public boolean hasWeekNumber(Double weekNumber)
  {

    for (Week week : weeks)
    {
      if (weekNumber.intValue() == week.getWeekNumber())
      {
        return true;
      }
    }
    return false;
  }

  /**
   * Returns the highest week number
   * 
   * @return
   */
  public double getHighestWeekNumber()
  {
    return weeks.get(weeks.size() - 1).getWeekNumber();
  }

  /**
   * Test method to print fields of a calendar
   */
  private String showCalValues(Calendar cal)
  {

    return "Day of year " + cal.get(Calendar.DAY_OF_YEAR) + " Day of month: " + cal.get(Calendar.DAY_OF_MONTH)
        + " Day of week: " + cal.get(Calendar.DAY_OF_WEEK) + " month " + cal.get(Calendar.MONTH) + " date: "
        + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.MILLISECOND)
        + " week number: " + cal.get(Calendar.WEEK_OF_YEAR) + " millis: " + cal.getTimeInMillis();
  }

  /**
   * Test method that prints the weeks
   */
  private void showWeeks()
  {
    for (Week w : weeks)
    {
      System.out.println(w.getWeekNumber() + " start millis: " + w.getStart().getTimeInMillis());
    }
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top