!= æ—¥æ™‚æƒ…å ±ã®å•ã„åˆã‚ã›
!= Inquire information of date
!
! Authors::   Yasuhiro MORIKAWA
! Version::   $Id: dccaldateinquire.f90,v 1.3 2010-09-24 00:28:18 morikawa Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2009-. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]
!
! ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã«è¨˜è¼‰ã•ã‚Œã‚‹æ‰‹ç¶šãç¾¤ã¯ dc_calendar ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‹ã‚‰æä¾›ã•ã‚Œã¾ã™.
!
! Procedures described in this file are provided from "dc_calendar" module.
!

subroutine DCCalDateInquire1( year, month, day, hour, min, sec, zone, &
  & elapse_sec, date, cal, err )
  !
  ! æ—¥æ™‚æƒ…å ±ã®å•ã„åˆã‚ã›ã‚’è¡Œã„ã¾ã™.
  !
  ! å•ã„åˆã‚ã›ã®çµæžœã‚’
  ! YYYY-MM-DDThh:mm:ss.sTZD ã®ã‚ˆã†ãªæ–‡å—åˆ—
  ! (YYYY ã¯å¹´, MM ã¯æœˆ, DD ã¯æ—¥, hh ã¯æ™‚, mm ã¯åˆ†, ss.s ã¯ç§’,
  ! TZD ã¯ã‚¿ã‚¤ãƒ ã‚¾ãƒ¼ãƒ³) ã§å—ã‘å–ã‚ŠãŸã„å ´åˆã«ã¯,
  ! ä¸‹è¨˜ã®åŒåã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’ä½¿ç”¨ã—ã¦ä¸‹ã•ã„.
  !
  ! çœç•¥å¯èƒ½å¼•æ•° *date* ãŒçœç•¥ã•ã‚ŒãŸå ´åˆã«ã¯, dc_calendar å†…éƒ¨ã§
  ! ä¿æŒã•ã‚Œã‚‹æ—¥æ™‚ã«é–¢ã™ã‚‹æƒ…å ±ãŒå¾—ã‚‰ã‚Œã¾ã™.
  ! *date* ãŒçœç•¥ã•ã‚Œãªã„å ´åˆã«ã¯ãã®å¤‰æ•°ã«è¨å®šã•ã‚ŒãŸæ—¥æ™‚ã®æƒ…å ±ãŒå¾—ã‚‰ã‚Œã¾ã™.
  !
  ! çœç•¥å¯èƒ½å¼•æ•° *cal* ãŒçœç•¥ã•ã‚ŒãŸå ´åˆã«ã¯, çµŒéŽç§’æ•° *elapse_sec*
  ! ã®å¹´æœˆæ—¥æ™‚åˆ†ã¸ã®å¤‰æ›ã« dc_calendar å†…éƒ¨ã§ä¿æŒã•ã‚Œã‚‹æš¦ãŒç”¨ã„ã‚‰ã‚Œã¾ã™.
  ! *cal* ãŒçœç•¥ã•ã‚Œãªã„å ´åˆã«ã¯ãã®å¤‰æ•°ã«è¨å®šã•ã‚ŒãŸæš¦ãŒç”¨ã„ã‚‰ã‚Œã¾ã™.
  !
  ! Inquire information of date.
  !
  ! If a string like as "YYYY-MM-DDThh:mm:ss.sTZD"
  ! (YYYY is year, MM is month, DD is day, hh is hour, mm is minute,
  ! ss.s is second, TZD is time zone) is needed,
  ! use a following homonymous subroutine.
  !
  ! If an optional argument *date* is omitted,
  ! information of date that is stored in the "dc_calendar"
  ! is returned,
  ! If *date* is not omitted, information of the variable is returned.
  !
  ! If an optional argument *cal* is omitted,
  ! information of calendar that is stored in the "dc_calendar"
  ! is used for conversion of elapsed seconds *elapse_sec* into
  ! year-month-day etc.
  ! If *cal* is not omitted, information of the variable is used.
  !
  use dc_calendar_types, only: DC_CAL, DC_CAL_DATE
  use dc_calendar_internal, only: default_cal, default_cal_set, default_date, &
    & dccaldate_normalize
  use dc_calendar_generic, only: DCCalDateToChar, DCCalToChar
  use dc_message, only: MessageNotify
  use dc_string, only: LChar
  use dc_trace, only: BeginSub, EndSub
  use dc_error, only: StoreError, DC_NOERR, DC_ENOTINIT, &
    & DC_EINCONSISTCALDATE, DC_ENEGATIVE
  use dc_types, only: STRING, DP, TOKEN
  implicit none
  integer, intent(out), optional:: year           ! å¹´. Year.
  integer, intent(out), optional:: month          ! æœˆ. Month.
  integer, intent(out), optional:: day            ! æ—¥. Day.
  integer, intent(out), optional:: hour           ! æ™‚. Hour.
  integer, intent(out), optional:: min            ! åˆ†. Minute.
  real(DP), intent(out), optional:: sec           ! ç§’. Sec.
  character(*), intent(out), optional:: zone      ! UTC ã‹ã‚‰ã®æ™‚å·®. Time-zone.
  real(DP), intent(in), optional:: elapse_sec
                              ! *date* ã‹ã‚‰ã®çµŒéŽç§’æ•°.
                              ! Elapsed seconds from *date*.
  type(DC_CAL_DATE), intent(in), optional, target:: date
                              ! æ—¥æ™‚æƒ…å ±ã‚’åŽã‚ãŸã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆ.
                              !
                              ! An object that stores information of
                              ! date and time.
  type(DC_CAL), intent(in), optional, target:: cal
                              ! æš¦æƒ…å ±ã‚’åŽã‚ãŸã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆ.
                              !
                              ! An object that stores information of
                              ! calendar.
  logical, intent(out), optional:: err
                              ! ä¾‹å¤–å‡¦ç†ç”¨ãƒ•ãƒ©ã‚°.
                              ! ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã§ã¯, ã“ã®æ‰‹ç¶šãå†…ã§ã‚¨ãƒ©ãƒ¼ãŒ
                              ! ç”Ÿã˜ãŸå ´åˆ, ãƒ—ãƒã‚°ãƒ©ãƒ ã¯å¼·åˆ¶çµ‚äº†ã—ã¾ã™.
                              ! å¼•æ•° *err* ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆ,
                              ! ãƒ—ãƒã‚°ãƒ©ãƒ ã¯å¼·åˆ¶çµ‚äº†ã›ãš, ä»£ã‚ã‚Šã«
                              ! *err* ã« .true. ãŒä»£å…¥ã•ã‚Œã¾ã™.
                              !
                              ! Exception handling flag.
                              ! By default, when error occur in
                              ! this procedure, the program aborts.
                              ! If this *err* argument is given,
                              ! .true. is substituted to *err* and
                              ! the program does not abort.

  ! ä½œæ¥å¤‰æ•°
  ! Work variables
  !
  integer:: wyear, wmonth, wday, whour, wmin
  real(DP):: wsec
  character(TOKEN):: wzone
  type(DC_CAL_DATE), pointer:: datep =>null()
  type(DC_CAL), pointer:: calp =>null()
  character(STRING):: e_date_str, e_cal_str
  integer:: stat
  character(STRING):: cause_c
  character(*), parameter:: subname = 'DCCalInquire1'
