import tauzaman.field.*;
import tauzaman.timestamp.*;
import tauzaman.calendar.*;
import tauzaman.calendar.Calendar;
import tauzaman.calendricsystem.*;
import tauzaman.TauZamanException;

/*
 * This class implements all the methods necessary for a simple Gregorian Calendar
 * that will work with tauZaman.  Here are the following assumptions I made while
 * writing this calendar:
 *   # It starts on January 1, 0001 AD and goes forward.
 *   # There is no support for negative granules (ones before January 1, 0001 00:00:00
 *     at this time).
 *   # There are no prophetic calculations that occur (i.e. estimating Gregorian
 *     Calendar information before AD).
 *   # Each granule starts at 1 (not 0), therefore, I am doing 1-based counting
 *     of the granules.  Therefore, second 1 = January 1, 0001 00:00:00.
 *   # Leap years and seconds have be implemented according to the Gregorian
 *     Calendar rules for leap years/seconds.
 *
 * Last Updated: 2003/3/16 by Jessica Miller
 */

public class ADGregorianCalendar
{
  /******************************************************************************/
  /* Constants                                                                  */
  /******************************************************************************/
  private static final long NUM_YEARS_LEAP_CYCLE  = 4;
  private static final long NUM_YEARS_CENTURY     = 100;
  private static final long NUM_YEARS_GC_CYCLE    = 400;

  private static final long NUM_MONTHS_YEAR       = 12;
  private static final long NUM_MONTHS_LEAP_CYCLE = NUM_MONTHS_YEAR * NUM_YEARS_LEAP_CYCLE;
  private static final long NUM_MONTHS_CENTURY    = NUM_MONTHS_YEAR * NUM_YEARS_CENTURY;
  private static final long NUM_MONTHS_GC_CYCLE   = NUM_MONTHS_YEAR * NUM_YEARS_GC_CYCLE;

  private static final long NUM_DAYS_YEAR         = 365;
  private static final long NUM_DAYS_LEAP_YEAR    = 366;
  private static final long NUM_DAYS_LEAP_CYCLE   = NUM_DAYS_YEAR * NUM_YEARS_LEAP_CYCLE + 1;
  private static final long NUM_DAYS_CENTURY      = NUM_DAYS_YEAR * NUM_YEARS_CENTURY +
                                                    (NUM_YEARS_CENTURY / NUM_YEARS_LEAP_CYCLE) - 1;
  private static final long NUM_DAYS_GC_CYCLE     = NUM_DAYS_CENTURY * 4 + 1;

  private static final long NUM_HOURS_DAY         = 24;
  private static final long NUM_HOURS_LEAP_YEAR   = NUM_HOURS_DAY * NUM_DAYS_LEAP_YEAR;
  private static final long NUM_HOURS_YEAR        = NUM_HOURS_DAY * NUM_DAYS_YEAR;
  private static final long NUM_HOURS_LEAP_CYCLE  = NUM_HOURS_DAY * NUM_DAYS_LEAP_CYCLE;
  private static final long NUM_HOURS_CENTURY     = NUM_HOURS_DAY * NUM_DAYS_CENTURY;
  private static final long NUM_HOURS_GC_CYCLE    = NUM_HOURS_DAY * NUM_DAYS_GC_CYCLE;

  private static final long NUM_MINS_HOUR         = 60;
  private static final long NUM_MINS_DAY          = NUM_MINS_HOUR * 24;
  private static final long NUM_MINS_LEAP_YEAR    = NUM_MINS_DAY * NUM_DAYS_LEAP_YEAR;
  private static final long NUM_MINS_YEAR         = NUM_MINS_DAY * NUM_DAYS_YEAR;
  private static final long NUM_MINS_LEAP_CYCLE   = NUM_MINS_DAY * NUM_DAYS_LEAP_CYCLE;
  private static final long NUM_MINS_CENTURY      = NUM_MINS_DAY * NUM_DAYS_CENTURY;
  private static final long NUM_MINS_GC_CYCLE     = NUM_MINS_DAY * NUM_DAYS_GC_CYCLE;

  private static final long NUM_SECS_MINUTE       = 60;
  private static final long NUM_SECS_HOUR         = NUM_SECS_MINUTE * 60;
  private static final long NUM_SECS_DAY          = NUM_SECS_MINUTE * NUM_MINS_DAY;
  private static final long NUM_SECS_LEAP_YEAR    = NUM_SECS_MINUTE * NUM_MINS_LEAP_YEAR;
  private static final long NUM_SECS_YEAR         = NUM_SECS_MINUTE * NUM_MINS_YEAR;
  private static final long NUM_SECS_LEAP_CYCLE   = NUM_SECS_MINUTE * NUM_MINS_LEAP_CYCLE;
  private static final long NUM_SECS_CENTURY      = NUM_SECS_MINUTE * NUM_MINS_CENTURY;
  private static final long NUM_SECS_GC_CYCLE     = NUM_SECS_MINUTE * NUM_MINS_GC_CYCLE;

