Search code examples
fortranpure-function

Have time in a pure manner in Fortran?


I am looking for a pure way to have access to time information. I thought about intrinsic functions and subroutines of standards compiler (date_and_time,cpu_time, system_clock, ltime, ctime, ...), the format do not really matter to me. I also thought about MPI function, but it is the same as intrinsic functions, there are all impure functions.

Here is a minimal example:

elemental subroutine add(message, text)
  ! function add
  IMPLICIT NONE
  character(len=:),allocatable,intent(inout)   :: message
  character(len=*), intent(in)                 :: text
  character(len=1), parameter                  :: nl=char(10)
  character(10) :: time
  ! character(8)  :: date

  ! time= 'hhmmss.sss'
  call DATE_AND_TIME(time) 
  Message= Message//time////text//nl

end subroutine add

and I get a logical error :

Error: Subroutine call to intrinsic ‘date_and_time’ at (1) is not PURE  

Thus, I am wandering if a pure way to have a time information exists, or if it is impossible to have it purely (maybe because it has to use cpu information which, for a reason unknown to me, could be thread-unsafe).

Maybe, a subquestion, could be is there a solution to force the compiler to consider date_and_time pure (or any other function of that kind)?


Solution

  • The answer about a pure manner to get time is no. A function that returns the current time or date, is impure because at different times it will yield different results—it refers to some global state.

    There are certainly tricks to persuade the compiler that a subroutine is pure. One is to flat out lie in an interface block.

    But there are consequences from lying to the compiler. It can do optimizations which are unsafe to do and the results will be undefined (most often correct anyway, but...).

    module m
    contains
    
      elemental subroutine add(text)
        IMPLICIT NONE
        character(len=*), intent(in)                 :: text
        character(len=1), parameter                  :: nl=char(10)
        character(10) :: time
              intrinsic date_and_time
    
        interface
          pure subroutine my_date_and_time(time)
            character(10), intent(out) :: time
          end subroutine
        end interface
    
        call MY_DATE_AND_TIME(time) 
      end subroutine add
    
    end module
    
    program test
      use m
    
      call add("test")
    end program
    
    subroutine my_date_and_time(time)
      character(10), intent(out) :: time
    
      call date_and_time(time)
    
    end subroutine
    

    Notice I had to delete your message because that was absolutely incompatible with elemental.