continue
  call BeginSub( subname )
  stat = DC_NOERR
  cause_c = ''

  ! ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã®ãƒã‚¤ãƒ³ã‚¿å‰²ä»˜
  ! Associate pointer of an object
  !
  if ( present( date ) ) then
    datep => date
  else
    datep => default_date
  end if

  if ( present( cal ) ) then
    calp => cal
  else
    calp => default_cal
    if ( .not. calp % initialized ) call default_cal_set
  end if

  ! åˆæœŸè¨å®šã®ãƒã‚§ãƒƒã‚¯
  ! Check initialization
  !
  if ( .not. datep % initialized ) then
    stat = DC_ENOTINIT
    cause_c = 'DC_CAL_DATE'
    goto 999
  end if

  if ( .not. calp % initialized ) then
    stat = DC_ENOTINIT
    cause_c = 'DC_CAL'
    goto 999
  end if

  ! å„è¦ç´ ã¸ã®å€¤ã®å‚ç…§
  ! Refer elements
  !
  wyear  = datep % year
  wmonth = datep % month
  wday   = datep % day
  whour  = datep % hour
  wmin   = datep % min
  wsec   = datep % sec
  wzone  = datep % zone

  ! çµŒéŽæ™‚é–“(ç§’)ã®è¿½åŠ
  ! Add elapsed time (seconds)
  !
  if ( present( elapse_sec ) ) then
