program dc_date_test
  use dc_types, only: STRING, DP, STDOUT
  use dc_test, only: AssertEqual
  use dc_string, only: StoA, Printf
  use dc_date, only: Create, Eval, Put_Line, &
    & operator(+), operator(-), operator(*), operator(/), mod, toChar, &
    & operator(<), operator(>), operator(==), &
    & EvalDay, EvalHour, EvalMin, EvalSec, EvalByUnit, &
    & ValidZone, ZoneToDiff, SetZone, SetSecOfDay
  use dc_date_types, only: DC_DATETIME, DC_DIFFTIME, &
    & CAL_NOLEAP, CAL_CYCLIC, CAL_JULIAN, day_seconds_default => day_seconds
  use dc_trace, only: SetDebug

  use dc_date, only: dcdate_normalize

  implicit none
  type(DC_DATETIME) :: time1, time2, time3, time4, time5, time6
  type(DC_DATETIME) :: time11, time12, time13
  type(DC_DIFFTIME) :: diff1, diff2, diff3, diff4, diff5, diff6, diff7
  type(DC_DIFFTIME) :: diff11, diff12, diff13
  integer:: year = 0, mon = 0, day = 0, hour = 0, min = 0
  real(DP) :: sec = 0.0_DP
  character(STRING) :: test_answer
