
define double mjdtol sectol radtol
let mjdtol 1d-8
let sectol 1d-5
let radtol 1d-10


! I) Round trip on date
define double mjd rad
define real se
define char*23 iso
define integer gd ye mo da ho mi
define char*8 yy
define char*11 dd
define char*12 sexa

datetime /from 2015 YEAR 11 MONTH 16 DAY /to mjd MJD
if nint(mjd).ne.57342 then
  message e demo "Error computing DATETIME /TO MJD (1)"
  return error
endif

datetime /from mjd MJD /to iso ISO
if iso[1:11].ne."2015-11-16T" then
  message e demo "Error computing DATETIME /TO ISO (1)"
  return error
endif

datetime /from iso ISO /to gd GAG_DATE
if gd.ne.-3207 then
  message e demo "Error computing DATETIME /TO GAG_DATE (1)"
  return error
endif

datetime /from gd GAG_DATE /to yy YYYYMMDD
if yy.ne."20151116" then
  message e demo "Error computing DATETIME /TO YYYYMMDD (1)"
  return error
endif

datetime /from yy YYYYMMDD /to dd DD-MMM-YYYY
if dd.ne."16-NOV-2015" then
  message e demo "Error computing DATETIME /TO DD-MMM-YYYY (1)"
  return error
endif

datetime /from dd DD-MMM-YYYY /to ye YEAR mo MONTH da DAY
if ye.ne.2015.or.mo.ne.11.or.da.ne.16 then
  message e demo "Error computing DATETIME /TO YEAR MONTH DAY (1)"
  return error
endif


! II) Round trip on time

datetime /from 17 HOUR 27 MINUTE 15.678 SECONDS /to mjd MJD
if abs(mjd-floor(mjd)-0.72726479167d0).gt.mjdtol then
  message e demo "Error computing DATETIME /TO MJD (2)"
  return error
endif

datetime /from mjd MJD /to iso ISO
if iso[11:23].ne."T17:27:15.678" then
  message e demo "Error computing DATETIME /TO ISO (2)"
  return error
endif

datetime /from iso ISO /to rad RADIAN
if abs(rad-4.569539453442793d0).gt.radtol then
  exa rad
  message e demo "Error computing DATETIME /TO RADIAN (2)"
  return error
endif

datetime /from rad RADIAN /to sexa SEXAGESIMAL
if sexa.ne."17:27:15.678" then
  message e demo "Error computing DATETIME /TO SEXAGESIMAL (2)"
  return error
endif

datetime /from sexa SEXAGESIMAL /to ho HOUR mi MINUTE se SECONDS
if ho.ne.17.or.mi.ne.27.or.abs(se-15.678).gt.sectol then
  exa ho mi se
  message e demo "Error computing DATETIME /TO HOUR MINUTE SECONDS (2)"
  return error
endif


! III) Test a mixture of explicit scalar values, scalar variables, and
! array variables (input), to all possible formats (output)

! Inputs
define integer imo[3] ida imi
define real ise[3]

let imo 10 11 12
let ida 16
let imi 27
let ise 14.0 15.0 16.0

! Outputs
define integer oye[3] omo[3] oda[3] oho[3] omi[3] ogd[3]
define real ose[3]
define double omjd[3] orad[3]
define character*23 oiso[3]
define character*8 oyy[3]
define character*11 odd[3]
define character*12 osexa[3]

datetime -
  /from 2015 YEAR imo MONTH ida DAY 17 HOUR imi MINUTE ise SECONDS -
  /to oye YEAR omo MONTH oda DAY oho HOUR omi MINUTE ose SECONDS -
      omjd MJD oiso ISO oyy YYYYMMDD odd DD-MMM-YYYY ogd GAG_DATE -
      orad RADIAN osexa SEXAGESIMAL

! exa oye omo oda oho omi ose omjd oiso ogd oyy odd orad osexa

if oye[1].ne.2015.or.oye[2].ne.2015.or.oye[3].ne.2015 then
  message e demo "Error computing DATETIME /TO YEAR (3)"
  return error
endif
if omo[1].ne.10.or.omo[2].ne.11.or.omo[3].ne.12 then
  message e demo "Error computing DATETIME /TO MONTH (3)"
  return error
endif
if oda[1].ne.16.or.oda[2].ne.16.or.oda[3].ne.16 then
  message e demo "Error computing DATETIME /TO DAY (3)"
  return error