!!$    if ( elapse_sec < 0.0_DP ) then
!!$      stat = DC_ENEGATIVE
!!$      cause_c = 'elapse_sec'
!!$      goto 999
!!$    end if

    wsec = wsec + elapse_sec
  end if

  ! æ—¥æ™‚ã®æ£è¦åŒ–
  ! Normalize date and time
  !
  stat = dccaldate_normalize( wyear, wmonth, wday, whour, wmin, wsec, & ! (inout)
    &                         calp )                                    ! (in)
  if ( stat == DC_EINCONSISTCALDATE ) then
    e_cal_str = DCCalToChar( calp )
    e_date_str = DCCalDateToChar( wyear, wmonth, wday, whour, wmin, wsec, wzone )
    call MessageNotify('W', subname, 'cal=<%c> and date=<%c> are inconsistency', &
      & c1 = trim(e_cal_str), c2 = trim(e_date_str) )
    goto 999
  end if

  ! å¼•æ•°ã¸ã®ä»£å…¥
  ! Substitute arguments
  !
  if ( present(year ) ) year  = wyear
  if ( present(month) ) month = wmonth
  if ( present(day  ) ) day   = wday
  if ( present(hour ) ) hour  = whour
  if ( present(min  ) ) min   = wmin
  if ( present(sec  ) ) sec   = wsec
  if ( present(zone ) ) zone  = wzone

  ! çµ‚äº†å‡¦ç†, ä¾‹å¤–å‡¦ç†
  ! Termination and Exception handling
  !
999 continue
  nullify( calp, datep )
  call StoreError( stat, subname, err, cause_c )
  call EndSub( subname )
end subroutine DCCalDateInquire1

