/*
 * DateTimeRangeTest class.
 *
 * Copyright (C) 2007 SATOH Takayuki All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package ts.util;

import ts.tester.function.coverage.FunctionTester;
import ts.tester.function.print.*;
import java.util.*;

/**
 * <code>DateTimeRange</code>クラスの機能試験クラス。
 *
 * @author  佐藤隆之. 
 * @version $Revision: 1.1.1.1 $, $Date: 2010-10-16 00:03:44 $
 */
public class DateTimeRangeTest extends FunctionTester
{
  public static void main(String[] args)
  {
    try {
      PrinterGroup group = new PrinterGroup();
      group.addPrinter(new ConsolePrinter());
      group.addPrinter(new HtmlPrinter("SATOH Takayuki"));
      setPrinter(group);

      run(DateTimeRangeTest.class, (args.length == 0) ? null : args[0]);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  /* -- test case -- */

  public void constructor_dttm1_dttm2()
  {
    MSG("通常の操作");

    DateTime dttm1 = new DateTime(2006, 5, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 5, 11, 22, 33, 44);
    DateTimeRange rng = new DateTimeRange(dttm1, dttm2);
    EQUAL(rng.getStart(), dttm1);
    EQUAL(rng.getEnd(), dttm2);

    Calendar cal = new GregorianCalendar(
      TimeZone.getTimeZone("America/Los_Angeles"));
    DateTime dttm21 = new DateTime(cal);
    dttm21.setDateTime(2006, 5, 10, 11, 22, 33);
    DateTime dttm22 = new DateTime(cal);
    dttm22.setDateTime(2006, 5, 11, 22, 33, 44);
    DateTimeRange rng2 = new DateTimeRange(dttm21, dttm22);
    EQUAL(rng2.getStart(), dttm21);
    EQUAL(rng2.getEnd(), dttm22);
  }

  public void constructor_dttm1_dttm2_1()
  {
    MSG("引数がヌルの場合");
    DateTime dttm1 = new DateTime(2006, 5, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 5, 11, 22, 33, 44);

    try {
      DateTimeRange rng = new DateTimeRange(null, null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      DateTimeRange rng = new DateTimeRange(null, dttm2);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      DateTimeRange rng = new DateTimeRange(dttm1, null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void set_dttm1_dttm2()
  {
    MSG("通常の操作");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    DateTime dttm1 = new DateTime(2006, 5, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 5, 11, 22, 33, 44);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.getStart(), dttm1);
    EQUAL(rng.getEnd(), dttm2);

    Calendar cal = new GregorianCalendar(
      TimeZone.getTimeZone("America/Los_Angeles"));
    DateTime dttm21 = new DateTime(cal);
    dttm21.setDateTime(2006, 5, 10, 11, 22, 33);
    DateTime dttm22 = new DateTime(cal);
    dttm22.setDateTime(2006, 5, 11, 22, 33, 44);
    rng.setRange(dttm21, dttm22);
    EQUAL(rng.getStart(), dttm21);
    EQUAL(rng.getEnd(), dttm22);
  }

  public void set_dttm1_dttm2_1()
  {
    MSG("引数がヌルの場合");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    DateTime dttm1 = new DateTime(2006, 5, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 5, 11, 22, 33, 44);

    try {
      rng.setRange(null, null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      rng.setRange(null, dttm2);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      rng.setRange(dttm1, null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void set_dttm1_dttm2_2()
  {
    MSG("二つの日時のカレンダが異なる場合");

    Calendar cal = new GregorianCalendar(
      TimeZone.getTimeZone("America/Los_Angeles"));
    DateTime dttm21 = new DateTime(2006, 5, 10, 11, 22, 33);
    DateTime dttm22 = new DateTime(cal);
    dttm22.setDateTime(2006, 5, 11, 22, 33, 44);

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    try {
      rng.setRange(dttm21, dttm22);
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getStart_getEnd()
  {
    MSG("設定時において日時1＜日時2");
    DateTime dttm01 = new DateTime(2006, 5, 10, 11, 22, 33);
    DateTime dttm02 = new DateTime(2006, 5, 11, 22, 33, 44);
    DateTimeRange rng0 = new DateTimeRange(dttm01, dttm02);
    EQUAL(rng0.getStart(), dttm01);
    EQUAL(rng0.getEnd(), dttm02);

    MSG("設定時において日時1＞日時2");
    DateTime dttm11 = new DateTime(2006, 5, 20, 11, 22, 33);
    DateTime dttm12 = new DateTime(2006, 4, 11, 22, 33, 44);
    DateTimeRange rng1 = new DateTimeRange(dttm11, dttm12);
    EQUAL(rng1.getStart(), dttm12);
    EQUAL(rng1.getEnd(), dttm11);

    MSG("設定時において日時1＝日時2");
    DateTime dttm21 = new DateTime(2006, 5, 30, 12, 34, 56);
    DateTime dttm22 = new DateTime(2006, 5, 30, 12, 34, 56);
    DateTimeRange rng2 = new DateTimeRange(dttm21, dttm22);
    EQUAL(rng2.getStart(), dttm21);
    EQUAL(rng2.getStart(), dttm22);
    EQUAL(rng2.getEnd(), dttm21);
    EQUAL(rng2.getEnd(), dttm22);
  }

  public void intervalInYear()
  {
    MSG("通常の操作");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.intervalInYear(), 0);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 5, 9));
    EQUAL(rng.intervalInYear(), 1);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 5, 10));
    EQUAL(rng.intervalInYear(), 1);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 5, 11));
    EQUAL(rng.intervalInYear(), 0);

    rng.setRange(new DateTime(2000, 5, 10), new DateTime(2006, 6, 1));
    EQUAL(rng.intervalInYear(), 6);

    rng.setRange(new DateTime(2000, 5, 10), new DateTime(2006, 5, 1));
    EQUAL(rng.intervalInYear(), 5);
  }

  public void countYears()
  {
    MSG("通常の操作");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.countYears(), 1);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 5, 9));
    EQUAL(rng.countYears(), 2);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 5, 10));
    EQUAL(rng.countYears(), 2);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 5, 11));
    EQUAL(rng.countYears(), 2);

    rng.setRange(new DateTime(2000, 5, 10), new DateTime(2006, 6, 1));
    EQUAL(rng.countYears(), 7);

    rng.setRange(new DateTime(2000, 5, 10), new DateTime(2006, 5, 1));
    EQUAL(rng.countYears(), 7);
  }

  public void intervalInMonth()
  {
    MSG("通常の操作");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.intervalInMonth(), 0);

    DateTime dttm01 = new DateTime(2006, 4, 10, 1, 2, 3);
    DateTime dttm02 = new DateTime(2006, 4, 10, 1, 2, 3);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInMonth(), 0);
    dttm02.addSecond(-1);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInMonth(), 0);
    dttm02.addSecond(2);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInMonth(), 0);

    DateTime dttm11 = new DateTime(2006, 4, 10, 1, 2, 3);
    DateTime dttm12 = new DateTime(2006, 5, 10, 1, 2, 3);
    rng.setRange(dttm11, dttm12);
    EQUAL(rng.intervalInMonth(), 1);
    dttm12.addSecond(-1);
    rng.setRange(dttm11, dttm12);
    EQUAL(rng.intervalInMonth(), 0);
    dttm12.addSecond(2);
    rng.setRange(dttm11, dttm12);
    EQUAL(rng.intervalInMonth(), 1);

    DateTime dttm21 = new DateTime(2006, 4, 10, 1, 2, 3);
    DateTime dttm22 = new DateTime(2007, 4, 10, 1, 2, 3);
    rng.setRange(dttm21, dttm22);
    EQUAL(rng.intervalInMonth(), 12);
    dttm22.addSecond(-1);
    rng.setRange(dttm21, dttm22);
    EQUAL(rng.intervalInMonth(), 11);
    dttm22.addSecond(2);
    rng.setRange(dttm21, dttm22);
    EQUAL(rng.intervalInMonth(), 12);

    DateTime dttm31 = new DateTime(2006, 3, 10, 1, 2, 3);
    DateTime dttm32 = new DateTime(2007, 8, 16, 11, 22, 33);
    rng.setRange(dttm31, dttm32);
    EQUAL(rng.intervalInMonth(), 17);
    dttm32.addDay(-6);
    rng.setRange(dttm31, dttm32);
    EQUAL(rng.intervalInMonth(), 17);
    dttm32.addDay(-1);
    rng.setRange(dttm31, dttm32);
    EQUAL(rng.intervalInMonth(), 16);
    dttm32.addMonth(-5);
    rng.setRange(dttm31, dttm32);
    EQUAL(rng.intervalInMonth(), 11);
  }

  static class GregorianCalendarEx extends GregorianCalendar {
    static final long serialVersionUID = 0L;
    public void complete() { super.complete(); }
    public void computeFields() { super.computeFields(); }
    public void computeTime() { super.computeTime(); }
  }
  static class MyCalendar extends Calendar {
    static final long serialVersionUID = 0L;
    private GregorianCalendarEx inner_ = new GregorianCalendarEx();
    public void add(int f, int a) { inner_.add(f, a); }
    public boolean after(Object w) { return inner_.after(w); }
    public boolean before(Object w) { return inner_.before(w); }
    public Object clone() {
      MyCalendar mcal = new MyCalendar();
      mcal.inner_ = (GregorianCalendarEx) inner_.clone();
      return mcal;
    }
    public int compareTo(Calendar c) { return inner_.compareTo(c); }
    protected void complete() { inner_.complete(); }
    protected void computeFields() { inner_.computeFields(); }
    protected void computeTime() { inner_.computeTime(); }
    public boolean equals(Object o) {
      try {
        return inner_.equals(((MyCalendar)o).inner_);
      } catch (Exception e) {
        return false;
      }
    }
    public int get(int f) { return inner_.get(f); }
    public int getActualMaximum(int f) { return inner_.getActualMaximum(f); }
    public int getActualMinimum(int f) { return inner_.getActualMinimum(f); }
    public int getFirstDayOfWeek() { return inner_.getFirstDayOfWeek(); }
    public int getGreatestMinimum(int f){return inner_.getGreatestMinimum(f);}
    public int getLeastMaximum(int f) { return inner_.getLeastMaximum(f); }
    public int getMaximum(int f) { return inner_.getMaximum(f); }
    public int getMinimalDaysInFirstWeek() {
      return inner_.getMinimalDaysInFirstWeek();
    }
    public int getMinimum(int f) { return inner_.getMinimum(f); }
    public long getTimeInMillis() { return inner_.getTimeInMillis(); }
    public TimeZone getTimeZone() { return inner_.getTimeZone(); }
    public int hashCode() { return inner_.hashCode(); }
    public boolean isLenient() { return inner_.isLenient(); }
    public void roll(int f, boolean u) { inner_.roll(f, u); }
    public void roll(int f, int a) { inner_.roll(f, a); }
    public void set(int f, int v) { inner_.set(f, v); }
    public void setFirstDayOfWeek(int v) { inner_.setFirstDayOfWeek(v); }
    public void setLenient(boolean b) { inner_.setLenient(b); }
    public void setMinimalDaysInFirstWeek(int v) 
      {inner_.setMinimalDaysInFirstWeek(v); }
    public void setTimeInMillis(long m) { inner_.setTimeInMillis(m); }
    public void setTimeZone(TimeZone tz) { inner_.setTimeZone(tz); }
    public String toString() { return inner_.toString(); }
  };

  public void intervalInMonth_1()
  {
    MSG("カレンダがGregorianCalendarではない場合");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());

    Calendar cal = new MyCalendar();
    DateTime dttm1 = new DateTime(cal);
    DateTime dttm2 = new DateTime(cal);

    dttm1.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm2.setDateTime(2006, 4, 10, 1, 2, 3);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 0);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 0);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 0);

    dttm1.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm2.setDateTime(2006, 5, 10, 1, 2, 3);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 1);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 0);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 1);

    dttm1.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm2.setDateTime(2007, 4, 10, 1, 2, 3);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 12);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 11);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 12);

    dttm1.setDateTime(2006, 3, 10, 1, 2, 3);
    dttm2.setDateTime(2007, 8, 16, 11, 22, 33);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 17);
    dttm2.addDay(-6);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 17);
    dttm2.addDay(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 16);
    dttm2.addMonth(-5);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMonth(), 11);
  }

  public void countMonths()
  {
    MSG("通常の操作");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.countMonths(), 1);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 5, 9));
    EQUAL(rng.countMonths(), 13);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 5, 10));
    EQUAL(rng.countMonths(), 13);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2005, 4, 11));
    EQUAL(rng.countMonths(), 14);

    rng.setRange(new DateTime(2000, 5, 10), new DateTime(2006, 6, 1));
    EQUAL(rng.countMonths(), 74);

    rng.setRange(new DateTime(2000, 5, 10), new DateTime(2006, 4, 1));
    EQUAL(rng.countMonths(), 72);
  }

  public void countMonths_1()
  {
    MSG("カレンダがGregorianCalendarではない場合");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());

    Calendar cal = new MyCalendar();
    DateTime dttm1 = new DateTime(cal);
    DateTime dttm2 = new DateTime(cal);

    dttm1.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm2.setDateTime(2006, 4, 10, 1, 2, 3);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 1);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 1);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 1);

    dttm1.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm2.setDateTime(2006, 5, 10, 1, 2, 3);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 2);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 2);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 2);

    dttm1.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm2.setDateTime(2007, 4, 10, 1, 2, 3);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 13);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 13);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 13);

    dttm1.setDateTime(2006, 3, 10, 1, 2, 3);
    dttm2.setDateTime(2007, 8, 16, 11, 22, 33);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 18);
    dttm2.addDay(-6);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 18);
    dttm2.addDay(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 18);
    dttm2.addMonth(-5);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMonths(), 13);
  }

  public void intervalInDay()
  {
    MSG("通常の操作");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.intervalInDay(), 0);

    DateTime dttm01 = new DateTime(2006, 4, 10, 1, 2, 3);
    DateTime dttm02 = new DateTime(2006, 4, 10, 1, 2, 3);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 0);
    dttm02.addSecond(-1);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 0);
    dttm02.addSecond(2);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 0);

    dttm01.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm02.setDateTime(2006, 4, 11, 1, 2, 3);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 1);
    dttm02.addSecond(-1);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 0);
    dttm02.addSecond(2);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 1);

    dttm01.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm02.setDateTime(2006, 5, 10, 1, 2, 3);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 30);
    dttm02.addSecond(-1);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 29);
    dttm02.addSecond(2);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 30);

    dttm01.setDateTime(2006, 5, 10, 1, 2, 3);
    dttm02.setDateTime(2006, 6, 10, 1, 2, 3);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 31);
    dttm02.addSecond(-1);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 30);
    dttm02.addSecond(2);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 31);

    dttm01.setDateTime(2006, 4, 10, 1, 2, 3);
    dttm02.setDateTime(2007, 4, 10, 1, 2, 3);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 365);
    dttm02.addSecond(-1);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 364);
    dttm02.addSecond(2);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 365);
  }

  public void intervalInDay_1()
  {
    MSG("閏年をはさむ場合");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.intervalInDay(), 0);

    DateTime dttm01 = new DateTime(2006, 4, 10, 1, 2, 3);
    DateTime dttm02 = new DateTime(2003, 4, 10, 1, 2, 3);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 365*3+1);
    dttm01.addSecond(-1);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 365*3);
    dttm01.addSecond(2);
    rng.setRange(dttm01, dttm02);
    EQUAL(rng.intervalInDay(), 365*3+1);
  }

  public void countDays()
  {
    MSG("通常の操作");
    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.countDays(), 1);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2006, 5, 9));
    EQUAL(rng.countDays(), 2);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2006, 5, 10));
    EQUAL(rng.countDays(), 1);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2006, 4, 11));
    EQUAL(rng.countDays(), 30);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2006, 6, 1));
    EQUAL(rng.countDays(), 23);

    rng.setRange(new DateTime(2006, 5, 10), new DateTime(2006, 4, 1));
    EQUAL(rng.countDays(), 40);
  }

  public void intervalInHour()
  {
    MSG("通常の場合");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.intervalInHour(), 0);

    DateTime dttm1 = new DateTime(2006, 4, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 4, 15, 11, 22, 33);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInHour(), 5*24);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInHour(), 5*24-1);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInHour(), 5*24);
  }

  public void countHours()
  {
    MSG("通常の場合");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.countHours(), 1);

    DateTime dttm1 = new DateTime(2006, 4, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 4, 15, 11, 22, 33);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countHours(), 5*24+1);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countHours(), 5*24+1);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countHours(), 5*24+1);
  }

  public void intervalInMinute()
  {
    MSG("通常の場合");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.intervalInMinute(), 0);

    DateTime dttm1 = new DateTime(2006, 4, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 4, 10, 13, 22, 33);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMinute(), 60*2);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMinute(), 60*2-1);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInMinute(), 60*2);
  }

  public void countMinutes()
  {
    MSG("通常の場合");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.countMinutes(), 1);

    DateTime dttm1 = new DateTime(2006, 4, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 4, 10, 13, 22, 33);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMinutes(), 60*2+1);
    dttm2.addSecond(-1);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMinutes(), 60*2+1);
    dttm2.addSecond(2);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countMinutes(), 60*2+1);
  }

  public void intervalInSecond()
  {
    MSG("通常の場合");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.intervalInSecond(), 0);

    DateTime dttm1 = new DateTime(2006, 4, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 4, 10, 11, 22, 53);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInSecond(), 20);
    dttm2.setDateTime(dttm2.getDateTimeMillis() - 1L);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInSecond(), 19);
    dttm2.setDateTime(dttm2.getDateTimeMillis() + 2L);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.intervalInSecond(), 20);
  }

  public void countSeconds()
  {
    MSG("通常の場合");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    EQUAL(rng.countSeconds(), 1);
    
    DateTime dttm1 = new DateTime(2006, 4, 10, 11, 22, 33);
    DateTime dttm2 = new DateTime(2006, 4, 10, 11, 22, 53);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countSeconds(), 21);
    dttm1.setDateTime(dttm1.getDateTimeMillis() + 1L);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countSeconds(), 21);
    dttm2.setDateTime(dttm2.getDateTimeMillis() + 2L);
    rng.setRange(dttm1, dttm2);
    EQUAL(rng.countSeconds(), 21);
  }

  public void encompass()
  {
    MSG("通常の場合");
    DateTime dttmS = new DateTime(2006, 2, 10);
    DateTime dttmE = new DateTime(2006, 4, 10);
    dttmE.setEndTimeOfDay();
    DateTimeRange rng = new DateTimeRange(dttmS, dttmE);

    DateTime dttm0 = new DateTime(2006, 3, 10);
    TRUE(rng.encompass(dttm0));
    DateTime dttm1 = new DateTime(2006, 2, 10);
    TRUE(rng.encompass(dttm1));
    DateTime dttm2 = new DateTime(2006, 4, 10);
    TRUE(rng.encompass(dttm2));
    DateTime dttm3 = new DateTime(2006, 2, 9);
    FALSE(rng.encompass(dttm3));
    DateTime dttm4 = new DateTime(2006, 4, 11);
    FALSE(rng.encompass(dttm4));
  }

  public void encompass_1()
  {
    MSG("引数がヌルの場合");
    DateTime dttmS = new DateTime(2006, 2, 10);
    DateTime dttmE = new DateTime(2006, 4, 10);
    dttmE.setEndTimeOfDay();
    DateTimeRange rng = new DateTimeRange(dttmS, dttmE);

    try {
      rng.encompass((DateTime) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void encompass_2()
  {
    MSG("引数の日時のカレンダが異なる場合");
    DateTime dttmS = new DateTime(2006, 2, 10);
    DateTime dttmE = new DateTime(2006, 4, 10);
    dttmE.setEndTimeOfDay();
    DateTimeRange rng = new DateTimeRange(dttmS, dttmE);

    Calendar cal = new GregorianCalendar(
      TimeZone.getTimeZone("America/Los_Angeles"));

    try {
      DateTime dttm = new DateTime(cal);
      rng.encompass(dttm);
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void encompass_DateTimeRange()
  {
    MSG("通常の操作");
    DateTimeRange rng0 = new DateTimeRange(
      new DateTime(2006, 04, 10), new DateTime(2006, 05, 10));

    DateTimeRange rng1 = new DateTimeRange(
      new DateTime(2006, 4, 11), new DateTime(2006, 5, 9));
    TRUE(rng0.encompass(rng1));
    FALSE(rng1.encompass(rng0));

    DateTimeRange rng2 = new DateTimeRange(
      new DateTime(2006, 5, 9), new DateTime(2006, 4, 9));
    FALSE(rng0.encompass(rng2));
    FALSE(rng2.encompass(rng0));
  }

  public void encompass_DateTimeRange_1()
  {
    MSG("引数がヌルの場合");
    DateTimeRange rng = new DateTimeRange(
      new DateTime(2006, 1, 2), new DateTime(2006, 2, 10));
    try {
      rng.encompass((DateTimeRange) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void encompass_DateTimeRange_2()
  {
    MSG("引数の日時のカレンダが異なる場合");
    Calendar cal = new GregorianCalendar(
      TimeZone.getTimeZone("America/Los_Angeles"));

    DateTime dttm01 = new DateTime(2004, 2, 10);
    DateTime dttm02 = new DateTime(2004, 4, 10);
    DateTime dttm11 = new DateTime(cal);
    DateTime dttm12 = new DateTime(cal);
    dttm11.setDateTime(2004, 2, 11);
    dttm12.setDateTime(2004, 4, 9);

    DateTimeRange rng0 = new DateTimeRange(dttm01, dttm02);
    DateTimeRange rng1 = new DateTimeRange(dttm11, dttm12);
    try {
      rng0.encompass(rng1);
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    } catch (Exception e) {
      OK(e);
    }
  }

  public void intersectsWith()
  {
    MSG("通常の場合");

    DateTimeRange rng = new DateTimeRange(
      new DateTime(2006,5,10), new DateTime(2006,10,20));
    DateTimeRange rng00 = rng.intersectsWith(rng);
    EQUAL(rng00.getStart(), rng.getStart());
    EQUAL(rng00.getEnd(), rng.getEnd());

    DateTimeRange rng1 = new DateTimeRange(
      new DateTime(2006, 7, 5), new DateTime(2006, 6, 2));
    DateTimeRange rng2 = new DateTimeRange(
      new DateTime(2006,10, 2), new DateTime(2006, 11, 5));
    DateTimeRange rng3 = new DateTimeRange(
      new DateTime(2006, 5, 2), new DateTime(2006, 6, 5));

    DateTimeRange rng01 = rng.intersectsWith(rng1);
    EQUAL(rng01.getStart(), new DateTime(2006,6,2));
    EQUAL(rng01.getEnd(),   new DateTime(2006,7,5));
    DateTimeRange rng10 = rng1.intersectsWith(rng);
    EQUAL(rng10.getStart(), new DateTime(2006,6,2));
    EQUAL(rng10.getEnd(),   new DateTime(2006,7,5));

    DateTimeRange rng02 = rng.intersectsWith(rng2);
    EQUAL(rng02.getStart(), new DateTime(2006,10, 2));
    EQUAL(rng02.getEnd()  , new DateTime(2006,10,20));
    DateTimeRange rng20 = rng2.intersectsWith(rng);
    EQUAL(rng20.getStart(), new DateTime(2006,10, 2));
    EQUAL(rng20.getEnd()  , new DateTime(2006,10,20));

    DateTimeRange rng03 = rng.intersectsWith(rng3);
    EQUAL(rng03.getStart(), new DateTime(2006,5,10));
    EQUAL(rng03.getEnd()  , new DateTime(2006,6,5));
    DateTimeRange rng30 = rng3.intersectsWith(rng);
    EQUAL(rng30.getStart(), new DateTime(2006,5,10));
    EQUAL(rng30.getEnd()  , new DateTime(2006,6,5));
  }

  public void intersectsWith_1()
  {
    MSG("引数がヌルの場合");

    DateTimeRange rng = new DateTimeRange(new DateTime(), new DateTime());
    try {
      rng.intersectsWith(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void intersectsWith_2()
  {
    MSG("カレンダが異なる場合");
    Calendar cal = new GregorianCalendar(
      TimeZone.getTimeZone("America/Los_Angeles"));

    DateTime dttm1S = new DateTime(cal);
    DateTime dttm1E = new DateTime(cal);
    DateTimeRange range1 = new DateTimeRange(dttm1S, dttm1E);

    DateTimeRange range2 = new DateTimeRange(new DateTime(), new DateTime());
    try {
      range1.intersectsWith(range2);
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      range2.intersectsWith(range1);
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void intersectsWith_3()
  {
    MSG("重なる範囲がない場合");

    DateTimeRange rng = new DateTimeRange(
      new DateTime(2006,5,10), new DateTime(2006,6,10));
    DateTimeRange rng1 = new DateTimeRange(
      new DateTime(2006,4,10), new DateTime(2006,5,8));
    DateTimeRange rng2 = new DateTimeRange(
      new DateTime(2006, 6, 12), new DateTime(2006,7,10));

    DateTimeRange rng01 = rng.intersectsWith(rng1);
    NULL(rng01);
    DateTimeRange rng10 = rng1.intersectsWith(rng);
    NULL(rng01);

    DateTimeRange rng02 = rng.intersectsWith(rng2);
    NULL(rng02);
    DateTimeRange rng20 = rng2.intersectsWith(rng);
    NULL(rng20);
  }

  public void try_countDays_except_holidays()
  {
    MSG("休日を除いた日数を取得する");
    DateTime today = new DateTime(2006, 5, 18);
    DateTime start = new DateTime(today);
    start.setStartDayOfMonth();
    DateTime end = new DateTime(today);
    end.setEndDayOfMonth();
    DateTimeRange rng = new DateTimeRange(start, end);
    EQUAL(rng.countDays(), 31);

    DateTime[] holidays = new DateTime[13];
    int i = -1;
    holidays[++i] = new DateTime(2006, 4, 30);
    holidays[++i] = new DateTime(2006, 5,  3);
    holidays[++i] = new DateTime(2006, 5,  4);
    holidays[++i] = new DateTime(2006, 5,  5);
    holidays[++i] = new DateTime(2006, 5,  6);
    holidays[++i] = new DateTime(2006, 5,  7);
    holidays[++i] = new DateTime(2006, 5, 13);
    holidays[++i] = new DateTime(2006, 5, 14);
    holidays[++i] = new DateTime(2006, 5, 20);
    holidays[++i] = new DateTime(2006, 5, 21);
    holidays[++i] = new DateTime(2006, 5, 27);
    holidays[++i] = new DateTime(2006, 5, 28);
    holidays[++i] = new DateTime(2006, 6,  3);

    int cntDays = rng.countDays();
    for (i=0; i<holidays.length; i++) {
      if (rng.encompass(holidays[i])) {
        cntDays -- ;
      }
    }
    EQUAL(cntDays, 20);
  }

  public void expandsWith_dttm()
  {
    MSG("引数の日時で範囲を拡張するメソッドの確認。");

    DateTimeRange range = new DateTimeRange(
      new DateTime(2006, 1, 1), new DateTime(2006,12,31));
    
    DateTimeRange rng01 = range.expandsWith(new DateTime(2007, 4, 30));
    EQUAL(rng01.getStart(), new DateTime(2006, 1, 1));
    EQUAL(rng01.getEnd()  , new DateTime(2007, 4,30));

    DateTimeRange rng02 = range.expandsWith(new DateTime(2005, 10, 10));
    EQUAL(rng02.getStart(), new DateTime(2005, 10, 10));
    EQUAL(rng02.getEnd()  , new DateTime(2006, 12, 31));

    DateTimeRange rng03 = range.expandsWith(new DateTime(2006, 5, 5));
    EQUAL(rng03.getStart(), new DateTime(2006, 1, 1));
    EQUAL(rng03.getEnd()  , new DateTime(2006, 12, 31));
  }

  public void expandsWith_dttm_0()
  {
    MSG("引数がヌルの場合。");

    DateTimeRange range = new DateTimeRange(new DateTime(), new DateTime());
    try {
      range.expandsWith((DateTime) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void expandsWith_DateTimeRange()
  {
    MSG("引数の範囲で範囲を拡張するメソッドの確認。");

    DateTimeRange range = new DateTimeRange(
      new DateTime(2006,1,1), new DateTime(2006,12,31));
    EQUAL(range.expandsWith(range), range);

    DateTimeRange rng01 = new DateTimeRange(
      new DateTime(2005,11,12), new DateTime(2006,2,3));
    EQUAL(range.expandsWith(rng01), new DateTimeRange(
      new DateTime(2005,11,12), new DateTime(2006,12,31)));

    DateTimeRange rng02 = new DateTimeRange(
      new DateTime(2006,11,12), new DateTime(2007,2,3));
    EQUAL(range.expandsWith(rng02), new DateTimeRange(
      new DateTime(2006,1,1), new DateTime(2007,2,3)));

    DateTimeRange rng03 = new DateTimeRange(
      new DateTime(2005,11,12), new DateTime(2007,2,3));
    EQUAL(range.expandsWith(rng03), new DateTimeRange(
      new DateTime(2005,11,12), new DateTime(2007,2,3)));

    DateTimeRange rng04 = new DateTimeRange(
      new DateTime(2005,11,12), new DateTime(2005,12,11));
    EQUAL(range.expandsWith(rng04), new DateTimeRange(
      new DateTime(2005,11,12), new DateTime(2006,12,31)));

    DateTimeRange rng05 = new DateTimeRange(
      new DateTime(2007,11,12), new DateTime(2007,12,11));
    EQUAL(range.expandsWith(rng05), new DateTimeRange(
      new DateTime(2006,1,1), new DateTime(2007,12,11)));
  }

  public void try_countHours_except_resttime()
  {
    MSG("休憩時間を除いた勤務時間を取得する");

    DateTimeRange rngBe = new DateTimeRange(
      new DateTime(2006,5,10,8,57,22), new DateTime(2006,5,10,19,20,33));

    List<DateTimeRange> restLst = new ArrayList<DateTimeRange>();
    restLst.add(new DateTimeRange(
      new DateTime(2006,5,10,12,0,0), new DateTime(2006,5,10,12,45,0)));
    restLst.add(new DateTimeRange(
      new DateTime(2006,5,10,18,0,0), new DateTime(2006,5,10,18,30,0)));
    restLst.add(new DateTimeRange(
      new DateTime(2006,5,10,21,0,0), new DateTime(2006,5,10,21,30,0)));
    
    DateTime dttmS = rngBe.getStart();
    dttmS.ceilMinute(15);
    {
      DateTime dttmS1 = rngBe.getStart();
      FALSE(dttmS1.equals(dttmS));

      int hS = dttmS1.getHour();
      int mS = dttmS1.getMinute();
      mS = 60-((60-mS)/15)*15;
      dttmS1.setStartTimeOfDay();
      dttmS1.addHour(hS);
      dttmS1.addMinute(mS);
      EQUAL(dttmS1, dttmS);
    }

    DateTime dttmE = rngBe.getEnd();
    dttmE.floorMinute(15);
    {
      DateTime dttmE1 = rngBe.getEnd();
      FALSE(dttmE1.equals(dttmE));

      int hE = dttmE1.getHour();
      int mE = dttmE1.getMinute();
      mE = (mE/15)*15;
      dttmE1.setStartTimeOfDay();
      dttmE1.addHour(hE);
      dttmE1.addMinute(mE);
      EQUAL(dttmE1, dttmE);
    }

    OK("Before:" + rngBe.getStart() + " - " + rngBe.getEnd());
    rngBe.setRange(dttmS, dttmE);
    OK("After :" + rngBe.getStart() + " - " + rngBe.getEnd());

    long worktime = rngBe.intervalInMinute();
    EQUAL(worktime, 615);
    for (int i=0; i<restLst.size(); i++) {
      DateTimeRange r = rngBe.intersectsWith(restLst.get(i));
      if (r != null) {
        OK(r.getStart() + " - " + r.getEnd());
        worktime -= r.intervalInMinute();
      }
    }
    EQUAL(worktime, 615-45-30);
  }
}