endif
if oho[1].ne.17.or.oho[2].ne.17.or.oho[3].ne.17 then
  message e demo "Error computing DATETIME /TO HOUR"
  return error
endif
if omi[1].ne.27.or.omi[2].ne.27.or.omi[3].ne.27 then
  message e demo "Error computing DATETIME /TO MINUTE (3)"
  return error
endif
if abs(ose[1]-14.0).gt.sectol.or.abs(ose[2]-15.0).gt.sectol.or.abs(ose[3]-16.0).gt.sectol then
  message e demo "Error computing DATETIME /TO SECONDS (3)"
  return error
endif
if abs(omjd[1]-57311.7272453703772d0).gt.mjdtol.or.abs(omjd[2]-57342.7272569444467d0).gt.mjdtol.or.abs(omjd[3]-57372.7272685185235).gt.mjdtol then
  exa omjd
  message e demo "Error computing DATETIME /TO MJD (3)"
  return error
endif
! /TO ISO: ensure some floating point tolerance, compare with 1 less digit
define logical c11 c12 c21 c22 c31 c32
let c11 oiso[1][1:22].ne."2015-10-16T17:27:13.99"
let c12 oiso[1][1:22].ne."2015-10-16T17:27:14.00"
let c21 oiso[2][1:22].ne."2015-11-16T17:27:14.99"
let c22 oiso[2][1:22].ne."2015-11-16T17:27:15.00"
let c31 oiso[3][1:22].ne."2015-12-16T17:27:15.99"
let c32 oiso[3][1:22].ne."2015-12-16T17:27:16.00"
if (c11.and.c12).or.(c21.and.c22).or.(c31.and.c32) then
  message e demo "Error computing DATETIME /TO ISO (3)"
  return error
endif
if oyy[1].ne."20151016".or.oyy[2].ne."20151116".or.oyy[3].ne."20151216" then
  message e demo "Error computing DATETIME /TO YYYYMMDD (3)"
  return error
endif
if odd[1].ne."16-OCT-2015".or.odd[2].ne."16-NOV-2015".or.odd[3].ne."16-DEC-2015" then
  message e demo "Error computing DATETIME /TO DD-MMM-YYYY (3)"
  return error
endif
if ogd[1].ne.-3238.or.ogd[2].ne.-3207.or.ogd[3].ne.-3177 then
  message e demo "Error computing DATETIME /TO GAG_DATE (3)"
  return error
endif
if abs(orad[1]-4.5694174258684272d0).gt.radtol.or.abs(orad[2]-4.5694901478918765d0).gt.radtol.or.abs(orad[3]-4.5695628699610431d0).gt.radtol then
  message e demo "Error computing DATETIME /TO RADIAN (3)"
  return error
endif
! /TO SEXAGESIMAL: ensure some floating point tolerance, compare with 1 less digit
let c11 osexa[1][1:11].ne."17:27:13.99"
let c12 osexa[1][1:11].ne."17:27:14.00"
let c21 osexa[2][1:11].ne."17:27:14.99"
let c22 osexa[2][1:11].ne."17:27:15.00"
let c31 osexa[3][1:11].ne."17:27:15.99"
let c32 osexa[3][1:11].ne."17:27:16.00"
if (c11.and.c12).or.(c21.and.c22).or.(c31.and.c32) then
  message e demo "Error computing DATETIME /TO SEXAGESIMAL (3)"
  return error
endif


! IV) Test NOW, PREVIOUS, NEXT
sic date
define char*21 sd
let sd 'sys_date'

define double now
datetime /from NOW /to dd DD-MMM-YYY sexa SEXAGESIMAL now MJD
if dd[1:11].ne.sd[1:11] then
  message e demo "Error computing DATETIME /FROM NOW (4)"
  return error
endif

datetime /from PREVIOUS DAY /TO mjd MJD
if abs(mjd+1-now).gt.mjdtol then
  message e demo "Error computing DATETIME /FROM PREVIOUS (4)"
  return error
endif

datetime /from NEXT HOUR /TO mjd MJD
if abs(mjd-1/24.d0-now).gt.mjdtol then
  message e demo "Error computing DATETIME /FROM NEXT (4)"
  return error
endif


! V) Test argument beyond their usual limits (valid use cases)

datetime /from 2015 YEAR 61 DAY -3*pi RADIAN /to mjd MJD  ! 2015-02-28T12:00:00.000
if abs(mjd-57081.5d0).gt.mjdtol then
  message e demo "Error computing DATETIME (5)"
  return error
endif