  private static final int NON_LEAP_YEAR      = 0;
  private static final int LEAP_YEAR          = 1;
  private static final long[][] DAYS_IN_MONTHS = {
    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} };
  private static final long[][] DAYS_COMPLETED_BY_MONTH = {
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
  };

  private static final long[] MINUTES_WITH_LEAP_SECONDS = {
    sumMinutes(1972, 06, 30, 23, 59),
    sumMinutes(1972, 12, 31, 23, 59),
    sumMinutes(1973, 12, 31, 23, 59),
    sumMinutes(1974, 12, 31, 23, 59),
    sumMinutes(1975, 12, 31, 23, 59),
    sumMinutes(1976, 12, 31, 23, 59),
    sumMinutes(1977, 12, 31, 23, 59),
    sumMinutes(1978, 12, 31, 23, 59),
    sumMinutes(1979, 12, 31, 23, 59),
    sumMinutes(1981, 06, 30, 23, 59),
    sumMinutes(1982, 06, 30, 23, 59),
    sumMinutes(1983, 06, 30, 23, 59),
    sumMinutes(1985, 06, 30, 23, 59),
    sumMinutes(1987, 12, 31, 23, 59),
    sumMinutes(1989, 12, 31, 23, 59),
    sumMinutes(1990, 12, 31, 23, 59),
    sumMinutes(1992, 06, 30, 23, 59),
    sumMinutes(1993, 06, 30, 23, 59),
    sumMinutes(1994, 06, 30, 23, 59),
    sumMinutes(1995, 12, 31, 23, 59),
    sumMinutes(1997, 06, 30, 23, 59),
    sumMinutes(1998, 12, 31, 23, 59)
  };

  private static final long[] LEAP_SECONDS = {
    sumSeconds(1972, 06, 30, 23, 59, 60),
    sumSeconds(1972, 12, 31, 23, 59, 60),
    sumSeconds(1973, 12, 31, 23, 59, 60),
    sumSeconds(1974, 12, 31, 23, 59, 60),
    sumSeconds(1975, 12, 31, 23, 59, 60),
    sumSeconds(1976, 12, 31, 23, 59, 60),
    sumSeconds(1977, 12, 31, 23, 59, 60),
    sumSeconds(1978, 12, 31, 23, 59, 60),
    sumSeconds(1979, 12, 31, 23, 59, 60),
    sumSeconds(1981, 06, 30, 23, 59, 60),
    sumSeconds(1982, 06, 30, 23, 59, 60),
    sumSeconds(1983, 06, 30, 23, 59, 60),
    sumSeconds(1985, 06, 30, 23, 59, 60),
    sumSeconds(1987, 12, 31, 23, 59, 60),
    sumSeconds(1989, 12, 31, 23, 59, 60),
    sumSeconds(1990, 12, 31, 23, 59, 60),
    sumSeconds(1992, 06, 30, 23, 59, 60),
    sumSeconds(1993, 06, 30, 23, 59, 60),
    sumSeconds(1994, 06, 30, 23, 59, 60),
    sumSeconds(1995, 12, 31, 23, 59, 60),
    sumSeconds(1997, 06, 30, 23, 59, 60),
    sumSeconds(1998, 12, 31, 23, 59, 60)
  };

  // Need these offsets because there is no 0th day, week, month or year of
  //   this calendar's starting point
  public static final int SECOND_OFFSET      = 1;
  public static final int MINUTE_OFFSET      = 1;
  public static final int DAY_OFFSET         = 1;
  public static final int WEEK_OFFSET        = 1;
  public static final int MONTH_OFFSET       = 1;
  public static final int YEAR_OFFSET        = 1;

  // Constants for indices of array that is given back in the split
  public static final int YEAR_INDEX         = 0;
  public static final int MONTH_INDEX        = 1;
  public static final int DAY_INDEX          = 2;
  public static final int HOUR_INDEX         = 3;
  public static final int MINUTE_INDEX       = 4;
  public static final int SECOND_INDEX       = 5;
  public static final int SPLIT_ARRAY_SIZE   = 6;


  /***************************************************************************/
  /* Helper methods                                                          */
  /***************************************************************************/


  /*
   * Returns the number of leap seconds that have occurred up to (not
   *   including) the given minute (away from January 1, 0001 00:00).
   *
   *   @param minute minute from January 1, 0001 00:00
   *   @return       number of leap seconds that have occurred since minute
   */
  private static long getNumLeapSecsFromMin(long minute)
  {
    int i = 0;
    long numLeapSeconds = 0;

    while (i < MINUTES_WITH_LEAP_SECONDS.length
          &&  MINUTES_WITH_LEAP_SECONDS[i++] < minute)
      numLeapSeconds++;

    return numLeapSeconds;
  }


  /*
   * Returns the number of leap seconds that have occurred up to (and
   *   including) the second given (away from January 1, 0001 00:00:00).
   *
   *   @param minute second from January 1, 0001 00:00:00
   *   @return       number of leap seconds that have occurred since second
   */
  private static long getNumLeapSecsFromSec(long second)
  {
    int i = 0;
    long numLeapSeconds = 0;

    while (i < LEAP_SECONDS.length
          &&  LEAP_SECONDS[i++] <= second)
      numLeapSeconds++;

    return numLeapSeconds;
  }


  /*
   * Leap years are determined according to the following rule:
   *   Every year that is exactly divisible by 4 is a leap year,
   *   except for years that are exactly divisible by 100;
   *   these centurial years are leap years only if they are exactly
   *   divisible by 400.
   *
   *   @param year the year that we want to determine is a leap year
   *   @return     whether or not the given year is a leap year
   */
  private static boolean isLeapYear(long year)
  {
    if (year < YEAR_OFFSET)
      return false;
    return ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)));
  }


  /*
   * Returns whether or not the given quantity of secs equates to a leap
   *   second.
   *
   *   @param sec  quantity of seconds to determine is a leap second
   *   @return     whether or not the given quantity of seconds is a leap
   *               second
   */
  private static boolean isLeapSecond(long secs)
  {
    for (int ii = 0; ii < LEAP_SECONDS.length; ii++)
    {
      if (LEAP_SECONDS[ii] == secs)
        return true;
    }

    return false;
  }


  /*
   * Splits years into years by simply returning the given argument.
   *
   *   @param years  the year that we want to split
   *   @return       array whose first value is a year
   */
  public static long[] splitYears(long years)
  {
    long[] result      = new long[SPLIT_ARRAY_SIZE];
    result[YEAR_INDEX] = years;
    return result;
  }


  /*
   * Splits given months into months and years.
   *
   *   @param months  the months that to split into years and months
   *   @return        array of split values (years, months)
   */
  public static long[] splitMonths(long months)
  {
    long[] result       = new long[SPLIT_ARRAY_SIZE];

    // need to take the ceiling since this is a 1-based implementation
    result[YEAR_INDEX]  = (long)Math.ceil((double)months / NUM_MONTHS_YEAR);
    result[MONTH_INDEX] = (months % NUM_MONTHS_YEAR == 0) ?
                          NUM_MONTHS_YEAR : months % NUM_MONTHS_YEAR;
    return result;
  }


  /*
   * Splits given days into days, months and years.
   *
   *   @param month  the day that to split into days, months, years
   *   @return       array of split values (years, months, days)
   */
  public static long[] splitDays(long days)
  {
    long gcCycleYears, centuryYears, leapCycleYears, years, months = 0;
    long[] result  = new long[SPLIT_ARRAY_SIZE];

    gcCycleYears   = days / NUM_DAYS_GC_CYCLE;
    days           -= gcCycleYears * NUM_DAYS_GC_CYCLE;

    centuryYears   = days / NUM_DAYS_CENTURY;
    days           -= centuryYears * NUM_DAYS_CENTURY;

    leapCycleYears = days / NUM_DAYS_LEAP_CYCLE;
    days           -= leapCycleYears * NUM_DAYS_LEAP_CYCLE;

    // need to take the ceiling since this is a 1-based implementation
    years          = (long)Math.ceil((double)days / NUM_DAYS_YEAR);
    years          += gcCycleYears * NUM_YEARS_GC_CYCLE
                   + centuryYears * NUM_YEARS_CENTURY
                   + leapCycleYears * NUM_YEARS_LEAP_CYCLE;

    days           = (days % NUM_DAYS_YEAR == 0) ?
                       isLeapYear(years) ?
                         NUM_DAYS_LEAP_YEAR : NUM_DAYS_YEAR
                     : days - (days / NUM_DAYS_YEAR) * NUM_DAYS_YEAR;

    int ii         = isLeapYear(years) ? LEAP_YEAR : NON_LEAP_YEAR;
    int jj;

    for (jj = 1; jj < DAYS_COMPLETED_BY_MONTH[ii].length; jj++)
    {
      if (days <= DAYS_COMPLETED_BY_MONTH[ii][jj])
      {
        months = jj;
        break;
      }
    }

    days -= DAYS_COMPLETED_BY_MONTH[ii][jj - 1];

    result[YEAR_INDEX]  = years;
    result[MONTH_INDEX] = months;
    result[DAY_INDEX]   = days;

    return result;
  }


  /*
   * Splits given hours into hours, days, months and years.
   *
   *   @param hours  the hours to split into hours, days, months, years
   *   @return       array of split values (years, months, days, hours)
   */
  public static long[] splitHours(long hours)
  {
    long days;

    days           = (long)Math.ceil((double)hours / NUM_HOURS_DAY);
    hours          = (hours % NUM_HOURS_DAY == 0) ?
                     NUM_HOURS_DAY : hours % NUM_HOURS_DAY;

    long[] result  = splitDays(days);
    result[HOUR_INDEX] = hours;
    return result;
  }


  /*
   * Splits given minutes into minutes, hours, days, months and years.
   *
   *   @param mins   the minutes to split into minutes, hours, days, months,
   *                 years
   *   @return       array of split values (years, months, days, hours,
   *                 minutes)
   */
  public static long[] splitMinutes(long mins)
  {
    long hours;

    hours           = (long)Math.ceil((double)mins / NUM_MINS_HOUR);
    mins            = (mins % NUM_MINS_HOUR == 0) ?
                      NUM_MINS_HOUR : mins % NUM_MINS_HOUR;

    long[] result  = splitHours(hours);
    result[MINUTE_INDEX] = mins;
    return result;
  }


  /*
   * Splits given seconds into seconds, minutes, hours, days, months and years.
   *
   *   @param secs   the seconds to split into seconds, minutes, hours, days,
   *                 months, years
   *   @return       array of split values (years, months, days, hours,
   *                 minutes, seconds)
   */
  public static long[] splitSeconds(long secs)
  {

    long mins;

    // adjust secs given by number of leap secs that have occurred up to secs
    long numLeapSecs = getNumLeapSecsFromSec(secs);

    long origSecs    = secs;
    secs           -= numLeapSecs;

    mins            = (long)Math.ceil((double)secs / NUM_SECS_MINUTE);
    secs            = (secs % NUM_SECS_MINUTE == 0) ?
                      NUM_SECS_MINUTE : secs % NUM_SECS_MINUTE;

    long[] result   = splitMinutes(mins);
    result[SECOND_INDEX] = isLeapSecond(origSecs) ? 61 : secs;
    return result;
  }


  /*
   * Return the total number of days (inclusive) in this date starting at
   *   January 1, 0001 to the date given in year, month, day.
   * <p>
   * Formula:
   *   numDays = number of days in the completed years (e.g. if we are in year
   *               1978, we have completed 1977 years according to start of
   *               this calendar)
   *             + number of leap days that occurred in year's time (years / 4)
   *             - number of non-400-divisible centurial years in year's time
   *             + number of days completed in given year up to the given month
   *             + day.
   *
   *   @param year  the year to turn into days
   *   @param month the month to turn into days
   *   @param day   the day to turn into days
   *   @return      sum of the days in the three granularities combined
   */
  private static long sumDays(long year, long month, long day)
  {
    long days;

    // using 'year - YEAR_OFFSET' here because we want to include all
    //   completed years in this calculation (so the current year - 1
    //   since the given year is not yet complete)
    days = ((year - YEAR_OFFSET) * NUM_DAYS_YEAR)
           + ((year - YEAR_OFFSET) / NUM_YEARS_LEAP_CYCLE)
           - (((year - YEAR_OFFSET) / NUM_YEARS_CENTURY)
               -  ((year - YEAR_OFFSET) / NUM_YEARS_GC_CYCLE));

    // using 'month - MONTH_OFFSET' for the same reason as above
    days += isLeapYear(year) ?
              DAYS_COMPLETED_BY_MONTH[LEAP_YEAR][new Long(month).intValue() - MONTH_OFFSET] :
              DAYS_COMPLETED_BY_MONTH[NON_LEAP_YEAR][new Long(month).intValue() - MONTH_OFFSET];

    days += day;

    return days;
  }


  /*
   * Return the total number of minutes (inclusive) in this date starting at
   *   January 1, 0001 00:00 to the date given in year, month, day, hour and
   *   minute.
   * <p>
   * Formula:
   *   numMinutes = number of completed days * 1440 (NUM_MINS_DAY)
   *                + number of completed days * 60 (NUM_MINS_HOUR)
   *                + number of minutes given
   *                + 1 (MINUTE_OFFSET) since counting at minutes starts at 0
   *                  and this method should be inclusive
   *
   *   @param year   the year to turn into minutes
   *   @param month  the month to turn into minutes
   *   @param day    the day to turn into minutes
   *   @param hour   the hour to turn into minutes
   *   @param minute the minute to turn into minutes
   *   @return       sum of the minutes in the five granularities combined
   */
  public static long sumMinutes(long year, long month, long day, long hour, long minute)
  {
    long days;

    days = sumDays(year, month, day) - DAY_OFFSET;

    return days * NUM_MINS_DAY + hour * NUM_MINS_HOUR + minute + MINUTE_OFFSET;
  }


  /*
   * Return the total number of seconds (inclusive) in this date starting at
   *   January 1, 0001 00:00:00 to the date given in year, month, day, hour,
   *   minute, and second.
   * <p>
   * Formula:
   *   numSeconds = number of completed minutes * 60 (NUM_SECS_MINUTE)
   *                + number of seconds given
   *                + 1 (SECOND_OFFSET) since counting at seconds starts at 0
   *                  and this method should be inclusive
   *                + number of leap seconds that have occurred up to this date
   *
   *   @param year   the year to turn into seconds
   *   @param month  the month to turn into seconds
   *   @param day    the day to turn into seconds
   *   @param hour   the hour to turn into seconds
   *   @param minute the minute to turn into seconds
   *   @param second the second to turn into seconds
   *   @return       sum of the seconds in the six granularities combined
   */
  private static long sumSeconds(long year, long month, long day, long hour, long minute,
                                 long second)
  {
    long minutes;

    minutes = sumMinutes(year, month, day, hour, minute) - MINUTE_OFFSET;
    return minutes * NUM_SECS_MINUTE + second + SECOND_OFFSET + getNumLeapSecsFromMin(minutes);
  }


  public static long castDayToYear(Long dayL){
      return castDayToYear(dayL.longValue());
  }

  /*
   * Covert the given amount of seconds to minutes using the cast operation.
   *   This method does take leap seconds into account.
   * <p>
   * Formula:
   *   numSeconds = the number of gregorian cycles in day
   *                + the number of centuries in the remainding days
   *                + the number of leap cycle years in the remainding days
   *                + the number of years in the remainding days
   *                + 1 (if there are any days remainding)
   *
   *   @param day number of day granules to cast into year granularity
   *   @return    number of year granules
   */
  public static long castDayToYear(long day)
  {
    long cycleYears, centuryYears, leapCycleYears, yearYears;
    long remaindingDays;

    cycleYears = day / NUM_DAYS_GC_CYCLE * NUM_YEARS_GC_CYCLE;
    remaindingDays = day - (day / NUM_DAYS_GC_CYCLE * NUM_DAYS_GC_CYCLE);

    centuryYears = remaindingDays / NUM_DAYS_CENTURY * NUM_YEARS_CENTURY;
    remaindingDays -= remaindingDays / NUM_DAYS_CENTURY * NUM_DAYS_CENTURY;

    leapCycleYears = remaindingDays / NUM_DAYS_LEAP_CYCLE * NUM_YEARS_LEAP_CYCLE;
    remaindingDays -= remaindingDays / NUM_DAYS_LEAP_CYCLE * NUM_DAYS_LEAP_CYCLE;

    yearYears = remaindingDays / NUM_DAYS_YEAR;
    remaindingDays -= remaindingDays / NUM_DAYS_YEAR * NUM_DAYS_YEAR;

    return cycleYears + centuryYears + leapCycleYears + yearYears
           + (remaindingDays > 0 ? 1 : 0);
  }


  /***************************************************************************/
  /* Methods that will be used for the irregular mappings in this calendar   */
  /***************************************************************************/

  public static long castSecondToMinute(Long secondL){
      return castSecondToMinute(secondL.longValue());
  }

  /*
   * Covert the given amount of seconds to minutes using the cast operation.
   *   This method does take leap seconds into account.
   * <p>
   * Formula:
   *   numMinutes = ceil((numSeconds - number of leap seconds that have
   *                      occurred up to and including this second)
   *                 / 60 [number of seconds in a minute])
   *
   *   @param second number of second granules to cast into minute granularity
   *   @return       number of minute granules
   */
  public static long castSecondToMinute(long second)
  {
    long leapSeconds = 0;

    leapSeconds = getNumLeapSecsFromSec(second);

    return (long)Math.ceil((second - leapSeconds) / 60.0);
  }

  public static long castMinuteToSecond(Long minuteL){
      return castMinuteToSecond(minuteL.longValue());
  }
  /*
   * Covert the given amount of minutes to seconds using the cast operation.
   *   This method does take leap seconds into account.
   * <p>
   * Formula:
   *   numSeconds = the number of minutes totally complete * number of seconds
   *                in a minute + 1 (to roll over to the lower support of minute)
   *
   *   @param second number of minute granules to cast into second granularity
   *   @return       number of second granules
   */
  public static long castMinuteToSecond(long minute)
  {
    long seconds;

    seconds = (NUM_SECS_MINUTE * (minute - 1)) + 1;

    return seconds += getNumLeapSecsFromMin(minute);
  }


  public static long castDayToMonth(Long dayL){
      return castDayToMonth(dayL.longValue());
  }

  /*
   * Convert the given amount of days to months using the cast operation.
   *   This method does take leap years into account.
   * <p>
   * Formula:
   *   numMonths = number of years completed in day * 12 + remainding months
   *
   *   @param day number of day granules to cast into month granularity
   *   @return    number of month granules
   */
  public static long castDayToMonth(long day)
  {
    long cycleYears, centuryYears, leapCycleYears, yearYears, totalYears;
    long remaindingDays;
    long months = 0;


    // get number of years completed by this day using the algorithm from
    //  castDayToYear()
    cycleYears = day / NUM_DAYS_GC_CYCLE * NUM_YEARS_GC_CYCLE;
    remaindingDays = day - (day / NUM_DAYS_GC_CYCLE * NUM_DAYS_GC_CYCLE);

    centuryYears = remaindingDays / NUM_DAYS_CENTURY * NUM_YEARS_CENTURY;
    remaindingDays -= remaindingDays / NUM_DAYS_CENTURY * NUM_DAYS_CENTURY;

    leapCycleYears = remaindingDays / NUM_DAYS_LEAP_CYCLE * NUM_YEARS_LEAP_CYCLE;
    remaindingDays -= remaindingDays / NUM_DAYS_LEAP_CYCLE * NUM_DAYS_LEAP_CYCLE;

    yearYears = remaindingDays / NUM_DAYS_YEAR;
    remaindingDays -= remaindingDays / NUM_DAYS_YEAR * NUM_DAYS_YEAR;

    totalYears = cycleYears + centuryYears + leapCycleYears + yearYears;

    // if there are still days remainding, using DAYS_COMPLETED_BY_MONTH,
    //   figure out how many months are in the remainding days
    if (remaindingDays > 0)
    {
      int i = isLeapYear(totalYears + 1) ? LEAP_YEAR : NON_LEAP_YEAR;

      for (int j = 1; j < DAYS_COMPLETED_BY_MONTH[i].length; j++)
      {
        if (remaindingDays < DAYS_COMPLETED_BY_MONTH[i][j])
        {
          months = j;
          break;
        }
      }
    }

    // now add to months the total number of months in all of the completed
    //   years
    return months + totalYears * NUM_MONTHS_YEAR;
  }


  public static long castMonthToDay(Long monthL){
      return castMonthToDay(monthL.longValue());
  }
  /*
   * Covert the given amount of months to days using the cast operation.
   *   This method does take leap years into account.
   * <p>
   * Formula:
   *   numMonths = number of days in completed years + days up to this
   *               month + 1 (to get the first day of this month since
   *               this would be the lower bound of a scale operation -
   *               and thus the correct behavior of cast)
   *
   *   @param month number of month granules to cast into day granularity
   *   @return      number of day granules
   */
  public static long castMonthToDay(long month)
  {
    long cycleYears, centuryYears, leapCycleYears, yearYears;
    long remaindingMonths;
    long year;
    long days = 0;
 
    month -= MONTH_OFFSET;

    cycleYears      = month / NUM_MONTHS_GC_CYCLE;
    remaindingMonths = month - (month / NUM_MONTHS_GC_CYCLE * NUM_MONTHS_GC_CYCLE);

    centuryYears    = remaindingMonths / NUM_MONTHS_CENTURY;
    remaindingMonths -= remaindingMonths / NUM_MONTHS_CENTURY * NUM_MONTHS_CENTURY;

    leapCycleYears  = remaindingMonths / NUM_MONTHS_LEAP_CYCLE;
    remaindingMonths -= remaindingMonths / NUM_MONTHS_LEAP_CYCLE * NUM_MONTHS_LEAP_CYCLE;

    yearYears       = remaindingMonths / NUM_MONTHS_YEAR;
    remaindingMonths -= remaindingMonths / NUM_MONTHS_YEAR * NUM_MONTHS_YEAR;

    if (remaindingMonths > 0)
    {
      // figure out what year this number of months is in
      year = (long) Math.ceil(month / 12.0);

      int i = isLeapYear(year) ? LEAP_YEAR : NON_LEAP_YEAR;
      for (int j = 0; j < remaindingMonths; j++)
        days += DAYS_IN_MONTHS[i][j];
    }

    return days += (cycleYears * NUM_DAYS_GC_CYCLE) + (centuryYears * NUM_DAYS_CENTURY)
                + (leapCycleYears * NUM_DAYS_LEAP_CYCLE) + (yearYears * NUM_DAYS_YEAR) + 1;
  }


  /**
  * Fills each <code>Field</code> of <code>Fields</code>, which can only be produced
  * by either InstantOutputFormat or IntervalOutputFormat properties.
  * 
  * @param granule <code>Granule</code>, which contains timestamp information
  * @param fields <code>Fields</code>, which represents unparsed temporal constant
  *
  * @return a boolean value true if conversion is successfull, false otherwise
  *
  * @throws CalendarServiceException if any abnormal condition occurs when converting
  * timestamp to unparsed temporal constant. Unsupported <code>Granularities</code> or 
  * <code>Properties</code>, which <code>Fields</code> is produced, may cause 
  * this exception.
  */
  static public Boolean granuleToFields(Granule granule, Fields fields) throws CalendarServiceException{
      
      
      long splitResults[];

      String granularityName = granule.getGranularity().getLocalName();

      // according to granularity of timestamp flattened it to upper granularities
      if(granularityName.equals("year"))
          splitResults = splitYears(granule.getGranule().getValue());
      else if(granularityName.equals("month"))
          splitResults = splitMonths(granule.getGranule().getValue());
      else if(granularityName.equals("day"))
          splitResults = splitDays(granule.getGranule().getValue());
      else if(granularityName.equals("hour"))
          splitResults = splitHours(granule.getGranule().getValue());
      else if(granularityName.equals("minute"))
          splitResults = splitMinutes(granule.getGranule().getValue());
      else if(granularityName.equals("second")){
          splitResults = splitSeconds(granule.getGranule().getValue());
          System.out.println("splitted granule: " + granule.image() 
                                 + splitResults[SECOND_INDEX] + "/" + splitResults[MINUTE_INDEX] + 
                             "/" + splitResults[HOUR_INDEX] + "/" + splitResults[DAY_INDEX] +
                             "/" + splitResults[MONTH_INDEX] + "/" + splitResults[YEAR_INDEX]);
      }
      else
          throw new CalendarServiceException("Exception when converting granule to fields: " +
                                       " undefined granularity: " + granularityName + " in ADGregorian Calendar.");

      // all the fields corresponding to all the granularities and additional 
      //   field names of ADGregorian calendar
      Field yearField = fields.getFieldByName("year"), 
            monthField = fields.getFieldByName("month"),
            dayField = fields.getFieldByName("day"), 
            hourField = fields.getFieldByName("hour"),
            minuteField = fields.getFieldByName("minute"),
            secondField = fields.getFieldByName("second"),
            monthOfYearField = fields.getFieldByName("monthOfYear"), 
            dayOfMonthField = fields.getFieldByName("dayOfMonth"), 
            hourOfDayField = fields.getFieldByName("hourOfDay"),
            minuteOfHourField = fields.getFieldByName("minuteOfHour"),
            secondOfMinuteField = fields.getFieldByName("secondOfMinute");

      // multiplexing of output formats, compatibility checks between fields
      //   are not handled yet 
      if(fields.getName().equals("InstantOutputFormat")){
          if(yearField != null) yearField.setValue(splitResults[YEAR_INDEX]);
          if(monthField != null) monthField.setValue(splitResults[MONTH_INDEX]);
          if(dayField != null) dayField.setValue(splitResults[DAY_INDEX]);
          if(hourField != null) hourField.setValue(splitResults[HOUR_INDEX]);
          if(minuteField != null) minuteField.setValue(splitResults[MINUTE_INDEX]);
          if(secondField != null) secondField.setValue(splitResults[SECOND_INDEX]);
          if(monthOfYearField != null) monthOfYearField.setValue(splitResults[MONTH_INDEX]);
          if(dayOfMonthField != null) dayOfMonthField.setValue(splitResults[DAY_INDEX]);
          if(hourOfDayField != null) hourOfDayField.setValue(splitResults[HOUR_INDEX]);
          if(minuteOfHourField != null) minuteOfHourField.setValue(splitResults[MINUTE_INDEX]);
          if(secondOfMinuteField != null) secondOfMinuteField.setValue(splitResults[SECOND_INDEX]);
      }
      else if(fields.getName().equals("IntervalOutputFormat")){
          if(yearField != null) yearField.setValue(splitResults[YEAR_INDEX]);
          if(monthField != null) monthField.setValue(splitResults[MONTH_INDEX]);
          if(dayField != null) dayField.setValue(splitResults[DAY_INDEX]);
          if(hourField != null) hourField.setValue(splitResults[HOUR_INDEX]);
          if(minuteField != null) minuteField.setValue(splitResults[MINUTE_INDEX]);
          if(secondField != null) secondField.setValue(splitResults[SECOND_INDEX]);
      }
      else
          throw new CalendarServiceException("Exception when converting Granule to fill Fields: undefined temporal data type " +
                                                                                                            fields.getName());

      return new Boolean(true);
  }

  /**
  * Converts unparsed temporal constant, <code>Fields</code>, into timestamp, <code>Granule</code>
  * <code>Fields</code>, which can only be produced by either InstantOutputFormat or 
  * IntervalOutputFormat properties.
  * 
  * @param fields <code>Fields</code>, which represents unparsed temporal constant
  *
  * @return a <code>Granule</code>, which is the corresponding timestamp
  *
  * @throws CalendarServiceException if any abnormal condition occurs when converting
  * unparsed temporal constant to timestamp. Unsupported <code>Granularities</code> or 
  * <code>Properties</code>, which <code>Fields</code> is produced, may cause 
  * this exception.
  */
  static public Granule fieldsToGranule(Fields fields) throws CalendarServiceException{

      // all the fields corresponding to all the granularities and additional 
      //   field names of ADGregorian calendar
      Field yearField = fields.getFieldByName("year"), 
            monthField = fields.getFieldByName("month"),
            dayField = fields.getFieldByName("day"), 
            hourField = fields.getFieldByName("hour"),
            minuteField = fields.getFieldByName("minute"),
            secondField = fields.getFieldByName("second"),
            monthOfYearField = fields.getFieldByName("monthOfYear"), 
            dayOfMonthField = fields.getFieldByName("dayOfMonth"), 
            hourOfDayField = fields.getFieldByName("hourOfDay"),
            minuteOfHourField = fields.getFieldByName("minuteOfHour"),
            secondOfMinuteField = fields.getFieldByName("secondOfMinute");

       // declare variables for values of granularities and additional field names/
       // should sumDays, sum... methods take long or int ???
       long secondOfMinute = 0, minuteOfHour = 0, hourOfDay = 0, dayOfMonth = 0, monthOfYear = 0, 
           year = 0, month = 0, day = 0, minute = 0, second = 0, hour = 0; 

       // get each granularity or additional field values from fields 
       if(yearField != null) year = yearField.getValue();
       if(monthField != null) month = monthField.getValue();
       if(dayField != null) day = dayField.getValue();
       if(hourField != null) hour = hourField.getValue();
       if(minuteField != null) minute = minuteField.getValue();
       if(secondField != null) second = secondField.getValue();
       if(monthOfYearField != null) monthOfYear = monthOfYearField.getValue();
       if(dayOfMonthField != null) dayOfMonth = dayOfMonthField.getValue();
       if(hourOfDayField != null) hourOfDay = hourOfDayField.getValue();
       if(minuteOfHourField != null) minuteOfHour = minuteOfHourField.getValue();
       if(secondOfMinuteField != null) secondOfMinute = secondOfMinuteField.getValue();


      // multiplexing of input formats, compatibility checks between fields
      //   are not handled yet 
      // Note that we don't accept "5 hour" or "hour 4, day 2, month 3" or 
      //   "second 2, hour 1, day 2, month 3" as valid instants. They should
      //   an instant in granularity X, should include valid granules for all its
      //   coarser granularities.
       
      if(fields.getName().equals("InstantInputFormat")){

          long sum = 0;

          if(dayOfMonthField != null && monthOfYearField != null && yearField != null 
             && hourOfDayField != null && minuteOfHourField != null && secondOfMinuteField != null){
              sum = sumSeconds(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute);
              //System.out.println(secondOfMinute + "/" + minuteOfHour + "/" + hourOfDay + "/" + dayOfMonth
              //                   + "/" + monthOfYear + "/" + year + "->" + sum);
              return new Granule(new Granularity("second"), sum);
          }
          if(dayOfMonthField != null && monthOfYearField != null && yearField != null 
             && hourOfDayField != null && minuteOfHourField != null){
              sum = sumMinutes(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour);
              return new Granule(new Granularity("minute"), sum);
          }
          if(dayOfMonthField != null && monthOfYearField != null && yearField != null 
             && hourOfDayField != null){
              sum = (sumDays(year, monthOfYear, dayOfMonth) - DAY_OFFSET) * NUM_HOURS_DAY + hourOfDay;
              return new Granule(new Granularity("hour"), sum);
          }
          if(dayOfMonthField != null && monthOfYearField != null && yearField != null){
              sum = sumDays(year, monthOfYear, dayOfMonth);
              return new Granule(new Granularity("day"), sum);
          } 
          if(monthOfYearField != null && yearField != null){
              sum = (year - YEAR_OFFSET) * NUM_MONTHS_YEAR + monthOfYear; 
              return new Granule(new Granularity("month"), sum);
          }
          if(yearField != null){
              sum = year; 
              return new Granule(new Granularity("year"), sum);
          }
      }
      else if(fields.getName().equals("IntervalInputFormat")){
          
          long sum = 0;

          // we have to note that when we sum "5 seconds, 4 hours, 5 days, 2 years" into seconds
          //   we can't use sum methods above since they use offset to adjust to instant semantic 
          // on the other hand, we need interval cast and scale methods, which we don't have. Therefore
          // we'll go with sum methods

          if(secondField != null ) {
              sum = sumSeconds(year, month, day, hour, minute, second);
              return new Granule(new Granularity("second"), sum);
          }
          if(minuteField != null) {
              sum = sumMinutes(year, month, day, hour, minute);
              return new Granule(new Granularity("minute"), sum);
          }
          if(hourField != null){ 
              sum = (sumDays(year, month, day) - DAY_OFFSET) * NUM_HOURS_DAY + hour;
              return new Granule(new Granularity("hour"), sum);
          }
          if(dayField != null){
              sum = sumDays(year, month, day);
              return new Granule(new Granularity("day"), sum);
          }
          if(monthField != null){ 
              sum = (year - YEAR_OFFSET) * NUM_MONTHS_YEAR + month; 
              return new Granule(new Granularity("month"), sum);
          }
          if(yearField != null) {
              sum = year;
              return new Granule(new Granularity("year"), sum);
          }
      }

      throw new CalendarServiceException("Exception when converting Fields to Granule: undefined temporal data type " +
                                               fields.getName() + " or unidentified field values in temporal constant ");

  }

  public static void main(String[] args)
  {
    long [] splitResults;
/*
    // ********************** test sumDays **********************
    System.out.println("\n********************** test sumDays **********************");
    System.out.println("January 1, 0001 in days    = " + sumDays(1, 1, 1));        //  1
    System.out.println("December 31, 0001 in days  = " + sumDays(1, 12, 31));      //  365
    System.out.println("December 31, 0004 in days  = " + sumDays(4, 12, 31));      //  1461
    System.out.println("February 15, 0001 in days  = " + sumDays(1, 2, 15));       //  46
    System.out.println("December 31, 0100 in days  = " + sumDays(100, 12, 31));    //  36524
    System.out.println("December 31, 0400 in days  = " + sumDays(400, 12, 31));    //  146097
    System.out.println("March 20, 0400 in days     = " + sumDays(400, 3, 20));     //  145811
    System.out.println("November 4, 1101 in days   = " + sumDays(1101, 11, 4));    //  402074
    System.out.println("July 11, 1978 in days      = " + sumDays(1978, 7, 11));    //  722276
    System.out.println("September 2, 2000 in days  = " + sumDays(2000, 9, 2));     //  730365
    System.out.println("September 19, 2003 in days = " + sumDays(2003, 9, 19));    //  731477
    System.out.println("August 21, 2000 in days    = " + sumDays(2000, 8, 21));    //  1053326000


    // ********************** test castDayToYear **********************
    System.out.println("\n********************** test castDayToYear **********************");
    System.out.println("cast(1 day(s), years)      = " + castDayToYear(1)      + " year(s)"); //  1
    System.out.println("cast(365 day(s), years)    = " + castDayToYear(365)    + " year(s)"); //  1
    System.out.println("cast(1461 day(s), years)   = " + castDayToYear(1461)   + " year(s)"); //  4
    System.out.println("cast(46 day(s), years)     = " + castDayToYear(46)     + " year(s)"); //  1
    System.out.println("cast(36524 day(s), years)  = " + castDayToYear(36524)  + " year(s)"); //  100
    System.out.println("cast(146097 day(s), years) = " + castDayToYear(146097) + " year(s)"); //  400
    System.out.println("cast(145811 day(s), years) = " + castDayToYear(145811) + " year(s)"); //  400
    System.out.println("cast(402074 day(s), years) = " + castDayToYear(402074) + " year(s)"); //  1101
    System.out.println("cast(722276 day(s), years) = " + castDayToYear(722276) + " year(s)"); //  1978
    System.out.println("cast(730365 day(s), years) = " + castDayToYear(730365) + " year(s)"); //  2000
    System.out.println("cast(731477 day(s), years) = " + castDayToYear(731477) + " year(s)"); //  2003


    // ********************** test castDayToMonth **********************
    System.out.println("\n********************** test castDayToMonth **********************");
    System.out.println("cast(1 day(s), months)      = " + castDayToMonth(1)      + " month(s)"); //  1     [January 1, 0001    -> 
January 0001]
    System.out.println("cast(365 day(s), months)    = " + castDayToMonth(365)    + " month(s)"); //  12    [December 31, 0001  ->
December 0001]
    System.out.println("cast(1461 day(s), months)   = " + castDayToMonth(1461)   + " month(s)"); //  48    [December 31, 0004  ->
December 0004]
    System.out.println("cast(46 day(s), months)     = " + castDayToMonth(46)     + " month(s)"); //  2     [February 15, 0001  ->
February 0001]
    System.out.println("cast(36524 day(s), months)  = " + castDayToMonth(36524)  + " month(s)"); //  1200  [December 31, 0100  ->
December 0100]
    System.out.println("cast(146097 day(s), months) = " + castDayToMonth(146097) + " month(s)"); //  4800  [December 31, 0400  ->
December 0400]
    System.out.println("cast(145811 day(s), months) = " + castDayToMonth(145811) + " month(s)"); //  4791  [March 20, 0400     -> March
0400]
    System.out.println("cast(402074 day(s), months) = " + castDayToMonth(402074) + " month(s)"); //  13211 [November 4, 1101   ->
November 1101]
    System.out.println("cast(722276 day(s), months) = " + castDayToMonth(722276) + " month(s)"); //  23731 [July 11, 1978      -> July
1978]
    System.out.println("cast(730365 day(s), months) = " + castDayToMonth(730365) + " month(s)"); //  23997 [September 2, 2000  ->
September 2000]
    System.out.println("cast(731477 day(s), months) = " + castDayToMonth(731477) + " month(s)"); //  24033 [September 19, 2003 ->
September 2003]
    // ********************** test castMonthToDay **********************
    System.out.println("\n********************** test castMonthToDay **********************");
    System.out.println("cast(1 month(s), days)     = " + castMonthToDay(1)     + " day(s) [should equal "
                       + sumDays(1, 1, 1) + "]");     //  1      [January 0001   -> January 1, 0001]
    System.out.println("cast(12 month(s), days)    = " + castMonthToDay(12)    + " days(s) [should equal "
                       + sumDays(1, 12, 1) + "]");    //  335    [December 0001  -> December 1, 0001]
    System.out.println("cast(48 month(s), days)    = " + castMonthToDay(48)    + " days(s) [should equal "
                       + sumDays(4, 12, 1) + "]");    //  1431   [December 0004  -> December 1, 0004]
    System.out.println("cast(2 month(s), days)     = " + castMonthToDay(2)     + " days(s) [should equal "
                       + sumDays(1, 2, 1) + "]");     //  32     [February 0001  -> February 1, 0001]
    System.out.println("cast(1200 month(s), days)  = " + castMonthToDay(1200)  + " days(s) [should equal "
                       + sumDays(100, 12, 1) + "]");  //  36494  [December 0100  -> December 1, 0100]
    System.out.println("cast(4800 month(s), days)  = " + castMonthToDay(4800)  + " days(s) [should equal "
                       + sumDays(400, 12, 1) + "]");  //  146067 [December 0400  -> December 1, 0400]
    System.out.println("cast(4791 month(s), days)  = " + castMonthToDay(4791)  + " days(s) [should equal "
                       + sumDays(400, 3, 1) + "]");   //  145792 [March 0400     -> March 1, 0400]
    System.out.println("cast(13211 month(s), days) = " + castMonthToDay(13211) + " days(s) [should equal "
                       + sumDays(1101, 11, 1) + "]"); //  402071 [November 1101  -> November 1, 1101]
    System.out.println("cast(23731 month(s), days) = " + castMonthToDay(23731) + " days(s) [should equal "
                       + sumDays(1978, 7, 1) + "]");  //  722266 [July 1978      -> July 1, 1978]
    System.out.println("cast(23997 month(s), days) = " + castMonthToDay(23997) + " days(s) [should equal "
                       + sumDays(2000, 9, 1) + "]");  //  730364 [September 2000 -> September 1, 2000]
    System.out.println("cast(24033 month(s), days) = " + castMonthToDay(24033) + " days(s) [should equal "
                        + sumDays(2003, 9, 1) + "]");  //  731459 [September 2003 -> September 1, 2003]

    // ********************** test sumSeconds **********************
    System.out.println("\n********************** test sumSeconds **********************");
    System.out.println("January 1, 0001 00:00:00 in seconds    = " + sumSeconds(1, 1, 1, 0, 0, 0));        //  1
    System.out.println("December 31, 0001 00:00:00 in seconds  = " + sumSeconds(1, 12, 31, 0, 0, 0));      //  31449601
    System.out.println("December 31, 0004 00:00:00 in seconds  = " + sumSeconds(4, 12, 31, 0, 0, 0));      //  126144001
    System.out.println("February 15, 0001 00:00:00 in seconds  = " + sumSeconds(1, 2, 15, 0, 0, 0));       //  3888001
    System.out.println("December 31, 0100 00:00:00 in seconds  = " + sumSeconds(100, 12, 31, 0, 0, 0));    //  3155587201
    System.out.println("December 31, 0400 00:00:00 in seconds  = " + sumSeconds(400, 12, 31, 0, 0, 0));    //  12622694401
    System.out.println("March 20, 0400 00:00:00 in seconds     = " + sumSeconds(400, 3, 20, 0, 0, 0));     //  12597984001
    System.out.println("November 4, 1101 00:00:00 in seconds   = " + sumSeconds(1101, 11, 4, 0, 0, 0));    //  34739107201
    System.out.println("July 11, 1978 23:47:00 in seconds      = " + sumSeconds(1978, 7, 11, 23, 47, 11)); //  62404645639
    System.out.println("September 2, 2000 00:00:00 in seconds  = " + sumSeconds(2000, 9, 2, 0, 0, 0));     //  63103449623
    System.out.println("September 19, 2003 00:00:00 in seconds = " + sumSeconds(2003, 9, 19, 0, 0, 0));
    System.out.println("January 1, 1970 00:00:00 in seconds    = " + sumSeconds(1970, 1, 1, 0, 0, 0));
    System.out.println("\n------------ these values are used in the test below ------------");
    System.out.println("January 1, 0001 00:00:00 in seconds    = " + sumSeconds(1, 1, 1, 0, 0, 0));        //  1
    System.out.println("January 1, 0001 00:00:33 in seconds    = " + sumSeconds(1, 1, 1, 0, 0, 33));       //  34
    System.out.println("March 20, 0400 19:02:15 in seconds     = " + sumSeconds(400, 3, 20, 19, 2, 15));   //  12598052536
    System.out.println("November 4, 1101 12:30:05 in seconds   = " + sumSeconds(1101, 11, 4, 12, 30, 5));  //  34739152206
    System.out.println("June 30, 1972 23:59:60 in seconds      = " + sumSeconds(1972, 6, 30, 23, 59, 60)); //  62214393601
    System.out.println("January 1, 1973 4:57:04 in seconds     = " + sumSeconds(1973, 1, 1, 4, 57, 04));   //  62230309027
    System.out.println("July 11, 1978 23:47:11 in seconds      = " + sumSeconds(1978, 7, 11, 23, 47, 11)); //  62404645639
    System.out.println("September 19, 2003 09:19:19 in seconds = " + sumSeconds(2003, 9, 19, 9, 19, 19));  //  63199559982


    // ********************** test sumMinutes **********************
    System.out.println("\n********************** test sumMinutes **********************");
    System.out.println("January 1, 0001 00:00 in minutes    = " + sumMinutes(1, 1, 1, 0, 0));        //  1
    System.out.println("December 31, 0001 00:00 in minutes  = " + sumMinutes(1, 12, 31, 0, 0));      //  524161
    System.out.println("December 31, 0004 00:00 in minutes  = " + sumMinutes(4, 12, 31, 0, 0));      //  2102401
    System.out.println("February 15, 0001 00:00 in minutes  = " + sumMinutes(1, 2, 15, 0, 0));       //  64801
    System.out.println("December 31, 0100 00:00 in minutes  = " + sumMinutes(100, 12, 31, 0, 0));    //  52593121
    System.out.println("December 31, 0400 00:00 in minutes  = " + sumMinutes(400, 12, 31, 0, 0));    //  210378241
    System.out.println("March 20, 0400 02:41 in minutes     = " + sumMinutes(400, 3, 20, 2, 41));    //  209966562
    System.out.println("November 4, 1101 00:00 in minutes   = " + sumMinutes(1101, 11, 4, 0, 0));    //  578985121
    System.out.println("July 11, 1978 23:47 in minutes      = " + sumMinutes(1978, 7, 11, 23, 47));  //  1040077428
    System.out.println("September 2, 2000 00:00 in minutes  = " + sumMinutes(2000, 9, 2, 0, 0));     //  1051724161
    System.out.println("September 19, 2003 00:00 in minutes = " + sumMinutes(2003, 9, 19, 0, 0));    //  1053325441
    System.out.println("August 21, 2000 07:00 in minutes    = " + sumMinutes(2000, 8, 21, 7, 00));   //  1053326000

    System.out.println("\n------------ these values are used in the test below ------------");
    System.out.println("January 1, 0001 00:00 in minutes    = " + sumMinutes(1, 1, 1, 0, 0));        //  1
    System.out.println("January 1, 0001 00:01 in minutes    = " + sumMinutes(1, 1, 1, 0, 1));        //  2
    System.out.println("March 20, 0400 02:41 in minutes     = " + sumMinutes(400, 3, 20, 2, 41));    //  134229762
    System.out.println("July 1, 1972 00:01 in minutes       = " + sumMinutes(1972, 7, 1, 0, 1));     //  1036906562
    System.out.println("January 1, 1973 4:57 in minutes     = " + sumMinutes(1973, 1, 1, 4, 57));    //  1037171818
    System.out.println("July 11, 1978 23:47 in minutes      = " + sumMinutes(1978, 7, 11, 23, 47));  //  1040077428
    System.out.println("September 19, 2003 09:19 in minutes = " + sumMinutes(2003, 9, 19, 9, 19));   //  1053326000

    // ******************* test castMinuteToSecond *****************
    System.out.println("\n********************** test castMinuteToSecond **********************");
    System.out.println("cast(1 minute(s), seconds)            = " + castMinuteToSecond(1)
                       + " second(s) [should equal " + sumSeconds(1, 1, 1, 0, 0, 0) + "]");       //  1           [January 1, 0001 00:00
-> January 1, 0001 00:00:00]
    System.out.println("cast(2 minute(s), seconds)            = " + castMinuteToSecond(2)
                       + " second(s) [should equal " + sumSeconds(1, 1, 1, 0, 1, 0) + "]");       //  61          [January 1, 0001 00:01
-> January 1, 0001 00:01:00]
    System.out.println("cast(209966562 minute(s), seconds)    = " + castMinuteToSecond(209966562)
                       + " second(s) [should equal " + sumSeconds(400, 3, 20, 2, 41, 0) + "]");   //  12597993661 [March 20, 0400 02:41
-> March 20, 0400 02:41:00]
    System.out.println("cast(1036906562 minute(s), seconds)   = " + castMinuteToSecond(1036906562)
                       + " second(s) [should equal " + sumSeconds(1972, 7, 1, 0, 1, 0) + "]");    //  62214393662 [July 1, 1972 00:01
-> July 1, 1972 00:01:00]
    System.out.println("cast(1037171818 minute(s), seconds)   = " + castMinuteToSecond(1037171818)
                       + " second(s) [should equal " + sumSeconds(1973, 1, 1, 4, 57, 0) + "]");   //  62230309023 [January 1, 1973 4:57
-> January 1, 1973 4:57:00]
    System.out.println("cast(1040077428 minute(s), seconds)   = " + castMinuteToSecond(1040077428)
                       + " second(s) [should equal " + sumSeconds(1978, 7, 11, 23, 47, 0) + "]"); //  62404645628 [July 11, 1978 23:47
-> July 11, 1978 23:47:00]
    System.out.println("cast(1053326000 minute(s), seconds)   = " + castMinuteToSecond(1053326000)
                       + " second(s) [should equal " + sumSeconds(2003, 9, 19, 9, 19, 0) + "]");  //  63199559963 [September 19, 2003
09:19 -> September 19, 2003 09:19:00]
    // ******************* test castSecondToMinute *****************
    System.out.println("\n********************** test castSecondToMinute **********************");
    System.out.println("cast(1 second(s), minutes)            = " + castSecondToMinute(1)
                       + " second(s) [should equal " + sumMinutes(1, 1, 1, 0, 0) + "]");       //  1           [January 1, 0001 00:00:00
-> January 1, 0001 00:00]
    System.out.println("cast(34 second(s), minutes)           = " + castSecondToMinute(34)
                       + " second(s) [should equal " + sumMinutes(1, 1, 1, 0, 0) + "]");       //  61          [January 1, 0001 00:00:33
-> January 1, 0001 00:00]
    System.out.println("cast(12598052536 second(s), minutes)  = " + castSecondToMinute(12598052536L)
                       + " second(s) [should equal " + sumMinutes(400, 3, 20, 19, 2) + "]");   //  12597993661 [March 20, 0400 19:02:15
-> March 20, 0400 19:02]
    System.out.println("cast(34739152206 second(s), minutes)  = " + castSecondToMinute(34739152206L)
                       + " second(s) [should equal " + sumMinutes(1101, 11, 4, 12, 30) + "]"); //  62214393662 [November 4, 1101
12:30:05   -> November 4, 1101 12:30]
    System.out.println("cast(62214393601 second(s), minutes)  = " + castSecondToMinute(62214393601L)
                       + " second(s) [should equal " + sumMinutes(1972, 6, 30, 23, 59) + "]"); //  62230309023 [June 30, 1972 23:59:60
-> June 30, 1972 23:59]
    System.out.println("cast(62230309027 second(s), minutes)  = " + castSecondToMinute(62230309027L)
                       + " second(s) [should equal " + sumMinutes(1973, 1, 1, 4, 57) + "]");   //  62404645628 [January 1, 1973 4:57:04
-> January 1, 1973 4:57]
    System.out.println("cast(62404645639 second(s), minutes)  = " + castSecondToMinute(62404645639L)
                       + " second(s) [should equal " + sumMinutes(1978, 7, 11, 23, 47) + "]"); //  63199559963 [July 11, 1978 23:47:11
-> July 11, 1978 23:47]
    System.out.println("cast(63199559982 second(s), minutes)  = " + castSecondToMinute(63199559982L)
                       + " second(s) [should equal " + sumMinutes(2003, 9, 19, 9, 19) + "]");  //  63199559963 [September 19, 2003
09:19:19 -> September 19, 2003 09:19:19]

    // ********************** test splitMonths**********************


    System.out.println("\n********************** test splitMonths **********************");

    splitResults = splitMonths(1);
    System.out.println("1 month = " + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 1, 1]");

    splitResults = splitMonths(1200);
    System.out.println("1200 months = " + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 12, 100]");

    splitResults = splitMonths(24033);
    System.out.println("24033 months = " + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 9, 2003]");


    // ********************** test splitDays **********************

    System.out.println("\n********************** test splitDays **********************");

    splitResults = splitDays(1);
    System.out.println("1 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 1, 1, 1]");

    splitResults = splitDays(31);
    System.out.println("31 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 31, 1, 1]");

    splitResults = splitDays(364);
    System.out.println("364 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 30, 12, 1]");

    splitResults = splitDays(365);
    System.out.println("365 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 31, 12, 1]");

    splitResults = splitDays(1461);
    System.out.println("1461 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 31, 12, 4]");

    splitResults = splitDays(46);
    System.out.println("46 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 15, 2, 1]");

    splitResults = splitDays(36524);
    System.out.println("36524 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 31, 12, 100]");

    splitResults = splitDays(146097);
    System.out.println("146097 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 31, 12, 400]");

    splitResults = splitDays(145811);
    System.out.println("145811 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 20, 3, 400]");

    splitResults = splitDays(402074);
    System.out.println("402074 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 4, 11, 1101]");

    splitResults = splitDays(722276);
    System.out.println("722276 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 11, 7, 1978]");

    splitResults = splitDays(730365);
    System.out.println("730365 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 2, 9, 2000]");

    splitResults = splitDays(731477);
    System.out.println("731477 day = " + splitResults[DAY_INDEX] + " days(s), "
                       + splitResults[MONTH_INDEX] + " month(s), "
                       + splitResults[YEAR_INDEX] + " year(s) [should be 19, 9, 2003]");


    // ********************** test splitHours **********************

    System.out.println("\n********************** test splitHours **********************");

    splitResults = splitHours(1);
    System.out.println("1 hour = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 1, 1, 1]");

    splitResults = splitHours(729);
    System.out.println("729 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 9, 31, 1, 1]");

    splitResults = splitHours(8724);
    System.out.println("8724 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 12, 30, 12, 1]");

    splitResults = splitHours(8760);
    System.out.println("8760 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 24, 31, 12, 1]");

    splitResults = splitHours(35044);
    System.out.println("35044 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 4, 31, 12, 4]");

    splitResults = splitHours(26642);
    System.out.println("26642 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 2, 16, 1, 4]");

    splitResults = splitHours(1081);
    System.out.println("1081 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 1, 15, 2, 1]");

    splitResults = splitHours(876555);
    System.out.println("876555 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 3, 31, 12, 100]");

    splitResults = splitHours(3506308);
    System.out.println("3506308 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 4, 31, 12, 400]");

    splitResults = splitHours(9649757);
    System.out.println("9649757 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 5, 4, 11, 1101]");

    splitResults = splitHours(17334606);
    System.out.println("17334606 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 6, 11, 7, 1978]");

    splitResults = splitHours(17528743);
    System.out.println("17528743 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 7, 2, 9, 2000]");

    splitResults = splitHours(17555432);
    System.out.println("17555432 hours = " + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 8, 19, 9, 2003]");


    // ********************** test splitMinutes **********************

    System.out.println("\n********************** test splitMinutes **********************");

    splitResults = splitMinutes(1);
    System.out.println("1 minute = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 1, 1, 1, 1, 1]");

    splitResults = splitMinutes(43710);
    System.out.println("43710 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 30, 9, 31, 1, 1]");

    splitResults = splitMinutes(523385);
    System.out.println("523385 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 5, 12, 30, 12, 1]");

    splitResults = splitMinutes(525541);
    System.out.println("525541 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 1, 24, 31, 12, 1]");

    splitResults = splitMinutes(2103840);
    System.out.println("2103840 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 60, 24, 31, 12, 4]");

    splitResults = splitMinutes(1598506);
    System.out.println("1598506 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 46, 2, 16, 1, 4]");

    splitResults = splitMinutes(64836);
    System.out.println("64836 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 36, 1, 15, 2, 1]");

    splitResults = splitMinutes(52593248);
    System.out.println("52593248 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 8, 3, 31, 12, 100]");

    splitResults = splitMinutes(210378474);
    System.out.println("210378474 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 54, 4, 31, 12, 400]");

    splitResults = splitMinutes(578985365);
    System.out.println("578985365 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 5, 5, 4, 11, 1101]");

    splitResults = splitMinutes(1040076321);
    System.out.println("1040076321 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 21, 6, 11, 7, 1978]");

    splitResults = splitMinutes(1051724573);
    System.out.println("1051724573 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 53, 7, 2, 9, 2000]");

    splitResults = splitMinutes(1053325886);
    System.out.println("1053325886 minutes = " + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 26, 8, 19, 9, 2003]");


    splitResults = splitSeconds(1);
    System.out.println("1 second = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 1, 1, 1, 1, 1, 1]");

    splitResults = splitSeconds(2622570);
    System.out.println("2622570 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 30, 30, 9, 31, 1, 1]");

    splitResults = splitSeconds(31403045);
    System.out.println("31403045 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 5, 5, 12, 30, 12, 1]");

    splitResults = splitSeconds(31532401);
    System.out.println("31532401 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 1, 1, 24, 31, 12, 1]");

    splitResults = splitSeconds(126230390);
    System.out.println("126230390 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 50, 60, 24, 31, 12, 4]");

    splitResults = splitSeconds(95910346);
    System.out.println("95910346 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 46, 46, 2, 16, 1, 4]");

    splitResults = splitSeconds(3890136);
    System.out.println("3890136 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 36, 36, 1, 15, 2, 1]");

    splitResults = splitSeconds(3155594828l);
    System.out.println("3155594828 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 8, 8, 3, 31, 12, 100]");

    splitResults = splitSeconds(12622708434l);
    System.out.println("12622708434 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 54, 54, 4, 31, 12, 400]");

    splitResults = splitSeconds(34739121845l);
    System.out.println("34739121845 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 5, 5, 5, 4, 11, 1101]");
*/

    System.out.println("September 19, 2003 09:19:19 in seconds = " + sumSeconds(2003, 9, 19, 9, 19, 19));  //  63199559982

    splitResults = splitSeconds(63199559982l);
    System.out.println("63199559982 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y");
/*
    splitResults = splitSeconds(62404579221l);
    System.out.println("62404579221 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 14, 21, 6, 11, 7, 1978]");

    splitResults = splitSeconds(63103474373l);
    System.out.println("63103474373 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 31, 53, 7, 2, 9, 2000]");

    splitResults = splitSeconds(63199553126l);
    System.out.println("63199553126 seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 4, 26, 8, 19, 9, 2003]");

    splitResults = splitSeconds(sumSeconds(1993, 06, 30, 23, 59, 60));
    System.out.println(sumSeconds(1993, 06, 30, 23, 59, 60) + " seconds = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y [should be 61, 60, 24, 30, 6, 1993]");

    splitResults = splitSeconds(sumSeconds(2003, 9, 19, 8, 26, 4));
    System.out.println("September 19, 2003 08:26:4 in seconds = " + sumSeconds(2003, 9, 19, 8, 26, 4)
                       + " = " + splitResults[SECOND_INDEX] + "s, "
                       + splitResults[MINUTE_INDEX] + "mi, "
                       + splitResults[HOUR_INDEX] + "h, "
                       + splitResults[DAY_INDEX] + "d, "
                       + splitResults[MONTH_INDEX] + "m, "
                       + splitResults[YEAR_INDEX] + "y");

*/
  }
}



