continue

  call Create(time1)
  call Printf(STDOUT, 'Current time is %c', c1=trim(toChar(time1)))
  call Put_Line(time1)

  call Create(time2, year=2008, mon=2, day=29, hour=20, sec=1300.5d0, &
    & zone='+09:00', caltype=CAL_NOLEAP)
  call Put_Line(time2)
  call AssertEqual('DateTime (CAL_NOLEAP), Create/toChar test 1', &
    & '2008-03-01T20:21:40.5+09:00', toChar(time2))

  call Create(time3, year=1999, mon=11, day=13, hour=20, min=3, sec=1300.5d0)
  call Put_Line(time3)
  call Eval(time3, year=year, mon=mon, day=day, hour=hour, min=min, sec=sec)
  call AssertEqual('DateTime (CAL_GREGORIAN), Create/Eval test 1', &
    & (/1999, 11, 13, 20, 24/), (/year, mon, day, hour, min/))
  call AssertEqual('DateTime (CAL_GREGORIAN), Create/Eval test 2', &
    & (/40.5d0/), (/sec/))
  year = 0; mon = 0; day = 0; hour = 0; min = 0; sec = 0.0_DP

  call Create(time4, mon=0, day=1, sec=12096.0d0, caltype=CAL_CYCLIC)
  call Put_Line(time4)
  call AssertEqual('DateTime (CAL_CYCLIC), Create/EvalDay test 1', &
    & 114, nint(EvalDay(time4) * 100))
  call AssertEqual('DateTime (CAL_CYCLIC), Create/EvalHour test 1', &
    & 2736, nint(EvalHour(time4) * 100))
  call AssertEqual('DateTime (CAL_CYCLIC), Create/EvalMin test 1', &
    & 16416, nint(EvalMin(time4) * 10))
  call AssertEqual('DateTime (CAL_CYCLIC), Create/EvalSec test 1', &
    & 98496, nint(EvalSec(time4)))

  call AssertEqual('DateTime (CAL_CYCLIC), Create/EvalByUnit test 1', &
    & 114, nint(EvalByUnit(time4, '   day') * 100))
  call AssertEqual('DateTime (CAL_CYCLIC), Create/EvalByUnit test 2', &
    & 2736, nint(EvalByUnit(time4, 'HOUR') * 100))
  call AssertEqual('DateTime (CAL_CYCLIC), Create/EvalByUnit test 3', &
    & 16416, nint(EvalByUnit(time4, 'minutes') * 10))
  call AssertEqual('DateTime (CAL_CYCLIC), Create/EvalByUnit test 4', &
    & 98496, nint(EvalByUnit(time4, 'sec.')))

  call Create(diff1, mon=2, day=12, sec=100345.0d0)
  call AssertEqual('DiffTime, Create/toChar test 1', &
    & '0000-02-13T03:52:25', toChar(diff1))

  call Create(diff1, value=25.0d0, unit='  day')
  call AssertEqual('DiffTime, Create/toChar test 2', &
    & '0000-00-25T00:00:00', toChar(diff1))
  call Create(diff1, value=-25.0d0, unit='min')
  call AssertEqual('DiffTime, Create/toChar test 3', &
    & '0000-00-00T00:-25:00', toChar(diff1))
  call Create(diff1, value=25.0d0, unit='s')
  call AssertEqual('DiffTime, Create/toChar test 4', &
    & '0000-00-00T00:00:25', toChar(diff1))

  call Create(diff2, mon=0, day=1, sec=12096.0d0)
  call AssertEqual('DiffTime, Create/EvalDay test 1', &
    & 114, nint(EvalDay(diff2) * 100))
  call AssertEqual('DiffTime, Create/EvalHour test 1', &
    & 2736, nint(EvalHour(diff2) * 100))
  call AssertEqual('DiffTime, Create/EvalMin test 1', &
    & 16416, nint(EvalMin(diff2) * 10))
  call AssertEqual('DiffTime, Create/EvalSec test 1', &
    & 98496, nint(EvalSec(diff2)))

  call AssertEqual('DiffTime, Create/EvalByUnit test 1', &
    & 114, nint(EvalByUnit(diff2, '  d  ') * 100))
  call AssertEqual('DiffTime, Create/EvalByUnit test 2', &
    & 2736, nint(EvalByUnit(diff2, 'hrs.') * 100))
  call AssertEqual('DiffTime, Create/EvalByUnit test 3', &
    & 16416, nint(EvalByUnit(diff2, 'min') * 10))
  call AssertEqual('DiffTime, Create/EvalByUnit test 4', &
    & 98496, nint(EvalByUnit(diff2, 's')))


  call Create(diff3, mon=2, day=10, sec=1000.0d0)
  call Create(diff4, mon=1, day=5,  sec=500.0d0)
  call Create(time5, &
    & year=2006, mon=9, day=20, hour=1, min=3, sec=30.5d0, &
    & zone='+09:00')
  call Create(time6, &
    & year=2006, mon=11, day=13, hour=23, min=3, sec=20.5d0, &
    & zone='-10:00')

  call AssertEqual('Operator(+) test 1', &
    & '2006-11-30T01:20:10.5+09:00', toChar(diff3 + time5))
  call AssertEqual('Operator(+) test 2', &
    & '2006-11-30T01:20:10.5+09:00', toChar(time5 + diff3))
  call AssertEqual('Operator(+) test 3', &
    & '0000-03-15T00:25:00', toChar(diff3 + diff4))

  call AssertEqual('Operator(-) test 1', &
    & '0000-00-54T02:59:50', toChar(time6 - time5))
  call AssertEqual('Operator(-) test 2', &
    & '2006-09-03T22:46:40.5-10:00', toChar(time6 - diff3))

  test_answer = '0000-02-10T00:16:40'
  call AssertEqual('Operator(*) test 1', &
    & trim(test_answer), toChar(diff4 * 2))
  call AssertEqual('Operator(*) test 2', &
    & trim(test_answer), toChar(diff4 * 2.0))
  call AssertEqual('Operator(*) test 3', &
    & trim(test_answer), toChar(diff4 * 2.0d0))
  call AssertEqual('Operator(*) test 4', &
    & trim(test_answer), toChar(2 * diff4))
  call AssertEqual('Operator(*) test 5', &
    & trim(test_answer), toChar(2.0 * diff4))
  call AssertEqual('Operator(*) test 6', &
    & trim(test_answer), toChar(2.0d0 * diff4))

  test_answer = '0000-01-05T00:08:20'
  call AssertEqual('Operator(/) test 1', &
    & trim(test_answer), toChar(diff3 / 2))
  call AssertEqual('Operator(/) test 2', &
    & trim(test_answer), toChar(diff3 / 2.0))
  call AssertEqual('Operator(/) test 3', &
    & trim(test_answer), toChar(diff3 / 2.0d0))
  call AssertEqual('Operator(/) test 4', &
    & 2.0d0, diff3 / diff4)

  call AssertEqual('mod test 1', &
    & '0000-00-00T00:00:00', toChar(mod(diff3, diff4)))

  call Create(time12, year=2008, mon=2, day=29, hour=19, sec=1300.5d0, &
    & zone='+09:00')
  call Create(time13, year=2008, mon=2, day=29, hour=20, sec=1300.5d0, &
    & zone='-13:00')

  call Create(diff5, day=10, hour=869, sec=1300.5d0)
  call Create(diff6, day=29, hour=20, sec=10.0d0)
  diff7 = diff5 - diff6

  call AssertEqual('Operator(>) test 1', .true., time1 > time3)
  call AssertEqual('Operator(>) test 2', .false., time13 > time12)
  call AssertEqual('Operator(>) test 3', .true., diff5 > diff6)
  call AssertEqual('Operator(<) test 1', .false., time1 < time3)
  call AssertEqual('Operator(<) test 2', .true., time13 < time12)
  call AssertEqual('Operator(<) test 3', .false., diff5 < diff6)
  call AssertEqual('Operator(==) test 1', .false., time13 == time12)

  call Create(time13, year=2008, mon=2, day=29, hour=19, sec=1300.5d0, &
    & zone='+09:00')
  call AssertEqual('Operator(==) test 2', .true., time13 == time12)
  call AssertEqual('Operator(==) test 3', .false., diff5 == diff6)
  call AssertEqual('Operator(==) test 4', .true., diff5 == diff6 + diff7)
  call AssertEqual('Operator(==) test 5', .false., diff5 == 0.0d0)
  call AssertEqual('Operator(==) test 6', .true., 3993700.5d0 == diff5)
  call AssertEqual('Operator(==) test 7', .true., diff5 - diff6 - diff7 == 0.0)
  call AssertEqual('Operator(==) test 8', .true., 0 == diff5 - diff6 - diff7)


  call AssertEqual('ValidZone test 1', .true., ValidZone('+09:00'))
  call AssertEqual('ValidZone test 2', .false., ValidZone('+0900'))
  call AssertEqual('ValidZone test 3', .false., ValidZone(' 13:00'))
  call AssertEqual('ValidZone test 4', .false., ValidZone('1'))

  call AssertEqual('ZoneToDiff test 1', '0000-00-00T-12:00:00', &
    & toChar(ZoneToDiff('-12:00')))
  call AssertEqual('ZoneToDiff test 1', '0000-00-00T00:00:00', &
    & toChar(ZoneToDiff('aaaa')))


  call Create(time11, &
    & year=2006, mon=11, day=13, hour=20, min=3, sec=20.0d0, &
    & zone='+09:00')
  call SetZone(time11, '-13:00')
  call AssertEqual('SetZone test 1', &
    & '2006-11-12T22:03:20-13:00', toChar(time11))

  call Create(diff11, mon=1, day=2, sec=80100.0d0, day_seconds=40000.0d0)
  call Create(diff12, mon=1, day=2, sec=172900.0d0)
  call SetSecOfDay(172800.0d0)
  call Create(diff13, mon=1, day=2, sec=345700.0d0)
  call SetSecOfDay(day_seconds_default)

  call AssertEqual('DiffTime, Create with day_seconds test 1', &
    & '0000-01-04T00:01:40', toChar(diff11))
  call AssertEqual('DiffTime, Create with day_seconds test 2', &
    & '0000-01-04T00:01:40', toChar(diff12))
  call AssertEqual('DiffTime, Create/SetSecOfDay test 1', &
    & '0000-01-04T00:01:40', toChar(diff13))


end program dc_date_test
