!== dc_date_types.f90 - 日付・時刻に関する構造体を提供するモジュール
!
! Authors::   Yasuhiro MORIKAWA, Eizi TOYODA
! Version::   $Id: dc_date_types.f90,v 1.10 2007-12-05 16:16:59 morikawa Exp $
! Tag Name::  $Name: gt4f90io-20080602 $
! Copyright:: Copyright (C) GFD Dennou Club, 2000-2005. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]

module dc_date_types
  !
  ! dc_date で用いられる構造体や変数、定数を保持するモジュールです。
  !
  ! また暦法に関する情報も保持しています.
  !
  use dc_types, only: DP, STRING

  implicit none

  private
  public:: DC_DATETIME, DC_DIFFTIME
  public:: CAL_CYCLIC, CAL_NOLEAP, CAL_JULIAN, CAL_GREGORIAN
  public:: CYCLIC_MDAYS, DAY_SECONDS_EARTH, MIN_SECONDS, HOUR_SECONDS
  public:: YEAR_MONTHS, YEAR_DAYS, FOUR_YEARS, FOUR_CENTURY
  public:: PREPARED_CALTYPES
  public:: caltype, day_seconds
  public:: UNIT_SEC, UNIT_MIN, UNIT_HOUR, UNIT_DAY, UNIT_MONTH, UNIT_YEAR

  !-------
  ! 暦法

  integer, parameter:: CAL_CYCLIC = 1   ! 1 ヵ月を 30.6 日 (CYCLIC_MDAYS)
                                        ! とする暦.
                                        ! (例: 0 ヶ月目は 1 〜 30 (30.6),
                                        ! 1 ヶ月目は 1 〜 31 (61.2),
                                        ! 2 ヶ月目は 1 〜 30 (91.8),
                                        ! 3 ヶ月目は 1 〜 31 (122.4),
                                        ! 4 ヶ月目は 1 〜 31 (153.0) ...)
                                        !
                                        ! 仮想的な時間で実験を行う
                                        ! 場合に使用することを想定してい
                                        ! ます.
                                        !
  integer, parameter:: CAL_NOLEAP = 2   ! 1 年 365 日の暦
                                        !
  integer, parameter:: CAL_JULIAN = 3   ! ユリウス暦
                                        !
  integer, parameter:: CAL_GREGORIAN = 4! グレゴリオ暦
                                        !
  integer, parameter:: PREPARED_CALTYPES(0:3) = &
    & (/CAL_CYCLIC, CAL_NOLEAP, CAL_JULIAN, CAL_GREGORIAN/)

  integer, save:: caltype = CAL_GREGORIAN ! デフォルトの暦

  !-------
  ! 日時の単位間の関係

  real(DP), parameter:: CYCLIC_MDAYS = 30.6_DP    ! CAL_CYCLIC で使用される
                                                  ! 1 ヶ月の日数.
                                                  ! また DC_DIFFTIME の
                                                  ! 1 ヶ月の日数にも
                                                  ! 使用します.

  real(DP), parameter:: MIN_SECONDS  = 60.0_DP    ! 1 分の秒数
  real(DP), parameter:: HOUR_SECONDS = 3600.0_DP  ! 1 時間の秒数
  real(DP), parameter:: DAY_SECONDS_EARTH  = 86400.0_DP
                                                  ! 地球の 1 日の秒数
  real(DP), save     :: day_seconds  = DAY_SECONDS_EARTH
                                                  ! 1 日の秒数
  integer, parameter:: YEAR_DAYS = 365            ! 1 年 (非閏年) の日数
  integer, parameter:: YEAR_MONTHS = 12           ! 1 年の月数
  integer, parameter:: FOUR_YEARS = YEAR_DAYS * 4 + 1
                                                  ! 4 年の日数
  integer, parameter:: FOUR_CENTURY = YEAR_DAYS * 400 + 97
                                                  ! 1 世紀の日数

  !-------
  ! 日時の単位として認識される文字列

  character(*), parameter, dimension(8) :: UNIT_SEC = (/ &
    & 'seconds', 'second ', 'secs.  ', 'secs   ', &
    & 'sec.   ', 'sec    ', 's.     ', 's      '/) ! 秒の単位を示す文字列

  character(*), parameter, dimension(4) :: UNIT_MIN = (/ &
    & 'minutes', 'minute ', 'min.   ', 'min    '/) ! 分の単位を示す文字列
  character(*), parameter, dimension(8) :: UNIT_HOUR = (/ &
    & 'hours', 'hour ', 'hrs. ', 'hrs  ', &
    & 'hr.  ', 'hr   ', 'h.   ', 'h    '/)         ! 時の単位を示す文字列
  character(*), parameter, dimension(4) :: UNIT_DAY = (/ &
    & 'days', 'day ', 'd.  ', 'd   '/)             ! 日の単位を示す文字列
  character(*), parameter, dimension(6) :: UNIT_MONTH = (/ &
    & 'months', 'month ', 'mon.  ', &
    & 'mon   ', 'mo.   ', 'mo    '/)               ! 月の単位を示す文字列
  character(*), parameter, dimension(4) :: UNIT_YEAR = (/ &
    & 'years', 'year ', 'yr.  ', 'yr   '/)         ! 年の単位を示す文字列


  type DC_DATETIME
    ! 通日と通秒の対で日付時刻を表現します.
    !
    ! この構造データ型の変数を使用する際は必ず変数を
    ! dc_date#Create または dc_date#assignment(=)
    ! によって初期化してください. また, *day*, *sec* などの内部変数は
    ! 直接変更しないでください.
    !
    ! 利用法は dc_date の "List" および "Usage" を参照してください.
    !
    sequence
    integer :: caltype = CAL_GREGORIAN ! 暦法
    integer :: day = 1      ! 日
    real(DP):: sec = 0.0_DP ! 秒
    real(DP):: day_seconds = DAY_SECONDS_EARTH  ! 1 日の秒数
    character(STRING) :: zone = '+00:00' ! UTC からの時差
  end type DC_DATETIME

  type DC_DIFFTIME
    ! X ヶ月後, X 日前, などを表現するためのデータ型です.
    !
    ! この構造データ型の変数を使用する際は必ず変数を
    ! dc_date#Create または dc_date#assignment(=)
    ! によって初期化してください. また, *day*, *sec* などの内部変数は
    ! 直接変更しないでください.
    !
    ! 利用法は dc_date の "List" および "Usage" を参照してください.
    !
    ! なお, 1 ヶ月は dc_date_types#CYCLIC_MDAYS と換算します.
    !
    !--
    !== 開発者向け情報
    !
    ! 「1ヵ月後」という概念に対応するため、month 欄を持ちます。
    !
    ! 注意: 日付と違って月を normalize することはできません。
    !++
    sequence
    integer :: mon = 0        ! 月
    integer :: day = 0        ! 日
    real(DP):: sec = 0.0_DP   ! 秒
    real(DP):: day_seconds = DAY_SECONDS_EARTH
                              ! 1 日の秒数
!!$    real(DP):: sec_scale_factor
!!$                              ! 1.0 以下の sec が与えられた際に, 
!!$                              ! 丸め誤差によって
!!$                              ! sec がずれるのを防ぐためのファクター
!!$                              ! (実験的機能)
  end type DC_DIFFTIME

end module dc_date_types
