Daniel Mutton
Daniel Mutton

Reputation: 103

Fortran rounding decimals to .0 from netcdf file

I have a fortran 90 function that is meant to parse a time stamp in the form day as %Y%m%d.%f where %f is fraction of a day /48 and return an array with year, month, day, fraction of day.

function parseTimeStamp (timeStamp)

    implicit none

    real, dimension(5) :: parseTimeStamp
    real, intent(in)   :: timeStamp
    real               :: date, moment
    integer            :: intdate, day, month, year, t

    date = floor(timeStamp) ! remove the part days
    parseTimeStamp(4) = timeStamp - date ! save the part days

    intdate = int(date)
    day = mod(intdate,100);   intdate = intdate / 100
    month = mod(intdate,100); intdate = intdate / 100
    year = intdate
    parseTimeStamp(1) = real(year)
    parseTimeStamp(2) = real(month)
    parseTimeStamp(3) = real(day)

  end function parseTimeStamp

The issue is the output shows fraction of the day always at 0. When printing the timestamp (!print *, timeStamp) I get the date without fraction of the day 48 times before rolling over to the next day, even when I know with 100% certainty the data being read contains the proper fraction.

ex: I am getting

20220101.0 20220101.0 20220101.0 .... 20220102.0 20220102.0 ...

instead of

20220101.0 20220101.02083 20220101.04167 .... 20220102.0 20220102.02083 ...

I've tried using several different input files and have confirmed that the input files contain the part day data.

Upvotes: 0

Views: 101

Answers (1)

lastchance
lastchance

Reputation: 6600

I think you would be better creating a user-defined type to hold your date and time variables than to try to return an array. Year, month and day are more naturally whole numbers (integer type). If you want higher precision use kind=real64 from iso_fortran_env (worth looking up: it has other goodies in that make codes portable).

program test
   use iso_fortran_env
   implicit none
   integer y, m, d           ! year, month, day
   real(real64) f            ! fraction of a day

   call parseTimeStamp( "20220101.02083", y, m, d, f )
   write( *, "( 3(a, ': ', i0, :, / ) )" ) "year", y, "month", m, "day", d
   write( *, "( a, ': ', f7.5 )" ) "fraction", f

contains

   subroutine parseTimeStamp( dateTime, year, month, day, dayfraction )
      character(len=*), intent(in) :: dateTime
      integer, intent(out) :: year, month, day
      real(real64), intent(out) :: dayfraction
      real(real64) temp

      ! *** TO DO *** check that timestamp is well formed before anything else

      read( dateTime(1:4), * ) year
      read( dateTime(5:6), * ) month
      read( dateTime(7: ), * ) temp
      day = temp
      dayfraction = temp - day

   end subroutine parseTimeStamp

end program test
year: 2022
month: 1
day: 1
fraction: 0.02083

If you want to go with a user-defined type then you can return that from a function:

module timemod
   use iso_fortran_env
   implicit none

   type DTime
      integer year
      integer month
      integer day
      real(real64) fraction  ! fraction of a day
   end type DTime

contains

   type(DTime) function parseTimeStamp( dateStamp ) result( res )
      character(len=*), intent(in) :: dateStamp
      real(real64) temp

      read( dateStamp(1:4), * ) res%year
      read( dateStamp(5:6), * ) res%month
      read( dateStamp(7: ), * ) temp
      res%day = temp
      res%fraction = temp - res%day

   end function parseTimeStamp

end module timemod

!=======================================================================

program test
   use iso_fortran_env
   use timemod
   implicit none

   write( *, "( 3( i0, / ), f7.5 )" ) parseTimeStamp( "20220101.02083" )

end program test

Upvotes: 1

Related Questions