Date and Time

Modern Fortran features some basic time routines. On POSIX-compliant systems, the ISO C binding interface allows us to access additional timing routines.

Current Date and Time

The routine date_and_time(date, time, zone, values) returns date and time information from the real-time system clock.

call date_and_time([date][, time][, zone][, values])
Argument Type Description
date character(len=8) Date in form ccyymmdd.
time character(len=10) Time in form hhmmss.sss.
zone character(len=5) Zone in form (+-)hhmm, representing the difference with respect to UTC.
values integer(8) Array with year (1), month (2), day of month (3), time difference with UTC in minutes (4), hour (5), minutes (6), seconds (7), and milliseconds (8).

The following example prints the current date and time in UTC and in Swatch Internet Time (.beats):

! datetime.f90
program main
    implicit none
    integer :: dt(8)
    real    :: beats

    call date_and_time(values=dt)
    print '(i4, 5(a, i2.2))', dt(1), '/', dt(2), '/', dt(3), ' ', &
                              dt(5), ':', dt(6), ':', dt(7)
    beats = (dt(7) + ((dt(6) - dt(4) + 60) * 60) + (dt(5) * 3600)) / 86.4
    print '("Beats: @", f0.2)', beats
end program main

Running the executable outputs:

$ ./datetime
2019/08/12 21:50:23
Beats: @868.32

Sleep

The Fortran standard does not include any routine for pausing a program for a given time. Some compilers, like GNU Fortran, provide a routine through extensions:

! time.f90
program main
    implicit none
    integer :: i

    do i = 1, 10
        print '(a)', 'zzz ...'
        call sleep(2)
    end do
end program main

Other compilers may support the sleep() routine, even if it is not a Fortran standard. As an alternative, a compiler-independent interface to the POSIX routine sleep(3) can be written, making the call compatible to all POSIX-compliant operating systems.

POSIX

In order to sleep for less than a second, one might consider an interface to usleep(3), which pauses for a given interval measured in microseconds:

! posix_sleep.f90
module posix
    use, intrinsic :: iso_c_binding, only: c_int32_t
    implicit none

    interface
        subroutine c_usleep(useconds) bind(c, name='usleep')
            import :: c_int32_t
            integer(kind=c_int32_t), value :: useconds
        end subroutine c_usleep
    end interface
contains
    subroutine microsleep(useconds)
        !! Wrapper for `c_usleep()` that converts `integer` to `c_int32_t`.
        integer :: useconds
        call c_usleep(int(useconds, kind=c_int32_t))
    end subroutine microsleep
end module posix

program main
    use :: posix
    implicit none
    integer :: i
    integer :: t = 500 * 1000 ! 500 milliseconds

    do i = 1, 10
        print '(a)', 'zzz ...'
        call microsleep(t)
    end do
end program main

The wrapper routine microsleep() does the type convertion from integer to c_int32_t. Note that the usleep(3) function has been declared obsolete. It is recommended to use nanosleep(2) instead.

CPU Time

The intrinsic Fortran routine cpu_time() returns the ellapsed CPU time in microseconds. The example measures the time required to compute the Mandelbrot set (fig. 1):

! mandelbrot.f90
program main
    implicit none
    integer, parameter :: WIDTH     = 80
    integer, parameter :: HEIGHT    = 40
    integer, parameter :: MAX_ITER  = 90
    real,    parameter :: THRESHOLD = 2.0
    integer            :: x, y
    real               :: re, im
    real               :: t1, t2

    call cpu_time(t1)

    do y = 0, HEIGHT
        im = -1.5 + real(y) * 3.0 / real(HEIGHT)

        do x = 0, WIDTH
            re = -2.0 + real(x) * 3.0 / real(WIDTH)

            if (mandelbrot(cmplx(re, im), MAX_ITER, THRESHOLD) < 10) then
                write (*, '(a)', advance='no') ' '
            else
                write (*, '(a)', advance='no') '*'
            end if
        end do

        write (*, '(a)')
    end do

    call cpu_time(t2)
    print '("Time: ", f8.6, " seconds")', t2 - t1
contains
    function mandelbrot(c, max_iter, threshold)
        !! Calculates Mandelbrot set.
        complex, intent(in) :: c
        integer, intent(in) :: max_iter
        real,    intent(in) :: threshold
        integer             :: mandelbrot
        complex             :: z

        z = (0.0, 0.0)

        do mandelbrot = 0, max_iter
            z = z**2 + c

            if (abs(z) > threshold) &
                exit
        end do
    end function mandelbrot
end program main

Compile and run the example with:

$ gfortran9 -o mandelbrot mandelbrot.f90
$ ./mandelbrot
Mandelbrot set in Fortran
Fig. 1: The example Mandelbrot program