LCOV - code coverage report
Current view: top level - src - mo_julian.f90 (source / functions) Hit Total Coverage
Test: forces coverage Lines: 261 267 97.8 %
Date: 2024-03-13 19:03:28 Functions: 21 21 100.0 %

          Line data    Source code
       1             : !> \file mo_julian.f90
       2             : !> \brief \copybrief mo_julian
       3             : !> \details \copydetails mo_julian
       4             : 
       5             : !> \brief Julian date conversion routines
       6             : !> \details Julian date to and from day, month, year, and also from day, month, year, hour, minute, and second.
       7             : !! Also convience routines for Julian dates of IMSL are provided.
       8             : !! \note Julian day definition starts at noon of the 1st January 4713 BC.\n
       9             : !! Here, the astronomical definition is used,
      10             : !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
      11             : !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
      12             : !! \n
      13             : !! julday and caldat start at midnight of the 1st January 4713 BC.
      14             : !! So date2dec and julday as well as dec2date and caldat are shifted by half a day.\n
      15             : !! Use date2dec with dec2date together for fractional Julian dates
      16             : !! and use julday with caldat together for integer Julian days.
      17             : !> \changelog
      18             : !! - Matthias Cuntz, Dec 2011
      19             : !! - Matthias Cuntz, Jan 2013
      20             : !!   - added date2dec and dec2date
      21             : !! - Matthias Cuntz, May 2014
      22             : !!   - changed to new algorithm with astronomical units removed numerical recipes
      23             : !! - David Schaefer, Oct 2015
      24             : !!   - addded 360 day calendar procedures
      25             : !! - David Schaefer, Jan 2016
      26             : !!   - addded 365 day calendar procedures
      27             : !! - David Schaefer, Feb 2016
      28             : !!   - implemented wrapper function and the module calendar state
      29             : !> \author Matthias Cuntz
      30             : !> \date Dec 2011
      31             : !> \copyright Copyright 2005-\today, the CHS Developers, Sabine Attinger: All rights reserved.
      32             : !! FORCES is released under the LGPLv3+ license \license_note
      33             : MODULE mo_julian
      34             : 
      35             :   USE mo_kind, ONLY : i4, i8, dp
      36             : 
      37             :   IMPLICIT NONE
      38             : 
      39             :   PRIVATE
      40             : 
      41             :   PUBLIC :: caldat
      42             :   PUBLIC :: date2dec     ! Fractional Julian day from day, month, year, hour, minute, and second
      43             :   PUBLIC :: dec2date     ! Day, month, year, hour, minute, and second from fractional Julian day
      44             :   PUBLIC :: julday       ! Julian day from day, month and year
      45             :   PUBLIC :: ndays        ! IMSL Julian day from day, month and year
      46             :   PUBLIC :: ndyin        ! Day, month and year from IMSL Julian day
      47             :   public :: setCalendar
      48             :   public :: caldatJulian
      49             : 
      50             :   integer(i4), save, private :: calendar = 1
      51             : 
      52             :   ! ------------------------------------------------------------------
      53             : 
      54             :   !>    \brief Set module private variable calendar
      55             : 
      56             :   !>    \details
      57             :   !!    Set which type of calendar to use.
      58             :   !!
      59             :   !!    \b Example
      60             :   !!
      61             :   !!    Set to Julian calendar.
      62             :   !!    \code{.f90}
      63             :   !!    call caldat("julian")
      64             :   !!    call caldat(1)
      65             :   !!    \endcode
      66             : 
      67             :   !>    \param[in] "character(len=*)/integer(i4) :: selector"     {"julian"/1|"365day"/2|"360day"/3}
      68             : 
      69             :   !>    \author David Schaefer
      70             :   !>    \date Jan 2015
      71             : 
      72             :   interface setCalendar
      73             :     module procedure setCalendarInteger, setCalendarString
      74             :   end interface setCalendar
      75             : 
      76             : CONTAINS
      77             : 
      78           2 :   subroutine setCalendarString(selector)
      79             :     character(*), intent(in) :: selector
      80             : 
      81           0 :     select case(selector)
      82             :     case("julian")
      83           0 :       call setCalendarInteger(1)
      84             :     case("365day")
      85           1 :       call setCalendarInteger(2)
      86             :     case("360day")
      87           1 :       call setCalendarInteger(3)
      88             :     case default
      89           0 :       print*, "Unknown selector! Select on of 'julian', '365day', '360day'."
      90           0 :       stop 1
      91             :     end select
      92           2 :   end subroutine setCalendarString
      93             : 
      94             : 
      95           2 :   subroutine setCalendarInteger(selector)
      96             :     integer(i4), intent(in) :: selector
      97             : 
      98           2 :     if ((selector .lt. 1) .or. (selector .gt. 3)) then
      99           0 :       print*, "Unknown selector! Select on of 1, 2, 3."
     100           0 :       stop 1
     101             :     end if
     102           2 :     calendar = selector
     103             : 
     104           2 :   end subroutine setCalendarInteger
     105             : 
     106             :   ! ------------------------------------------------------------------
     107             : 
     108             :   !>    \brief Select a calendar
     109             : 
     110             :   !>    \details Returns a valid calendar index, based on the given optional argument
     111             :   !!    and/or the module global private variable calendar. If an invalid selector is passed,
     112             :   !!    its value is ignored and the global calendar value retuned instead.
     113             :   !!
     114             :   !!    \b Example
     115             :   !!
     116             :   !!    Returns a valid index which is 3
     117             :   !!    \code{.f90}
     118             :   !!    idx = selectCalendar(3)
     119             :   !!    \endcode
     120             : 
     121             :   !>    \param[in] "integer(i4), optional :: selector"     Calendar selector {1|2|3}
     122             : 
     123             :   !>    \author David Schaefer
     124             :   !>    \date Jan 2015
     125   130924072 :   pure function selectCalendar(selector)
     126             :     integer(i4), intent(in), optional :: selector
     127             :     integer(i4) :: selectCalendar
     128             : 
     129   130924072 :     selectCalendar = calendar
     130   130924072 :     if (present(selector)) then
     131           4 :       if ((selector .gt. 0) .and. (selector .lt. 4)) then
     132           4 :         selectCalendar = selector
     133             :       end if
     134             :     end if
     135             : 
     136           2 :   end function selectCalendar
     137             : 
     138             :   ! ------------------------------------------------------------------
     139             : 
     140             :   !>    \brief Day, month and year from Julian day in the current or given calendar
     141             : 
     142             :   !>    \details
     143             :   !!    Wrapper around the calendar specific caldat procedures.
     144             :   !!    Inverse of the function julday. Here julian is input as a Julian Day Number,
     145             :   !!    and the routine outputs d0d, mm, and yy as the day, month, and year on which the specified
     146             :   !!    Julian Day started at noon.\n
     147             :   !!
     148             :   !!    The zeroth Julian Day depends on the called procedure. See their documentation for details.
     149             :   !!
     150             :   !!    \b Example
     151             :   !!
     152             :   !!    Converts julday to dd, mm, yy format
     153             :   !!    \code{.f90}
     154             :   !!    call caldat(julday, dd, mm, yy)
     155             :   !!    \endcode
     156             : 
     157             :   !>    \param[in] "integer(i4) :: julday"     Julian day
     158             :   !>    \param[out] "integer(i4) :: dd"        Day in month of Julian day
     159             :   !>    \param[out] "integer(i4) :: mm"        Month in year of Julian day
     160             :   !>    \param[out] "integer(i4) :: yy"        Year of Julian day
     161             :   !>    \param[in] "integer(i4) :: calendar"   The calendar to use, the global calendar
     162             :   !!                                           will be used by default
     163             : 
     164             :   !>    \author David Schaefer
     165             :   !>    \date Jan 2015
     166     7636067 :   elemental subroutine caldat(julian, dd, mm, yy, calendar)
     167             : 
     168             :     implicit none
     169             : 
     170             :     integer(i4), intent(in) :: julian
     171             :     integer(i4), intent(out) :: dd, mm, yy
     172             :     integer(i4), intent(in), optional :: calendar
     173             : 
     174     5158863 :     select case(selectCalendar(calendar))
     175             :     case(1)
     176     5158863 :       call caldatJulian(julian, dd, mm, yy)
     177             :     case(2)
     178     1606002 :       call caldat365(julian, dd, mm, yy)
     179             :     case(3)
     180      871202 :       call caldat360(julian, dd, mm, yy)
     181             :     end select
     182             : 
     183   130924072 :   end subroutine caldat
     184             : 
     185             :   ! ------------------------------------------------------------------
     186             : 
     187             :   !>    \brief Day, month, year, hour, minute, and second from fractional Julian day in the current or given calendar
     188             : 
     189             :   !>    \details Wrapper around the calendar specific dec2date procedures.
     190             :   !!    Inverse of the function date2dec. Here dec2date is input as a fractional Julian Day.
     191             :   !!    The routine outputs dd, mm, yy, hh, nn, ss as the day, month, year, hour, minute, and second
     192             :   !!    on which the specified Julian Day started at noon.
     193             :   !!
     194             :   !!    The zeroth Julian Day depends on the called procedure. See their documentation for details.
     195             :   !!
     196             :   !!    \b Example
     197             :   !!
     198             :   !!    Takes in fraction julian date fJulian to covert to dd, mm, yy, hh, nn, ss
     199             :   !!    \code{.f90}
     200             :   !!    call dec2date(fJulian, dd, mm, yy, hh, nn, ss)
     201             :   !!    \endcode
     202             : 
     203             :   !>    \param[in] "real(dp) :: fJulian"                  fractional Julian day
     204             :   !>    \param[in] "integer(i4), optional :: calendar"    The calendar to use, the global calendar
     205             :   !!                                                      will be used by default
     206             :   !>    \param[out] "integer(i4), optional :: dd"         Day in month of Julian day
     207             :   !>    \param[out] "integer(i4), optional :: mm"         Month in year of Julian day
     208             :   !>    \param[out] "integer(i4), optional :: yy"         Year of Julian day
     209             :   !>    \param[out] "integer(i4), optional :: hh"         Hour of Julian day
     210             :   !>    \param[out] "integer(i4), optional :: nn"         Minute in hour of Julian day
     211             :   !>    \param[out] "integer(i4), optional :: ss"         Second in minute of hour of Julian day
     212             : 
     213             : 
     214             :   !     HISTORY
     215             :   !>    \author David Schaefer
     216             :   !>    \date Jan 2015
     217    77101599 :   elemental subroutine dec2date(julian, dd, mm, yy, hh, nn, ss, calendar)
     218             : 
     219             :     implicit none
     220             : 
     221             :     real(dp), intent(in) :: julian
     222             :     integer(i4), intent(out), optional :: dd, mm, yy, hh, nn, ss
     223             :     integer(i4), intent(in), optional :: calendar
     224             : 
     225    35345303 :     select case(selectCalendar(calendar))
     226             :     case(1)
     227    35345303 :       call dec2dateJulian(julian, dd, mm, yy, hh, nn, ss)
     228             :     case(2)
     229    11242011 :       call dec2date365(julian, dd, mm, yy, hh, nn, ss)
     230             :     case(3)
     231    30514285 :       call dec2date360(julian, dd, mm, yy, hh, nn, ss)
     232             :     end select
     233             : 
     234     7636067 :   end subroutine dec2date
     235             : 
     236             :   ! ------------------------------------------------------------------
     237             : 
     238             :   !>    \brief Fractional Julian day from day, month, year, hour, minute, second in the current calendar
     239             : 
     240             :   !>    \details Wrapper around the calendar specific date2dec procedures.
     241             :   !!    In this routine date2dec returns the fractional Julian Day that begins at noon
     242             :   !!    of the calendar date specified by month mm, day dd, and year yy, all integer variables.
     243             :   !!
     244             :   !!    The zeroth Julian Day depends on the called procedure. See their documentation for details.
     245             :   !!
     246             :   !!    \b Example
     247             :   !!
     248             :   !!    Take dd, mm, yy, hh, nn, ss to fractional Julian date
     249             :   !!    \code{.f90}
     250             :   !!    date2dec = date2dec(dd, mm, yy, hh, nn, ss)
     251             :   !!    \endcode
     252             : 
     253             :   !>    \param[in] "integer(i4), optional :: dd"         Day in month of Julian day (default: 1)
     254             :   !>    \param[in] "integer(i4), optional :: mm"         Month in year of Julian day (default: 1)
     255             :   !>    \param[in] "integer(i4), optional :: yy"         Year of Julian day (default: 1)
     256             :   !>    \param[in] "integer(i4), optional :: hh"         Hours of Julian day (default: 0)
     257             :   !>    \param[in] "integer(i4), optional :: nn"         Minutes of hour of Julian day (default: 0)
     258             :   !>    \param[in] "integer(i4), optional :: ss"         Secondes of minute of hour of Julian day (default: 0)
     259             :   !>    \param[in] "integer(i4), optional :: calendar"   The calendar to use, the global calendar
     260             :   !!                                                     will be used by default
     261             :   !>    \retval "real(dp) :: date2dec"                   Fractional Julian day
     262             : 
     263             :   !>    \author David Schaefer
     264             :   !>    \date Jan 2015
     265    41957130 :   elemental function date2dec(dd, mm, yy, hh, nn, ss, calendar)
     266             : 
     267             :     implicit none
     268             : 
     269             :     integer(i4), intent(in), optional :: dd, mm, yy
     270             :     integer(i4), intent(in), optional :: hh, nn, ss
     271             :     integer(i4), intent(in), optional :: calendar
     272             :     real(dp) :: date2dec
     273             : 
     274    20196767 :     select case(selectCalendar(calendar))
     275             :     case(1)
     276    20196767 :       date2dec = date2decJulian(dd, mm, yy, hh, nn, ss)
     277             :     case(2)
     278     6424013 :       date2dec = date2dec365(dd, mm, yy, hh, nn, ss)
     279             :     case(3)
     280    15336350 :       date2dec = date2dec360(dd, mm, yy, hh, nn, ss)
     281             :     end select
     282             : 
     283    77101599 :   end function date2dec
     284             : 
     285             :   ! ------------------------------------------------------------------
     286             : 
     287             :   !>    \brief Julian day from day, month and year in the current or given calendar
     288             : 
     289             :   !>    \details Wrapper around the calendar specific julday procedures.
     290             :   !!    In this routine julday returns the Julian Day Number that begins at noon of the calendar
     291             :   !!    date specified by month mm, day dd, and year yy, all integer variables.
     292             :   !!
     293             :   !!    The zeroth Julian Day depends on the called procedure. See their documentation for details.
     294             :   !!
     295             :   !!    \b Example
     296             :   !!
     297             :   !!    Take dd, mm, yy, hh, nn, ss to Julian date
     298             :   !!    \code{.f90}
     299             :   !!    date2dec = date2dec(dd, mm, yy)
     300             :   !!    \endcode
     301             : 
     302             :   !>    \param[in] "integer(i4) :: dd"                    Day in month of Julian day
     303             :   !>    \param[in] "integer(i4) :: mm"                    Month in year of Julian day
     304             :   !>    \param[in] "integer(i4) :: yy"                    Year of Julian day
     305             :   !>    \param[in] "integer(i4), optional :: calendar"    The calendar to use, the global calendar
     306             :   !!                                                      will be used by default
     307             : 
     308             :   !>    \retval "integer(i4) :: julian"                   Julian day
     309             : 
     310             :   !>    \author David Schaefer
     311             :   !>    \date Jan 2015
     312     4229276 :   elemental function julday(dd, mm, yy, calendar)
     313             : 
     314             :     implicit none
     315             : 
     316             :     integer(i4), intent(in) :: dd, mm, yy
     317             :     integer(i4), intent(in), optional :: calendar
     318             :     integer(i4) :: julday
     319             : 
     320     2634272 :     select case(selectCalendar(calendar))
     321             :     case(1)
     322     2634272 :       julday = juldayJulian(dd, mm, yy)
     323             :     case(2)
     324      803002 :       julday = julday365(dd, mm, yy)
     325             :     case(3)
     326      792002 :       julday = julday360(dd, mm, yy)
     327             :     end select
     328             : 
     329    41957130 :   end function julday
     330             : 
     331             :   ! ------------------------------------------------------------------
     332             : 
     333             :   !>    \brief Day, month and year from Julian day
     334             : 
     335             :   !>    \details Inverse of the function juldayJulian. Here julian is input as a Julian Day Number,
     336             :   !!    and the routine outputs id, mm, and yy as the day, month, and year on which the specified
     337             :   !!    Julian Day started at noon.
     338             :   !!
     339             :   !!    The zeroth Julian Day is 01.01.-4712, i.e. the 1st January 4713 BC.
     340             :   !!
     341             :   !!    Julian day definition starts at 1st January 4713 BC.\n
     342             :   !!    Here, the astronomical definition is used,
     343             :   !!    i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
     344             :   !!    This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
     345             :   !!
     346             :   !!    \b Example
     347             :   !!
     348             :   !!    \code{.f90}
     349             :   !!    2415021 is 01.01.1900
     350             :   !!    call caldatJulian(2415021, dd, mm, yy)
     351             :   !!    \endcode
     352             :   !!
     353             :   !!    \b Literature
     354             :   !!    1.  http://de.wikipedia.org/wiki/Julianisches_Datum
     355             :   !!        which is different to the english Wiki\n
     356             :   !!    2.  http://en.wikipedia.org/wiki/Julian_day
     357             :   !!        It is essentially the same as Numerical Recipes but uses astronomical instead of historical units.
     358             : 
     359             : 
     360             :   !>    \param[in] "integer(i4) :: Julday"     Julian day
     361             :   !>    \param[out] "integer(i4) :: dd"         Day in month of Julian day
     362             :   !>    \param[out] "integer(i4) :: mm"         Month in year of Julian day
     363             :   !>    \param[out] "integer(i4) :: yy"         Year of Julian day
     364             : 
     365             :   !>    \note Julian day definition starts at noon of the 1st January 4713 BC.\n
     366             :   !!    Here, the astronomical definition is used,
     367             :   !!    i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
     368             :   !!    This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
     369             :   !!
     370             :   !!    julday and caldat start at midnight of the 1st January 4713 BC.
     371             :   !!    So date2decJulian and juldayJulian as well as dec2dateJulian and caldatJulian are shifted by half a day.\n
     372             :   !!    Use date2decJulian with dec2dateJulian together for fractional Julian dates
     373             :   !!    and use juldayJulian with caldatJulian together for integer Julian days.
     374             : 
     375             :   !>    \author Matthias Cuntz
     376             :   !>    \date Dec 2011
     377             :   !!      - modified julday from Numerical Recipes
     378             :   !>    \date May 2014
     379             :   !!      - changed to new algorithm with astronomical units
     380             :   !!      - removed numerical recipes
     381             : 
     382             :   !>    \author David Schaefer
     383             :   !>    \date Jan 2016
     384             :   !!      - renamed procodure
     385     5158863 :   ELEMENTAL SUBROUTINE caldatJulian(julian, dd, mm, yy)
     386             : 
     387             :     IMPLICIT NONE
     388             : 
     389             :     INTEGER(i4), INTENT(IN) :: julian
     390             :     INTEGER(i4), INTENT(OUT) :: dd, mm, yy
     391             : 
     392             :     INTEGER(i8) :: A, B, C, D, E, g
     393             :     INTEGER(i4), PARAMETER :: IGREG = 2299161_i4
     394             : 
     395     5158863 :     if (julian < IGREG) then
     396     4598411 :       A = int(julian, i8) ! julian
     397             :     else
     398      560452 :       g = int((real(julian, dp) - 1867216.25_dp) / 36524.25_dp, i8) ! gregorian
     399      560452 :       A = julian + 1_i8 + g - g / 4_i8
     400             :     end if
     401             : 
     402     5158863 :     B = A + 1524_i8
     403     5158863 :     C = int((real(B, dp) - 122.1_dp) / 365.25_dp, i8)
     404     5158863 :     D = int(365.25_dp * real(C, dp), i8)
     405     5158863 :     E = int(real(B - D, dp) / 30.6001_dp, i8)
     406             : 
     407     5158863 :     dd = int(B - D - int(30.6001_dp * real(E, dp), i8), i4)
     408             : 
     409     5158863 :     if (E<14_i8) then
     410     4322010 :       mm = int(E - 1_i8, i4)
     411             :     else
     412      836853 :       mm = int(E - 13_i8, i4)
     413             :     end if
     414             : 
     415     5158863 :     if (mm > 2) then
     416     4322010 :       yy = int(C - 4716_i8, i4)
     417             :     else
     418      836853 :       yy = int(C - 4715_i8, i4)
     419             :     end if
     420             : 
     421     4229276 :   END SUBROUTINE caldatJulian
     422             : 
     423             : 
     424             :   ! ------------------------------------------------------------------
     425             : 
     426             :   !>    \brief Fractional Julian day from day, month, year, hour, minute, second
     427             : 
     428             :   !>    \details In this routine date2decJulian returns the fractional Julian Day that begins at noon
     429             :   !!    of the calendar date specified by month mm, day dd, and year yy, all integer variables.
     430             :   !!
     431             :   !!    The zeroth Julian Day is 01.01.-4712 at noon, i.e. the 1st January 4713 BC 12:00:00 h.
     432             :   !!
     433             :   !!    Julian day definition starts at noon of the 1st January 4713 BC.\n
     434             :   !!    Here, the astronomical definition is used,
     435             :   !!    i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
     436             :   !!    This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
     437             :   !!
     438             :   !!    \b Example
     439             :   !!
     440             :   !!    2415020.5 is 01.01.1900 00:00
     441             :   !!    \code{.f90}
     442             :   !!    julian = date2decJulian(01,01,1990)
     443             :   !!    \endcode
     444             :   !!    \code{.f90}
     445             :   !!    2415021.0 is 01.01.1900 12:00
     446             :   !!    \endcode
     447             :   !!    julian = date2decJulian(01,01,1990,12,00)
     448             :   !!
     449             :   !!    \b Literature
     450             :   !!
     451             :   !!    1.  http://de.wikipedia.org/wiki/Julianisches_Datum
     452             :   !!        which is different to the english Wiki \n
     453             :   !!    2.  http://en.wikipedia.org/wiki/Julian_day
     454             :   !!        It is essentially the same as Numerical Recipes but uses astronomical instead of historical units.
     455             :   !!        Numerical regulation of fractions is after \n
     456             :   !!    3.  IDL routine julday.pro. Copyright (c) 1988-2011, ITT Visual Information Solutions.
     457             : 
     458             :   !>    \param[in] "integer(i4), optional :: dd"         Day in month of Julian day (default: 1)
     459             :   !>    \param[in] "integer(i4), optional :: mm"         Month in year of Julian day (default: 1)
     460             :   !>    \param[in] "integer(i4), optional :: yy"         Year of Julian day (default: 1)
     461             :   !>    \param[in] "integer(i4), optional :: hh"         Hours of Julian day (default: 0)
     462             :   !>    \param[in] "integer(i4), optional :: nn"         Minutes of hour of Julian day (default: 0)
     463             :   !>    \param[in] "integer(i4), optional :: ss"         Secondes of minute of hour of Julian day (default: 0)
     464             :   !>    \retval "real(dp) :: date2dec"                   Fractional Julian day
     465             : 
     466             :   !>    \note Julian day definition starts at noon of the 1st January 4713 BC.\n
     467             :   !!    Here, the astronomical definition is used,
     468             :   !!    i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
     469             :   !!    This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
     470             :   !!
     471             :   !!    juldayJulian and caldatJulian start at midnight of the 1st January 4713 BC.
     472             :   !!    So date2decJulian and juldayJulian as well as dec2dateJulian and caldatJulian are shifted by half a day.\n
     473             :   !!    Use date2decJulian with dec2dateJulian together for fractional Julian dates
     474             :   !!    and use juldayJulian with caldatJulian together for integer Julian days.
     475             : 
     476             :   !>    \author Matthias Cuntz
     477             :   !>    \date Jan 2013
     478             :   !>    \date May 2014
     479             :   !!      - changed to new algorithm with astronomical units
     480             :   !>      - removed numerical recipes
     481             : 
     482             :   !>    \author David Schaefer
     483             :   !>    \date Jan 2016
     484             :   !!      - renamed procodure
     485             : 
     486    20196767 :   ELEMENTAL FUNCTION date2decJulian(dd, mm, yy, hh, nn, ss)
     487             : 
     488             :     IMPLICIT NONE
     489             : 
     490             :     INTEGER(i4), INTENT(IN), OPTIONAL :: dd, mm, yy
     491             :     INTEGER(i4), INTENT(IN), OPTIONAL :: hh, nn, ss
     492             :     REAL(dp) :: date2decJulian
     493             : 
     494             :     INTEGER(i4), PARAMETER :: IGREG2 = 15 + 31 * (10 + 12 * 1582)
     495             :     INTEGER(i4), PARAMETER :: IGREG1 = 4 + 31 * (10 + 12 * 1582)
     496             :     INTEGER(i4) :: idd, imm, iyy
     497    20196767 :     REAL(dp) :: ihh, inn, iss
     498             :     INTEGER(i8) :: jm, jy
     499    20196767 :     REAL(dp) :: jd, H, eps
     500             :     INTEGER(i8) :: A, B
     501             : 
     502             :     ! Presets
     503    20196767 :     idd = 1
     504    20196767 :     if (present(dd)) idd = dd
     505    20196767 :     imm = 1
     506    20196767 :     if (present(mm)) imm = mm
     507    20196767 :     iyy = 1
     508    20196767 :     if (present(yy)) iyy = yy
     509    20196767 :     ihh = 0.0_dp
     510    20196767 :     if (present(hh)) ihh = real(hh, dp)
     511    20196767 :     inn = 0.0_dp
     512    20196767 :     if (present(nn)) inn = real(nn, dp)
     513    20196767 :     iss = 0.0_dp
     514    20196767 :     if (present(ss)) iss = real(ss, dp)
     515             : 
     516    20196767 :     if (imm > 2) then
     517    16920907 :       jm = int(imm, i8)
     518    16920907 :       jy = int(iyy, i8)
     519             :     else
     520     3275860 :       jm = int(imm + 12, i8)
     521     3275860 :       jy = int(iyy - 1, i8)
     522             :     end if
     523             : 
     524    20196767 :     jd = real(idd, dp)
     525             : 
     526    20196767 :     H = ihh / 24._dp + inn / 1440._dp + iss / 86400._dp
     527             : 
     528    20196767 :     if (dd + 31 * (mm + 12 * yy) >= IGREG2) then ! gregorian
     529     1803484 :       A = jy / 100_i8
     530     1803484 :       B = 2_i8 - A + A / 4_i8
     531    18393283 :     else if (dd + 31 * (mm + 12 * yy) <= IGREG1) then ! julian
     532    18393283 :       B = 0_i8
     533             :       ! else
     534             :       !    stop 'No Gregorian dates between 04.10.1582 and 15.10.1582'
     535             :     end if
     536             : 
     537             :     ! Fractional Julian day starts at noon
     538             :     date2decJulian = floor(365.25_dp * real(jy + 4716_i8, dp)) + &
     539    20196767 :             floor(30.6001_dp * real(jm + 1_i8, dp)) + jd + H + real(B, dp) - 1524.5_dp
     540             : 
     541             :     ! Add a small offset (proportional to julian date) for correct re-conversion.
     542    20196767 :     eps = epsilon(1.0_dp)
     543    20196767 :     eps = max(eps * abs(date2decJulian), eps)
     544    20196767 :     date2decJulian = date2decJulian + eps
     545             : 
     546     5158863 :   END FUNCTION date2decJulian
     547             : 
     548             :   ! ------------------------------------------------------------------
     549             : 
     550             :   !>    \brief Day, month, year, hour, minute, and second from fractional Julian day
     551             : 
     552             :   !>    \details Inverse of the function date2decJulian. Here dec2dateJulian is input as a fractional Julian Day,
     553             :   !!    which starts at noon of the 1st January 4713 BC, i.e. 01.01.-4712.
     554             :   !!    The routine outputs dd, mm, yy, hh, nn, ss as the day, month, year, hour, minute, and second
     555             :   !!    on which the specified Julian Day started at noon.
     556             :   !!
     557             :   !!    The zeroth Julian Day is 01.01.-4712 at noon, i.e. the 1st January 4713 BC at noon.
     558             :   !!
     559             :   !!    Julian day definition starts at 1st January 4713 BC.\n
     560             :   !!    Here, the astronomical definition is used,
     561             :   !!    i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
     562             :   !!    This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
     563             :   !!
     564             :   !!    \b Example
     565             :   !!
     566             :   !!    2415020.5 is 01.01.1900 00:00
     567             :   !!    \code{.f90}
     568             :   !!    call caldatJulian(2415020.5, dd, mm, yy, hh, nn)
     569             :   !!    \endcode
     570             :   !!    2415021.0 is 01.01.1900 12:00
     571             :   !!    \code{.f90}
     572             :   !!    call caldatJulian(2415021., dd, mm, yy, hh, nn, ss)
     573             :   !!    \endcode
     574             :   !!
     575             :   !!    \b Literature
     576             :   !!
     577             :   !!    1.  http://de.wikipedia.org/wiki/Julianisches_Datum
     578             :   !!        which is different to the english Wiki\n
     579             :   !!    2.  http://en.wikipedia.org/wiki/Julian_day
     580             :   !!        It is essentially the same as Numerical Recipes but uses astronomical instead of historical units.
     581             :   !!        Here the sometimes 60 sec as output are corrected at the end.
     582             : 
     583             :   !>    \param[in] "real(dp) :: fJulian"                  fractional Julian day
     584             :   !>    \param[out] "integer(i4), optional :: dd"         Day in month of Julian day
     585             :   !>    \param[out] "integer(i4), optional :: mm"         Month in year of Julian day
     586             :   !>    \param[out] "integer(i4), optional :: yy"         Year of Julian day
     587             :   !>    \param[out] "integer(i4), optional :: hh"         Hour of Julian day
     588             :   !>    \param[out] "integer(i4), optional :: nn"         Minute in hour of Julian day
     589             :   !>    \param[out] "integer(i4), optional :: ss"         Second in minute of hour of Julian day
     590             : 
     591             :   !>    \note Julian day definition starts at noon of the 1st January 4713 BC.\n
     592             :   !!    Here, the astronomical definition is used,
     593             :   !!    i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
     594             :   !!    This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
     595             :   !!
     596             :   !!    juldayJulian and caldatJulian start at midnight of the 1st January 4713 BC.
     597             :   !!    So date2decJulian and juldayJulian as well as dec2dateJulian and caldatJulian are shifted by half a day.\n
     598             :   !!    Use date2decJulian with dec2dateJulian together for fractional Julian dates
     599             :   !!    and use juldayJulian with caldatJulian together for integer Julian days.
     600             : 
     601             :   !>    \author Matthias Cuntz
     602             :   !>    \date Jan 2013
     603             :   !>    \date May 2014
     604             :   !!      - changed to new algorithm with astronomical units
     605             :   !>      - removed numerical recipes
     606             : 
     607             :   !>    \author David Schaefer
     608             :   !>    \date Jan 2016
     609             :   !!      - renamed procodure
     610    35345303 :   ELEMENTAL SUBROUTINE dec2dateJulian(julian, dd, mm, yy, hh, nn, ss)
     611             : 
     612             :     IMPLICIT NONE
     613             : 
     614             :     REAL(dp), INTENT(IN) :: julian
     615             :     INTEGER(i4), INTENT(OUT), OPTIONAL :: dd, mm, yy
     616             :     INTEGER(i4), INTENT(OUT), OPTIONAL :: hh, nn, ss
     617             : 
     618             :     INTEGER(i4) :: day, month, year, hour, minute, second
     619    35345303 :     REAL(dp) :: fraction
     620             :     ! REAL(dp)    :: eps
     621             : 
     622             :     INTEGER(i8) :: A, B, C, D, E, g, Z
     623             :     INTEGER(i4), PARAMETER :: IGREG = 2299161_i4
     624             : 
     625    35345303 :     Z = int(julian + 0.5, i8)
     626             : 
     627    35345303 :     if (Z < IGREG) then
     628             :       A = Z ! julian
     629             :     else
     630     3157062 :       g = int((real(Z, dp) - 1867216.25_dp) / 36524.25_dp, i8) ! gregorian
     631     3157062 :       A = Z + 1_i8 + g - g / 4_i8
     632             :     end if
     633             : 
     634    35345303 :     B = A + 1524_i8
     635    35345303 :     C = int((real(B, dp) - 122.1_dp) / 365.25_dp, i8)
     636    35345303 :     D = int(365.25_dp * real(C, dp), i8)
     637    35345303 :     E = int(real(B - D, dp) / 30.6001_dp, i8)
     638             : 
     639    35345303 :     day = int(B - D - int(30.6001_dp * real(E, dp), i8), i4)
     640             : 
     641    35345303 :     if (E<14_i8) then
     642    29612121 :       month = int(E - 1_i8, i4)
     643             :     else
     644     5733182 :       month = int(E - 13_i8, i4)
     645             :     end if
     646             : 
     647    35345303 :     if (month > 2) then
     648    29612121 :       year = int(C - 4716_i8, i4)
     649             :     else
     650     5733182 :       year = int(C - 4715_i8, i4)
     651             :     end if
     652             : 
     653             :     ! ! Fractional part
     654             :     ! eps = 1e-12_dp ! ~ 5000*epsilon(1.0_dp)
     655             :     ! eps = max(eps * abs(real(Z,dp)), eps)
     656             :     ! fraction = julian + 0.5_dp - real(Z,dp)
     657             :     ! hour     = min(max(floor(fraction * 24.0_dp + eps), 0), 23)
     658             :     ! fraction = fraction - real(hour,dp)/24.0_dp
     659             :     ! minute   = min(max(floor(fraction*1440.0_dp + eps), 0), 59)
     660             :     ! second   = max(nint((fraction - real(minute,dp)/1440.0_dp)*86400.0_dp), 0)
     661             : 
     662             :     ! Fractional part
     663    35345303 :     fraction = julian + 0.5_dp - real(Z, dp)
     664    35345303 :     hour = min(max(floor(fraction * 24.0_dp), 0), 23)
     665    35345303 :     fraction = fraction - real(hour, dp) / 24.0_dp
     666    35345303 :     minute = min(max(floor(fraction * 1440.0_dp), 0), 59)
     667    35345303 :     second = max(nint((fraction - real(minute, dp) / 1440.0_dp) * 86400.0_dp), 0)
     668             : 
     669             :     ! If seconds==60
     670    35345303 :     if (second==60) then
     671      148394 :       second = 0
     672      148394 :       minute = minute + 1
     673      148394 :       if (minute==60) then
     674        2553 :         minute = 0
     675        2553 :         hour = hour + 1
     676        2553 :         if (hour==24) then
     677          98 :           hour = 0
     678          98 :           call caldat(julday(day, month, year) + 1, day, month, year)
     679             :         end if
     680             :       end if
     681             :     end if
     682             : 
     683    35345303 :     if (present(dd)) dd = day
     684    35345303 :     if (present(mm)) mm = month
     685    35345303 :     if (present(yy)) yy = year
     686    35345303 :     if (present(hh)) hh = hour
     687    35345303 :     if (present(nn)) nn = minute
     688    35345303 :     if (present(ss)) ss = second
     689             : 
     690    20196767 :   END SUBROUTINE dec2dateJulian
     691             : 
     692             :   ! ------------------------------------------------------------------
     693             : 
     694             :   !>    \brief Julian day from day, month and year
     695             : 
     696             :   !>    \details In this routine juldayJulian returns the Julian Day Number that begins at noon of the calendar
     697             :   !!    date specified by month mm, day dd, and year yy, all integer variables.
     698             :   !!
     699             :   !!    The zeroth Julian Day is 01.01.-4712 at noon, i.e. the 1st January 4713 BC 12:00:00 h.
     700             :   !!
     701             :   !!    Julian day definition starts at noon of the 1st January 4713 BC.\n
     702             :   !!    Here, the astronomical definition is used,
     703             :   !!    i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
     704             :   !!    This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
     705             :   !!
     706             :   !!    \b Example
     707             :   !!
     708             :   !!    2415021 is 01.01.1900 and 2440588 is 01.01.1970
     709             :   !!    \code{.f90}
     710             :   !!    julian = juldayJulian(01,01,1990)
     711             :   !!    \endcode
     712             :   !!    See also example in test directory
     713             :   !!
     714             :   !!    \b Literature
     715             :   !!    1.  http://de.wikipedia.org/wiki/Julianisches_Datum
     716             :   !!        which is different to the english Wiki \n
     717             :   !!    2.  http://en.wikipedia.org/wiki/Julian_day
     718             :   !!        It is essentially the same as Numerical Recipes but uses astronomical instead of historical units.
     719             : 
     720             :   !>    \param[in] "integer(i4) :: dd"         Day in month of Julian day
     721             :   !>    \param[in] "integer(i4) :: mm"         Month in year of Julian day
     722             :   !>    \param[in] "integer(i4) :: yy"         Year of Julian day
     723             :   !>    \retval "integer(i4) :: julian"        Julian day
     724             : 
     725             :   !>    \note Julian day definition starts at noon of the 1st January 4713 BC.\n
     726             :   !!    Here, the astronomical definition is used,
     727             :   !!    i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
     728             :   !!    This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
     729             :   !!
     730             :   !!    juldayJulian and caldatJulian start at midnight of the 1st January 4713 BC.
     731             :   !!    So date2decJulian and juldayJulian as well as dec2dateJulian and caldatJulian are shifted by half a day.\n
     732             :   !!    Use date2decJulian with dec2dateJulian together for fractional Julian dates
     733             :   !!    and use juldayJulian with caldatJulian together for integer Julian days.
     734             : 
     735             :   !>    \author Matthias Cuntz
     736             :   !>    \date Dec 2011
     737             :   !!              - modified julday from Numerical Recipes
     738             :   !>    \date May 2014
     739             :   !!              - changed to new algorithm with astronomical units
     740             :   !!              - removed numerical recipes
     741             :   !>    \author David Schaefer
     742             :   !>    \date Jan 2016
     743             :   !!              - renamed procodure
     744     2634272 :   ELEMENTAL FUNCTION juldayJulian(dd, mm, yy)
     745             : 
     746             :     IMPLICIT NONE
     747             : 
     748             :     INTEGER(i4), INTENT(IN) :: dd, mm, yy
     749             :     INTEGER(i4) :: juldayJulian
     750             : 
     751             :     INTEGER(i4), PARAMETER :: IGREG2 = 15 + 31 * (10 + 12 * 1582)
     752             :     INTEGER(i4), PARAMETER :: IGREG1 = 4 + 31 * (10 + 12 * 1582)
     753             :     INTEGER(i8) :: jd, jm, jy
     754             :     INTEGER(i8) :: A, B
     755             : 
     756     2634272 :     if (mm > 2) then
     757     2206948 :       jm = int(mm, i8)
     758     2206948 :       jy = int(yy, i8)
     759             :     else
     760      427324 :       jm = int(mm + 12, i8)
     761      427324 :       jy = int(yy - 1, i8)
     762             :     end if
     763             : 
     764     2634272 :     jd = int(dd, i8)
     765             : 
     766     2634272 :     if (dd + 31 * (mm + 12 * yy) >= IGREG2) then ! gregorian
     767      335021 :       A = jy / 100_i8
     768      335021 :       B = 2_i8 - A + A / 4_i8
     769     2299251 :     else if (dd + 31 * (mm + 12 * yy) <= IGREG1) then ! julian
     770     2299251 :       B = 0_i8
     771             :       ! else
     772             :       !    stop 'No Gregorian dates between 04.10.1582 and 15.10.1582'
     773             :     end if
     774             : 
     775             :     ! add 0.5 to Wiki formula because formula was for fractional day
     776             :     ! juldayJulian = int(365.25_dp*real(jy+4716_i8,dp) + real(int(30.6001*real(jm+1_i8,dp),i8),dp) + real(jd+B,dp) - 1524.5_dp, i4)
     777             :     juldayJulian = int(365.25_dp * real(jy + 4716_i8, dp) + real(int(30.6001 * real(jm + 1_i8, dp), i8), dp) &
     778     2634272 :             + real(jd + B, dp) - 1524.5_dp + 0.5_dp, i4)
     779             : 
     780    35345303 :   END FUNCTION juldayJulian
     781             : 
     782             :   ! ------------------------------------------------------------------
     783             : 
     784             :   !>    \brief IMSL Julian day from day, month and year
     785             : 
     786             :   !>    \details In this routine ndays returns the IMSL Julian Day Number. Julian days begin at noon of the calendar
     787             :   !!    date specified by month mm, day dd, and year yy, all integer variables. IMSL treats 01.01.1900
     788             :   !!    as a reference and assigns a Julian day 0 to it.
     789             :   !!
     790             :   !!    ndays = julday(dd,mm,yy) - julday(01,01,1900)
     791             :   !!
     792             :   !!    \b Example
     793             :   !!
     794             :   !!    0 is 01.01.1900
     795             :   !!    \code{.f90}
     796             :   !!    julian = ndays(01,01,1990)
     797             :   !!    \endcode
     798             :   !!    See also example in test directory
     799             : 
     800             :   !>    \param[in] "integer(i4) :: dd"         Day in month of IMSL Julian day
     801             :   !>    \param[in] "integer(i4) :: mm"         Month in year of IMSL Julian day
     802             :   !>    \param[in] "integer(i4) :: yy"         Year of IMSL Julian day
     803             :   !>    \retval "integer(i4) :: julian"        IMSL Julian day, i.e. days before or after 01.01.1900
     804             : 
     805             :   !>    \author Matthias Cuntz
     806             :   !>    \date Dec 2011
     807             : 
     808      109576 :   ELEMENTAL FUNCTION ndays(dd, mm, yy)
     809             : 
     810             :     IMPLICIT NONE
     811             : 
     812             :     INTEGER(i4), INTENT(IN) :: dd, mm, yy
     813             :     INTEGER(i4) :: ndays
     814             : 
     815             :     INTEGER(i4), PARAMETER :: IMSLday = 2415021_i4
     816             : 
     817      109576 :     ndays = julday(dd, mm, yy) - IMSLday
     818             : 
     819     2634272 :   END FUNCTION ndays
     820             : 
     821             :   ! ------------------------------------------------------------------
     822             : 
     823             :   !>    \brief Day, month and year from IMSL Julian day
     824             : 
     825             :   !>    \details Inverse of the function ndys. Here ISML Julian is input as a Julian Day Number
     826             :   !!    minus the Julian Day Number of 01.01.1900, and the routine outputs id, mm, and yy
     827             :   !!    as the day, month, and year on which the specified Julian Day started at noon.
     828             :   !!
     829             :   !!    ndyin is caldat(IMSLJulian + 2415021, dd, mm, yy)
     830             :   !!
     831             :   !!    \b Example
     832             :   !!
     833             :   !!    0 is 01.01.1900
     834             :   !!    \code{.f90}
     835             :   !!    call ndyin(0,dd,mm,yy)
     836             :   !!    \endcode
     837             :   !!    See also example in test directory
     838             : 
     839             :   !>    \param[in] "integer(i4) :: julian"     IMSL Julian day, i.e. days before or after 01.01.1900
     840             :   !>    \param[out] "integer(i4) :: dd"         Day in month of IMSL Julian day
     841             :   !>    \param[out] "integer(i4) :: mm"         Month in year of IMSL Julian day
     842             :   !>    \param[out] "integer(i4) :: yy"         Year of IMSL Julian day
     843             : 
     844             :   !>    \author Matthias Cuntz
     845             :   !>    \date Dec 2011
     846             : 
     847      109576 :   ELEMENTAL SUBROUTINE ndyin(julian, dd, mm, yy)
     848             : 
     849             :     IMPLICIT NONE
     850             : 
     851             :     INTEGER(i4), INTENT(IN) :: julian
     852             :     INTEGER(i4), INTENT(OUT) :: dd, mm, yy
     853             : 
     854             :     INTEGER(i4), PARAMETER :: IMSLday = 2415021_i4
     855             : 
     856      109576 :     call caldat(julian + IMSLday, dd, mm, yy)
     857             : 
     858      219152 :   END SUBROUTINE ndyin
     859             : 
     860             :   ! ------------------------------------------------------------------
     861             : 
     862             :   !>    \brief Day, month and year from Julian day in a 360 day calendar
     863             : 
     864             :   !>    \details Inverse of the function julday360. Here julian is input as a Julian Day Number,
     865             :   !!    and the routine outputs dd, mm, and yy as the day, month, and year on which the specified
     866             :   !!    Julian Day started at noon.
     867             :   !!
     868             :   !!    The zeroth Julian Day here is 01.01.0000
     869             :   !!
     870             :   !!    \b Example
     871             :   !!
     872             :   !!    \code{.f90}
     873             :   !!    call caldat360(julday, dd, mm, yy)
     874             :   !!    \endcode
     875             : 
     876             :   !>    \param[in] "integer(i4) :: julday"     Julian day
     877             :   !>    \param[out] "integer(i4) :: dd"         Day in month of Julian day
     878             :   !>    \param[out] "integer(i4) :: mm"         Month in year of Julian day
     879             :   !>    \param[out] "integer(i4) :: yy"         Year of Julian day
     880             : 
     881             :   !>    \author  David Schaefer
     882             :   !>    \date Oct 2015
     883    31385570 :   elemental subroutine caldat360(julian, dd, mm, yy)
     884             : 
     885             :     implicit none
     886             : 
     887             :     integer(i4), intent(in) :: julian
     888             :     integer(i4), intent(out) :: dd, mm, yy
     889             :     integer(i4), parameter :: year = 360, month = 30
     890             :     integer(i4) :: remainder
     891             : 
     892    31385570 :     yy = julian / year
     893    31385570 :     remainder = mod(abs(julian), year)
     894    31385570 :     mm = remainder / month + 1
     895    31385570 :     dd = mod(abs(julian), month) + 1
     896             : 
     897      109576 :   end subroutine caldat360
     898             : 
     899             :   ! ------------------------------------------------------------------
     900             : 
     901             :   !>    \brief Julian day from day, month and year in a 360_day calendar
     902             : 
     903             :   !>    \details In this routine julday360 returns the Julian Day Number that begins at noon of the calendar
     904             :   !!    date specified by month mm, day dd, and year yy, all integer variables.
     905             :   !!
     906             :   !!    The zeroth Julian Day is 01.01.0000
     907             :   !!
     908             :   !!    \b Example
     909             :   !!
     910             :   !!    \code{.f90}
     911             :   !!    julian = julday360(dd, mm, yy)
     912             :   !!    \endcode
     913             : 
     914             :   !>    \param[in] "integer(i4) :: dd"         Day in month of Julian day
     915             :   !>    \param[in] "integer(i4) :: mm"         Month in year of Julian day
     916             :   !>    \param[in] "integer(i4) :: yy"         Year of Julian day
     917             :   !>    \retval "integer(i4) :: julian"        Julian day
     918             : 
     919             :   !>    \author David Schaefer
     920             :   !>    \date Oct 2015
     921    16128435 :   elemental function julday360(dd, mm, yy)
     922             : 
     923             :     implicit none
     924             : 
     925             :     integer(i4), intent(in) :: dd, mm, yy
     926             :     integer(i4) :: julday360
     927             :     integer(i4), parameter :: year = 360, month = 30
     928             : 
     929    16128435 :     julday360 = abs(yy) * year + (mm - 1) * month + (dd - 1)
     930           2 :     if (yy < 0) julday360 = julday360 * (-1)
     931             : 
     932    47514005 :   end function julday360
     933             : 
     934             :   ! ------------------------------------------------------------------
     935             : 
     936             :   !>    \brief Day, month, year, hour, minute, and second from fractional Julian day in a 360_day calendar
     937             : 
     938             :   !>    \details Inverse of the function date2dec360. Here dec2date360 is input as a fractional Julian Day.
     939             :   !!    The routine outputs dd, mm, yy, hh, nn, ss as the day, month, year, hour, minute, and second
     940             :   !!    on which the specified Julian Day started at noon.
     941             :   !!
     942             :   !!    The zeroth Julian Day is 01.01.0000 at noon.
     943             :   !!
     944             :   !!    \b Example
     945             :   !!
     946             :   !!    \code{.f90}
     947             :   !!    call dec2date360(fJulian, dd, mm, yy, hh, nn, ss)
     948             :   !!    \endcode
     949             : 
     950             :   !>    \param[in] "real(dp) :: fJulian"     fractional Julian day
     951             :   !>    \param[out] "integer(i4), optional :: dd"         Day in month of Julian day
     952             :   !>    \param[out] "integer(i4), optional :: mm"         Month in year of Julian day
     953             :   !>    \param[out] "integer(i4), optional :: yy"         Year of Julian day
     954             :   !>    \param[out] "integer(i4), optional :: hh"         Hour of Julian day
     955             :   !>    \param[out] "integer(i4), optional :: nn"         Minute in hour of Julian day
     956             :   !>    \param[out] "integer(i4), optional :: ss"         Second in minute of hour of Julian day
     957             : 
     958             :   !>    \author David Schaefer
     959             :   !>    \date Oct 2015
     960    30514285 :   elemental subroutine dec2date360(julian, dd, mm, yy, hh, nn, ss)
     961             : 
     962             :     implicit none
     963             : 
     964             :     real(dp), intent(in) :: julian
     965             :     integer(i4), intent(out), optional :: dd, mm, yy
     966             :     integer(i4), intent(out), optional :: hh, nn, ss
     967             :     integer(i4) :: day, month, year
     968    30514285 :     real(dp) :: fraction, fJulian
     969             :     integer(i4) :: hour, minute, second
     970             : 
     971    30514285 :     fJulian = julian + .5_dp
     972    30514285 :     call caldat360(int(floor(fJulian), i4), day, month, year)
     973             : 
     974    30514285 :     fraction = fJulian - floor(fJulian)
     975    30514285 :     hour = min(max(floor(fraction * 24.0_dp), 0), 23)
     976    30514285 :     fraction = fraction - real(hour, dp) / 24.0_dp
     977    30514285 :     minute = min(max(floor(fraction * 1440.0_dp), 0), 59)
     978    30514285 :     second = max(nint((fraction - real(minute, dp) / 1440.0_dp) * 86400.0_dp), 0)
     979             : 
     980             :     ! If seconds==60
     981    30514285 :     if (second==60) then
     982      127327 :       second = 0
     983      127327 :       minute = minute + 1
     984      127327 :       if (minute==60) then
     985        2078 :         minute = 0
     986        2078 :         hour = hour + 1
     987        2078 :         if (hour==24) then
     988          83 :           hour = 0
     989          83 :           call caldat360(julday360(day, month, year) + 1, day, month, year)
     990             :         end if
     991             :       end if
     992             :     end if
     993             : 
     994    30514285 :     if (present(dd)) dd = day
     995    30514285 :     if (present(mm)) mm = month
     996    30514285 :     if (present(yy)) yy = year
     997    30514285 :     if (present(hh)) hh = hour
     998    30514285 :     if (present(nn)) nn = minute
     999    30514285 :     if (present(ss)) ss = second
    1000             : 
    1001    16128435 :   end subroutine dec2date360
    1002             : 
    1003             :   ! ------------------------------------------------------------------
    1004             : 
    1005             :   !>    \brief Fractional Julian day from day, month, year, hour, minute, second in 360 day calendar
    1006             : 
    1007             :   !>    \details In this routine date2dec360 returns the fractional Julian Day that begins at noon
    1008             :   !!    of the calendar date specified by month mm, day dd, and year yy, all integer variables.
    1009             :   !!
    1010             :   !!    The zeroth Julian Day is 01.01.0000 at noon.
    1011             :   !!
    1012             :   !!    \b Example
    1013             :   !!
    1014             :   !!    \code{.f90}
    1015             :   !!    date2dec360 = date2dec360(dd, mm, yy, hh, nn, ss)
    1016             :   !!    \endcode
    1017             : 
    1018             :   !>    \param[in] "integer(i4), optional :: dd"         Day in month of Julian day (default: 1)
    1019             :   !>    \param[in] "integer(i4), optional :: mm"         Month in year of Julian day (default: 1)
    1020             :   !>    \param[in] "integer(i4), optional :: yy"         Year of Julian day (default: 1)
    1021             :   !>    \param[in] "integer(i4), optional :: hh"         Hours of Julian day (default: 0)
    1022             :   !>    \param[in] "integer(i4), optional :: nn"         Minutes of hour of Julian day (default: 0)
    1023             :   !>    \param[in] "integer(i4), optional :: ss"         Secondes of minute of hour of Julian day (default: 0)
    1024             :   !>    \retval "real(dp) :: date2dec360"                 Fractional Julian day
    1025             : 
    1026             :   !>    \author David Schaefer
    1027             :   !>    \date Oct 2015
    1028    15336350 :   elemental function date2dec360(dd, mm, yy, hh, nn, ss)
    1029             : 
    1030             :     implicit none
    1031             : 
    1032             :     integer(i4), intent(in), optional :: dd, mm, yy
    1033             :     integer(i4), intent(in), optional :: hh, nn, ss
    1034    15336350 :     real(dp) :: date2dec360, eps
    1035             :     integer(i4) :: idd, imm, iyy
    1036    15336350 :     real(dp) :: ihh, inn, iss
    1037    15336350 :     real(dp) :: hour
    1038             : 
    1039             :     ! Presets
    1040    15336350 :     idd = 1
    1041    15336350 :     if (present(dd)) idd = dd
    1042    15336350 :     imm = 1
    1043    15336350 :     if (present(mm)) imm = mm
    1044    15336350 :     iyy = 1
    1045    15336350 :     if (present(yy)) iyy = yy
    1046    15336350 :     ihh = 0.0_dp
    1047    15336350 :     if (present(hh)) ihh = real(hh, dp)
    1048    15336350 :     inn = 0.0_dp
    1049    15336350 :     if (present(nn)) inn = real(nn, dp)
    1050    15336350 :     iss = 0.0_dp
    1051    15336350 :     if (present(ss)) iss = real(ss, dp)
    1052             : 
    1053    15336350 :     hour = ihh / 24._dp + inn / 1440._dp + iss / 86400._dp - .5_dp
    1054             : 
    1055             :     ! Fractional Julian day starts at noon
    1056    15336350 :     date2dec360 = real(julday360(idd, imm, iyy), dp) + hour
    1057             : 
    1058             :     ! Add a small offset (proportional to julian date) for correct re-conversion.
    1059    15336350 :     eps = epsilon(1.0_dp)
    1060    15336350 :     eps = max(eps * abs(date2dec360), eps)
    1061    15336350 :     date2dec360 = date2dec360 + eps
    1062             : 
    1063    30514285 :   end function date2dec360
    1064             : 
    1065             :   ! ------------------------------------------------------------------
    1066             : 
    1067             :   !>    \brief Day, month and year from Julian day in a 365 day calendar
    1068             : 
    1069             :   !>    \details Inverse of the function julday365. Here julian is input as a Julian Day Number,
    1070             :   !!    and the routine outputs dd, mm, and yy as the day, month, and year on which the specified
    1071             :   !!    Julian Day started at noon.
    1072             :   !!
    1073             :   !!    The zeroth Julian Day here is 01.01.0000
    1074             :   !!
    1075             :   !!    \b Example
    1076             :   !!
    1077             :   !!    \code{.f90}
    1078             :   !!    call caldat365(julday, dd, mm, yy)
    1079             :   !!    \endcode
    1080             : 
    1081             :   !>    \param[in] "integer(i4) :: julday"     Julian day
    1082             :   !>    \param[out] "integer(i4) :: dd"         Day in month of Julian day
    1083             :   !>    \param[out] "integer(i4) :: mm"         Month in year of Julian day
    1084             :   !>    \param[out] "integer(i4) :: yy"         Year of Julian day
    1085             : 
    1086             :   !>    \author David Schaefer
    1087             :   !>    \date Dec 2015
    1088    12848044 :   elemental subroutine caldat365(julian, dd, mm, yy)
    1089             : 
    1090             :     implicit none
    1091             : 
    1092             :     integer(i4), intent(in) :: julian
    1093             :     integer(i4), intent(out) :: dd, mm, yy
    1094             :     integer(i4), parameter :: year = 365
    1095             :     integer(i4), dimension(12), parameter :: months = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
    1096             :     integer(i4) :: remainder
    1097             : 
    1098    12848044 :     yy = julian / year
    1099    12848044 :     remainder = mod(abs(julian), year) + 1
    1100             : 
    1101    83847408 :     do mm = 1, size(months)
    1102    83847408 :       if (remainder .le. months(mm)) then
    1103             :         exit
    1104             :       end if
    1105    83847408 :       remainder = remainder - months(mm)
    1106             :     end do
    1107             : 
    1108    12848044 :     dd = remainder
    1109             : 
    1110    15336350 :   end subroutine caldat365
    1111             : 
    1112             :   ! ------------------------------------------------------------------
    1113             : 
    1114             :   !>    \brief Julian day from day, month and year in a 365_day calendar
    1115             : 
    1116             :   !>    \details In this routine julday365 returns the Julian Day Number that begins at noon of the calendar
    1117             :   !!    date specified by month mm, day dd, and year yy, all integer variables.
    1118             :   !!
    1119             :   !!    The zeroth Julian Day is 01.01.0000
    1120             :   !!
    1121             :   !!    \b Example
    1122             :   !!
    1123             :   !!    \code{.f90}
    1124             :   !!    julian = julday365(dd, mm, yy)
    1125             :   !!    \endcode
    1126             : 
    1127             :   !>    \param[in] "integer(i4) :: dd"         Day in month of Julian day
    1128             :   !>    \param[in] "integer(i4) :: mm"         Month in year of Julian day
    1129             :   !>    \param[in] "integer(i4) :: yy"         Year of Julian day
    1130             :   !>    \retval "integer(i4) :: julian"        Julian day
    1131             : 
    1132             :   !>    \author David Schaefer
    1133             :   !>    \date Dec 2015
    1134     7227046 :   elemental function julday365(dd, mm, yy)
    1135             : 
    1136             :     implicit none
    1137             : 
    1138             :     integer(i4), intent(in) :: dd, mm, yy
    1139             :     integer(i4) :: julday365
    1140             :     integer(i4), parameter :: year = 365
    1141             :     integer(i4), dimension(12), parameter :: months = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
    1142             : 
    1143    47164393 :     julday365 = abs(yy) * year + sum(months(1 : mm - 1)) + (dd - 1)
    1144             : 
    1145     7227046 :     if (yy < 0) julday365 = julday365 * (-1)
    1146             : 
    1147    12848044 :   end function julday365
    1148             : 
    1149             :   ! ------------------------------------------------------------------
    1150             : 
    1151             :   !>    \brief Day, month, year, hour, minute, and second from fractional Julian day in a 365_day calendar
    1152             : 
    1153             :   !>    \details Inverse of the function date2dec. Here dec2date365 is input as a fractional Julian Day.
    1154             :   !!    The routine outputs dd, mm, yy, hh, nn, ss as the day, month, year, hour, minute, and second
    1155             :   !!    on which the specified Julian Day started at noon.
    1156             :   !!
    1157             :   !!    The zeroth Julian Day is 01.01.0000 at noon.
    1158             :   !!
    1159             :   !!    \b Example
    1160             :   !!
    1161             :   !!    \code{.f90}
    1162             :   !!    call dec2date365(fJulian, dd, mm, yy, hh, nn, ss)
    1163             :   !!    \endcode
    1164             : 
    1165             :   !>    \param[in] "real(dp) :: fJulian"                  fractional Julian day
    1166             :   !>    \param[out] "integer(i4), optional :: dd"         Day in month of Julian day
    1167             :   !>    \param[out] "integer(i4), optional :: mm"         Month in year of Julian day
    1168             :   !>    \param[out] "integer(i4), optional :: yy"         Year of Julian day
    1169             :   !>    \param[out] "integer(i4), optional :: hh"         Hour of Julian day
    1170             :   !>    \param[out] "integer(i4), optional :: nn"         Minute in hour of Julian day
    1171             :   !>    \param[out] "integer(i4), optional :: ss"         Second in minute of hour of Julian day
    1172             : 
    1173             :   !>    \author David Schaefer
    1174             :   !>    \date Dec 2015
    1175    11242011 :   elemental subroutine dec2date365(julian, dd, mm, yy, hh, nn, ss)
    1176             : 
    1177             :     implicit none
    1178             : 
    1179             :     real(dp), intent(in) :: julian
    1180             :     integer(i4), intent(out), optional :: dd, mm, yy
    1181             :     integer(i4), intent(out), optional :: hh, nn, ss
    1182             :     integer(i4) :: day, month, year
    1183    11242011 :     real(dp) :: fraction, fJulian
    1184             :     integer(i4) :: hour, minute, second
    1185             : 
    1186    11242011 :     fJulian = julian + .5_dp
    1187    11242011 :     call caldat365(int(floor(fJulian), i4), day, month, year)
    1188             : 
    1189    11242011 :     fraction = fJulian - floor(fJulian)
    1190    11242011 :     hour = min(max(floor(fraction * 24.0_dp), 0), 23)
    1191    11242011 :     fraction = fraction - real(hour, dp) / 24.0_dp
    1192    11242011 :     minute = min(max(floor(fraction * 1440.0_dp), 0), 59)
    1193    11242011 :     second = max(nint((fraction - real(minute, dp) / 1440.0_dp) * 86400.0_dp), 0)
    1194             : 
    1195             :     ! If seconds==60
    1196    11242011 :     if (second==60) then
    1197       46482 :       second = 0
    1198       46482 :       minute = minute + 1
    1199       46482 :       if (minute==60) then
    1200         782 :         minute = 0
    1201         782 :         hour = hour + 1
    1202         782 :         if (hour==24) then
    1203          31 :           hour = 0
    1204          31 :           call caldat365(julday365(day, month, year) + 1, day, month, year)
    1205             :         end if
    1206             :       end if
    1207             :     end if
    1208             : 
    1209    11242011 :     if (present(dd)) dd = day
    1210    11242011 :     if (present(mm)) mm = month
    1211    11242011 :     if (present(yy)) yy = year
    1212    11242011 :     if (present(hh)) hh = hour
    1213    11242011 :     if (present(nn)) nn = minute
    1214    11242011 :     if (present(ss)) ss = second
    1215             : 
    1216     7227046 :   end subroutine dec2date365
    1217             : 
    1218             :   ! ------------------------------------------------------------------
    1219             : 
    1220             :   !>    \brief Fractional Julian day from day, month, year, hour, minute, second in 365 day calendar
    1221             : 
    1222             :   !>    \details In this routine date2dec365 returns the fractional Julian Day that begins at noon
    1223             :   !!    of the calendar date specified by month mm, day dd, and year yy, all integer variables.
    1224             :   !!
    1225             :   !!    The zeroth Julian Day is 01.01.0000 at noon.
    1226             :   !!
    1227             :   !!    \b Example
    1228             :   !!
    1229             :   !!    \code{.f90}
    1230             :   !!    date2dec365 = date2dec365(dd, mm, yy, hh, nn, ss)
    1231             :   !!    \endcode
    1232             : 
    1233             :   !>    \param[in] "integer(i4), optional :: dd"        Day in month of Julian day (default: 1)
    1234             :   !>    \param[in] "integer(i4), optional :: mm"        Month in year of Julian day (default: 1)
    1235             :   !>    \param[in] "integer(i4), optional :: yy"        Year of Julian day (default: 1)
    1236             :   !>    \param[in] "integer(i4), optional :: hh"        Hours of Julian day (default: 0)
    1237             :   !>    \param[in] "integer(i4), optional :: nn"        Minutes of hour of Julian day (default: 0)
    1238             :   !>    \param[in] "integer(i4), optional :: ss"        Secondes of minute of hour of Julian day (default: 0)
    1239             :   !>    \retval "real(dp) :: date2dec365"               Fractional Julian day
    1240             : 
    1241             :   !>    \author David Schaefer
    1242             :   !>    \date Dec 2015
    1243     6424013 :   elemental function date2dec365(dd, mm, yy, hh, nn, ss)
    1244             : 
    1245             :     implicit none
    1246             : 
    1247             :     integer(i4), intent(in), optional :: dd, mm, yy
    1248             :     integer(i4), intent(in), optional :: hh, nn, ss
    1249     6424013 :     real(dp) :: date2dec365, eps
    1250             :     integer(i4) :: idd, imm, iyy
    1251     6424013 :     real(dp) :: ihh, inn, iss
    1252     6424013 :     real(dp) :: hour
    1253             : 
    1254             :     ! Presets
    1255     6424013 :     idd = 1
    1256     6424013 :     if (present(dd)) idd = dd
    1257     6424013 :     imm = 1
    1258     6424013 :     if (present(mm)) imm = mm
    1259     6424013 :     iyy = 1
    1260     6424013 :     if (present(yy)) iyy = yy
    1261     6424013 :     ihh = 0.0_dp
    1262     6424013 :     if (present(hh)) ihh = real(hh, dp)
    1263     6424013 :     inn = 0.0_dp
    1264     6424013 :     if (present(nn)) inn = real(nn, dp)
    1265     6424013 :     iss = 0.0_dp
    1266     6424013 :     if (present(ss)) iss = real(ss, dp)
    1267             : 
    1268     6424013 :     hour = ihh / 24._dp + inn / 1440._dp + iss / 86400._dp - .5_dp
    1269             : 
    1270             :     ! Fractional Julian day starts at noon
    1271     6424013 :     date2dec365 = real(julday365(idd, imm, iyy), dp) + hour
    1272             : 
    1273             :     ! Add a small offset (proportional to julian date) for correct re-conversion.
    1274     6424013 :     eps = epsilon(1.0_dp)
    1275     6424013 :     eps = max(eps * abs(date2dec365), eps)
    1276     6424013 :     date2dec365 = date2dec365 + eps
    1277             : 
    1278    11242011 :   end function date2dec365
    1279             : 
    1280             : 
    1281             :   ! ------------------------------------------------------------------
    1282             : 
    1283             : END MODULE mo_julian

Generated by: LCOV version 1.16