A nice straight-forward wallclock timer. Odd something like that was
never added to the cmd() environment.
Alternatively to measure the elapsed time for a command on Windows,
I am told you can use PowerShell’s Measure-Command.
I am not a PowerShell power user so I find the PowerShell syntax very
awkward and prefer the more familiar (at least to me) CLI interface your
program provides.
In the past I remember using DOS scripts that used the %TIME% variable
to provide a wallclock timer. I bet some of those are still out there
or AI could generate a “.bat” file that would do wallclock timing.
Related information for GNU/Linux
On GNU/Linux systems, which I am far more familiar with,
if I want a Fortran program (or bash shell, or …)
to report metrics without requiring using something like
/bin/time -v $CMD
I find having the program open files like /proc/$PPID/status and parse
out fields or even just do something like
program testit
! show a bunch of process information about the current program
call execute_command_line("cat /proc/$PPID/status")
! use the same file but just extract memory usage
call execute_command_line("egrep '^Name:|^VMsize:|^VmRSS:' /proc/$PPID/status")
! ps(1) lets you select many metrics such as user, system, and wallclock time
call execute_command_line("ps -p $PPID -o cutime,cstime,time")
end program testit
is easier than making all the required C calls as I usually want User CPU,
System CPU, context switching information, wallclock, memory HWM … at
a minimum, and it is all out there in files on Unix variants. Since the
/proc files are accessible from any language it is easy to create a bash
shell to show the information and just call that from EXECUTE_COMMAND_LINE().
If you use cgroups (quite commonly used on HPC clusters in particular)
there are several files showing the most important metrics for your
overall session available. A lot of batch scheduling environments can
generate metric reports as well.
ps(1) has a lot of options on most systems that accesses a lot of the
information in the /proc/$$/* files. Calling the ps(1) command
you can get virtually all the information that the time(1) command provides
(note that /bin/time -v $CMD usually provides far more information than
“time $CMD” displays, which usually runs a shell built-in instead of
the actual time(1) command).
/bin/time -v date
Sun Mar 22 23:00:52 EDT 2026
Command being timed: "date"
User time (seconds): 0.03
System time (seconds): 0.00
Percent of CPU this job got: 33%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.09
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 10396
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 2737
Minor (reclaiming a frame) page faults: 0
Voluntary context switches: 0
Involuntary context switches: 0
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 65536
Exit status: 0
Some systems restrict ps(1) functionality partly because it does show
so much system information, and some environments like CygWin only
provide a subset of what the ps(1) command typically does on BSD and
GNU/Linux systems.
The timeit.f90 example program is a demonstration program for the
M_stopwatch module that on Posix
systems also gives User and System time but currently would just give
wallclock in most Microsoft environments, I think.
It does something similiar to your timer in just a few lines but to do
so uses several fpm(1) packages.
Fortran-based wallclock timer
Taking a lead from the timeit(1) program and your timer I put together
a stand-alone Fortran variant of the wallclock timer.
When I went to emulate your program in Fortran I admit it got longer than
I was initially thinking because of issues with requoting parameters. on
Unix/BSD/GNU-Linux it is relatively easy to requote the arguments but I am
not much of a Microsoft user so I am not sure if the same quoting rules
apply there or not. That aside I approximated your program in Fortran
using DATE_AND_TIME() and EXECUTE_COMMAND_LINE() extracting parts of a
few routines from M_time and
reducing the components from their general form to something just specific
to the task at hand.
Adding other Fortran intrinsics like CPU_TIME() would add some nice
additional functionality while still remaining relatively portable.
wallclock sleep 4
wallclock=4.146 sec or 0-00:00:04.146
wallclock.f90
program demo_wallclock
use,intrinsic :: iso_fortran_env, only : stderr=>ERROR_UNIT
implicit none
integer,parameter :: dp=kind(0.0d0)
integer :: i,j,length,cmdstat,exitstat
character(len=*),parameter :: doublequote='"',g0='(*(g0))',g1='(*(g0,1x))'
character(len=256) :: cmdmsg
character(len=:),allocatable :: arg,arg_requote,cmd
real(kind=dp) :: start,finish,wallclock
cmd=''
do i=1,command_argument_count()
call get_command_argument(i,length=length)
arg=repeat(' ',length)
call get_command_argument(i,arg)
arg_requote=''
! assume you double a quote on non-GNU/Linux and Unix to escape it
! probably needs changed in some PC environments
do j=1,length
arg_requote=arg_requote//arg(j:j)
if(arg(j:j).eq.doublequote) arg_requote=arg_requote//doublequote
enddo
arg=arg_requote
if(i.ne.1)arg=doublequote//arg//doublequote
cmd=cmd//arg//' '
enddo
if(cmd.eq.'')stop
start=now_as_julian()
call execute_command_line(cmd,cmdstat=cmdstat,cmdmsg=cmdmsg,exitstat=exitstat)
finish=now_as_julian()
wallclock=(finish-start)*86400
write(*,'("wallclock=",f0.3," sec or ",a,:," for ",a)')wallclock,sec2days(wallclock)!,cmd
if(cmdstat.ne.0)then
write(stderr,g0)trim(cmdmsg)
stop 1
endif
if(exitstat.ne.0)then
stop exitstat
endif
contains
function now_as_julian() result(julian)
integer :: dat(8), A, Y, M, JDN
real(kind=dp) :: julian
call date_and_time(values=dat)
associate(yr=>dat(1),mo=>dat(2),day=>dat(3),&
& hr=>dat(5),min=>dat(6),sec=>dat(7)-(dat(4)*60)+dat(8)/1000.0_dp)
A=(14-mo)/12
Y=yr+4800-A
M=mo+12*A-3
JDN=day + (153*M+2)/5 + 365*Y + Y/4 - Y/100 + Y/400 - 32045
julian=JDN + (hr-12)/24.0_dp + min/1440.0_dp + sec/86400.0_dp
end associate
end function now_as_julian
function sec2days(seconds) result(dhms)
use, intrinsic :: iso_fortran_env, only : int64
real(kind=dp),intent(in) :: seconds
real(kind=dp) :: remainder
character(len=40) :: scratch
character(len=:),allocatable :: dhms
integer,parameter :: one_day=86400, one_hour=3600, one_minute=60
integer(kind=int64) :: days, hours, minutes, secs
integer :: i
remainder=abs(seconds)
days=remainder/one_day
remainder=remainder-days*one_day
hours=remainder/one_hour
remainder=remainder-hours*one_hour
minutes=remainder/one_minute
remainder=remainder-minutes*one_minute
secs=nint(remainder)
remainder=remainder-secs
write(scratch,'(i0,"-",i2.2,":",i2.2,":",i2.2,".",i3.3)') &
&sign(days,merge(-1_int64,1_int64,seconds<0)),hours,minutes,secs,nint(remainder*1000)
dhms=trim(scratch)
end function sec2days
end program demo_wallclock
FUNIX has a time-.f90 program
There are a number of Fortran sample programs that use the GPF(General Purpose Fortran) package that emulate or approximate GNU Linux commands in the funix section of apps. That includes time-.f90 which is a minature version of time(1).