Skip to content
Snippets Groups Projects
mod_dates.f90 4.86 KiB
!---------------------------------------------------------------------------------------
! PREP_SYNDATA: mod_dates
!---------------------------------------------------------------------------------------
!  FLEXINVERT is free software: you can redistribute it and/or modify
!  it under the terms of the GNU General Public License as published by
!  the Free Software Foundation, either version 3 of the License, or
!  (at your option) any later version.
!
!  FLEXINVERT 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 General Public License for more details.
!
!  You should have received a copy of the GNU General Public License
!  along with FLEXINVERT.  If not, see <http://www.gnu.org/licenses/>.
!
!  Copyright 2017, Rona Thompson
!---------------------------------------------------------------------------------------
!
!> mod_dates
!!
!! Purpose:    Module of date functions.
!!
!---------------------------------------------------------------------------------------

module mod_dates

  implicit none

  contains

  ! --------------------------------------------------
  ! caldate
  ! --------------------------------------------------
  !> caldate
  !!
  !! Purpose:  Converts a julian date number to date 
  !!           and time format YYYYMMDD, HHMISS 
  !!           according to the gregorian calender
  !!
  ! --------------------------------------------------

  subroutine caldate(jdate, yyyymmdd, hhmiss)

    real(kind=8), intent(in) :: jdate
    integer, intent(out)     :: yyyymmdd, hhmiss
    integer                  :: yyyy, mm, dd, hh, mi, ss
    integer                  :: julday, ja, jb, jc, jd, je, jalpha
    integer, parameter       :: igreg = 2299161

    julday=int(jdate)
    if(julday.ge.igreg) then
      jalpha=int(((julday-1867216)-0.25)/36524.25)
      ja=julday+1+jalpha-int(0.25*jalpha)
    else
      ja=julday
    endif
    jb=ja+1524
    jc=int(6680.+((jb-2439870)-122.1)/365.25)
    jd=365*jc+int(0.25*jc)
    je=int((jb-jd)/30.6001)
    dd=jb-jd-int(30.6001*je)
    mm=je-1
    if(mm.gt.12) mm=mm-12
    yyyy=jc-4715
    if(mm.gt.2) yyyy=yyyy-1
    if(yyyy.le.0) yyyy=yyyy-1

    yyyymmdd=10000*yyyy+100*mm+dd
    hh=int(24.*(jdate-float(julday)))
    mi=int(1440.*(jdate-float(julday))-60.*float(hh))
    ss=nint(86400.*(jdate-float(julday))-3600.*float(hh))-60.*float(mi)
    if(ss.eq.60) then  ! 60 seconds = 1 minute
      ss=0
      mi=mi+1
    endif
    if(mi.eq.60) then
      mi=0
      hh=hh+1
    endif
    hhmiss=10000*hh+100*mi+ss

  end subroutine caldate

  ! --------------------------------------------------
  ! julday
  ! --------------------------------------------------
  !> julday
  !!
  !! Purpose:  Converts the date and time format 
  !!           YYYYMMDD and HHMMSS to a julian date 
  !!           number.
  !!
  ! --------------------------------------------------

  real(kind=8) function juldate(yyyymmdd,hhmiss)

    integer, intent(in) :: yyyymmdd,hhmiss
    integer :: yyyy,mm,hh,dd,mi,ss
    integer :: julday,jy,jm,ja
    integer, parameter :: igreg=15+31*(10+12*1582)

    yyyy=yyyymmdd/10000
    mm=(yyyymmdd-10000*yyyy)/100
    dd=yyyymmdd-10000*yyyy-100*mm
    hh=hhmiss/10000
    mi=(hhmiss-10000*hh)/100
    ss=hhmiss-10000*hh-100*mi

    if(yyyy.eq.0) print*, 'ERROR: there is no year zero'
    if(yyyy.lt.0) yyyy=yyyy+1
    if(mm.gt.2) then
      jy=yyyy
      jm=mm+1
    else
      jy=yyyy-1
      jm=mm+13
    endif
    julday=int(365.25*jy)+int(30.6001*jm)+dd+1720995
    if (dd+31*(mm+12*yyyy).ge.igreg) then
      ja=int(0.01*jy)
      julday=julday+2-ja+int(0.25*ja)
    endif

    juldate=dble(float(julday))+dble(float(hh)/24.)&
             &+dble(float(mi)/1440.)+dble(float(ss)/86400.)

  end function juldate

  ! --------------------------------------------------
  ! calceomday
  ! --------------------------------------------------
  !> calceomday
  !! 
  !! Purpose:  Calculates number of days in a given 
  !!           year, month. Currently only considers 
  !!           years from 1900
  !!
  ! --------------------------------------------------
  integer function calceomday(yyyymm)

    integer, intent(in) :: yyyymm
    integer :: yyyy,mm
    integer, dimension(12) :: leapdays,days
    integer :: eomday

    leapdays=(/31,29,31,30,31,30,31,31,30,31,30,31/)
    days=(/31,28,31,30,31,30,31,31,30,31,30,31/)

    yyyy=floor(yyyymm/100.)
    mm=yyyymm-yyyy*100

    if((float(yyyy)/100.).eq.float(yyyy/100)) then
      if((float(yyyy)/400.).eq.float(yyyy/400)) then
        eomday=leapdays(mm)
      else
        eomday=days(mm)
      endif
    else
      if((float(yyyy)/4.).eq.float(yyyy/4)) then
        eomday=leapdays(mm)
      else
        eomday=days(mm)
      endif
    endif

    calceomday=eomday

  end function calceomday

  ! --------------------------------------------------

end module mod_dates