subroutine DCCalDateInquire2( date_str, elapse_sec, date, cal, err )
  !
  ! æ—¥æ™‚æƒ…å ±ã®å•ã„åˆã‚ã›ã‚’è¡Œã„ã¾ã™.
  ! å•ã„åˆã‚ã›çµæžœã¯ YYYY-MM-DDThh:mm:ss.sTZD ã®ã‚ˆã†ãªæ–‡å—åˆ—
  ! (YYYY ã¯å¹´, MM ã¯æœˆ, DD ã¯æ—¥, hh ã¯æ™‚, mm ã¯åˆ†, ss.s ã¯ç§’,
  ! TZD ã¯ã‚¿ã‚¤ãƒ ã‚¾ãƒ¼ãƒ³) ã§è¿”ã‚Šã¾ã™.
  ! æ—¥æ™‚ã®æ–‡å—åˆ—å½¢å¼ã¯
  ! gtool4 netCDF è¦ç´„ã€Œ5.5 æ—¥æ™‚å½¢å¼ã€ã«æº–æ‹ ã—ã¦ã„ã¾ã™.
  !
  ! å•ã„åˆã‚ã›ã®çµæžœã‚’å¹´æœˆæ—¥æ™‚åˆ†ç§’ã§å„å€‹å¤‰æ•°ã§å—ã‘å–ã‚ŠãŸã„å ´åˆã¯
  ! ä¸Šè¨˜ã®åŒåã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’ä½¿ç”¨ã—ã¦ä¸‹ã•ã„.
  !
  ! çœç•¥å¯èƒ½å¼•æ•° *date* ãŒçœç•¥ã•ã‚ŒãŸå ´åˆã«ã¯, dc_calendar å†…éƒ¨ã§
  ! ä¿æŒã•ã‚Œã‚‹æ—¥æ™‚ã«é–¢ã™ã‚‹æƒ…å ±ãŒå¾—ã‚‰ã‚Œã¾ã™.
  ! *date* ãŒçœç•¥ã•ã‚Œãªã„å ´åˆã«ã¯ãã®å¤‰æ•°ã«è¨å®šã•ã‚ŒãŸæ—¥æ™‚ã®æƒ…å ±ãŒå¾—ã‚‰ã‚Œã¾ã™.
  !
  ! çœç•¥å¯èƒ½å¼•æ•° *cal* ãŒçœç•¥ã•ã‚ŒãŸå ´åˆã«ã¯, çµŒéŽç§’æ•° *elapse_sec*
  ! ã®å¹´æœˆæ—¥æ™‚åˆ†ã¸ã®å¤‰æ›ã« dc_calendar å†…éƒ¨ã§ä¿æŒã•ã‚Œã‚‹æš¦ãŒç”¨ã„ã‚‰ã‚Œã¾ã™.
  ! *cal* ãŒçœç•¥ã•ã‚Œãªã„å ´åˆã«ã¯ãã®å¤‰æ•°ã«è¨å®šã•ã‚ŒãŸæš¦ãŒç”¨ã„ã‚‰ã‚Œã¾ã™.
  !
  ! Inquire information of date.
  ! A result is returned as a string like as
  ! YYYY-MM-DDThh:mm:ss.sTZD
  ! (YYYY is year, MM is month, DD is day, hh is hour, mm is minute,
  ! ss.s is second, TZD is time zone).
  ! Format of date is conformed to gtool4 netCDF Convention "5.5 Expression of date and time"
  !
  ! If individual variables (year, month, day, hour, minute, second, zone)
  ! are needed, use a foregoing homonymous subroutine.
  !
  ! If an optional argument *date* is omitted,
  ! information of date that is stored in the "dc_calendar"
  ! is returned,
  ! If *date* is not omitted, information of the variable is returned.
  !
  ! If an optional argument *cal* is omitted,
  ! information of calendar that is stored in the "dc_calendar"
  ! is used for conversion of elapsed seconds *elapse_sec* into
  ! year-month-day etc.
  ! If *cal* is not omitted, information of the variable is used.
  !
  use dc_calendar_generic, only: DCCalDateToChar
  use dc_calendar_types, only: DC_CAL, DC_CAL_DATE
  use dc_calendar_internal, only: default_cal, default_cal_set, default_date, &
    & dccaldate_normalize
  use dc_calendar_generic, only: DCCalDateToChar, DCCalToChar
  use dc_message, only: MessageNotify
  use dc_string, only: LChar
  use dc_trace, only: BeginSub, EndSub
  use dc_error, only: StoreError, DC_NOERR, DC_ENOTINIT, &
    & DC_EINCONSISTCALDATE, DC_ENEGATIVE
  use dc_types, only: STRING, DP, TOKEN
  implicit none
  character(*), intent(out):: date_str
                              ! æ—¥æ™‚æƒ…å ±ã‚’è¡¨ã™æ–‡å—åˆ—.
                              ! è¡¨ç¤ºå½¢å¼ã«ã¤ã„ã¦ã¯ gtool4 netCDF è¦ç´„
                              ! 5.5 æ—¥æ™‚å½¢å¼ã‚’å‚ç…§ã®ã“ã¨.
                              !
                              ! Strings that express date and time.
                              ! See gtool4 netCDF Convention
                              ! 5.5 Expression of date and time for details.
  real(DP), intent(in), optional:: elapse_sec
                              ! *date* ã‹ã‚‰ã®çµŒéŽç§’æ•°.
                              ! Elapsed seconds from *date*.
  type(DC_CAL_DATE), intent(in), optional, target:: date
                              ! æ—¥æ™‚æƒ…å ±ã‚’åŽã‚ãŸã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆ.
                              !
                              ! An object that stores information of
                              ! date and time.
  type(DC_CAL), intent(in), optional, target:: cal
                              ! æš¦æƒ…å ±ã‚’åŽã‚ãŸã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆ.
                              !
                              ! An object that stores information of
                              ! calendar.
  logical, intent(out), optional:: err
                              ! ä¾‹å¤–å‡¦ç†ç”¨ãƒ•ãƒ©ã‚°.
                              ! ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã§ã¯, ã“ã®æ‰‹ç¶šãå†…ã§ã‚¨ãƒ©ãƒ¼ãŒ
                              ! ç”Ÿã˜ãŸå ´åˆ, ãƒ—ãƒã‚°ãƒ©ãƒ ã¯å¼·åˆ¶çµ‚äº†ã—ã¾ã™.
                              ! å¼•æ•° *err* ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆ,
                              ! ãƒ—ãƒã‚°ãƒ©ãƒ ã¯å¼·åˆ¶çµ‚äº†ã›ãš, ä»£ã‚ã‚Šã«
                              ! *err* ã« .true. ãŒä»£å…¥ã•ã‚Œã¾ã™.
                              !
                              ! Exception handling flag.
                              ! By default, when error occur in
                              ! this procedure, the program aborts.
                              ! If this *err* argument is given,
                              ! .true. is substituted to *err* and
                              ! the program does not abort.

  ! ä½œæ¥å¤‰æ•°
  ! Work variables
  !
  integer:: year, month, day, hour, min
  real(DP):: sec
  character(TOKEN):: zone
  type(DC_CAL_DATE), pointer:: datep =>null()
  type(DC_CAL), pointer:: calp =>null()
  character(STRING):: e_date_str, e_cal_str
  integer:: stat
  character(STRING):: cause_c
  character(*), parameter:: subname = 'DCCalInquire2'
continue
  call BeginSub( subname )
  stat = DC_NOERR
  cause_c = ''

  ! ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã®ãƒã‚¤ãƒ³ã‚¿å‰²ä»˜
  ! Associate pointer of an object
  !
  if ( present( date ) ) then
    datep => date
  else
    datep => default_date
  end if

  if ( present( cal ) ) then
    calp => cal
  else
    calp => default_cal
    if ( .not. calp % initialized ) call default_cal_set
  end if

  ! åˆæœŸè¨å®šã®ãƒã‚§ãƒƒã‚¯
  ! Check initialization
  !
  if ( .not. datep % initialized ) then
    stat = DC_ENOTINIT
    cause_c = 'DC_CAL_DATE'
    goto 999
  end if

  if ( .not. calp % initialized ) then
    stat = DC_ENOTINIT
    cause_c = 'DC_CAL'
    goto 999
  end if

  ! å„è¦ç´ ã®å–å¾—
  ! Get elements
  !
  year  = datep % year
  month = datep % month
  day   = datep % day
  hour  = datep % hour
  min   = datep % min
  sec   = datep % sec
  zone  = datep % zone

  ! çµŒéŽæ™‚é–“(ç§’)ã®è¿½åŠ
  ! Add elapsed time (seconds)
  !
  if ( present( elapse_sec ) ) then
!!$    if ( elapse_sec < 0.0_DP ) then
!!$      stat = DC_ENEGATIVE
!!$      cause_c = 'elapse_sec'
!!$      goto 999
!!$    end if

    sec = sec + elapse_sec
  end if

  ! æ—¥æ™‚ã®æ£è¦åŒ–
  ! Normalize date and time
  !
  stat = dccaldate_normalize( year, month, day, hour, min, sec, & ! (inout)
    &                         calp )                              ! (in)
  if ( stat == DC_EINCONSISTCALDATE ) then
    e_cal_str = DCCalToChar( calp )
    e_date_str = DCCalDateToChar( year, month, day, hour, min, sec, zone )
    call MessageNotify('W', subname, 'cal=<%c> and date=<%c> are inconsistency', &
      & c1 = trim(e_cal_str), c2 = trim(e_date_str) )
    goto 999
  end if

  ! æ—¥æ™‚è¡¨è¨˜ï¼ˆgtool4 netCDF è¦ç´„ 5.5 æ—¥æ™‚å½¢å¼ï¼‰ã¸ã®å¤‰æ›
  ! Convert expression of date (gtool4 netCDF Convention 5.5 Expression of date and time)
  !
  date_str = DCCalDateToChar( year, month, day, hour, min, sec, zone )

  ! çµ‚äº†å‡¦ç†, ä¾‹å¤–å‡¦ç†
  ! Termination and Exception handling
  !
999 continue
  nullify( calp, datep )
  call StoreError( stat, subname, err, cause_c )
  call EndSub( subname )
end subroutine DCCalDateInquire2