stdlib icon indicating copy to clipboard operation
stdlib copied to clipboard

[Proposal] add `time_stamp` function and `stdlib_time` module: get formatted now time information?

Open zoziha opened this issue 3 years ago • 10 comments

Description For example, the Go language standard library has a time library golang/time, and stdlib also has a time module requirement. Is it possible to provide basic time module capabilities for stdlib. Start stdlib_time module by implementing a time_stamp function ?

Prior Art

Fortran Time Packages

Related Issues https://github.com/fortran-lang/stdlib/issues/1 and https://github.com/fortran-lang/stdlib/issues/106

zoziha avatar Jul 15 '21 01:07 zoziha

The codes of John Burkardt all contain a timestamp subroutine (GPL-licensed) with fixed format:

subroutine timestamp()
subroutine timestamp ( )

!*****************************************************************************80
!
!! TIMESTAMP prints the current YMDHMS date as a time stamp.
!
!  Example:
!
!    31 May 2001   9:45:54.872 AM
!
!  Licensing:
!
!    This code is distributed under the GNU LGPL license.
!
!  Modified:
!
!    18 May 2013
!
!  Author:
!
!    John Burkardt
!
!  Parameters:
!
!    None
!
  implicit none

  character ( len = 8 ) ampm
  integer ( kind = 4 ) d
  integer ( kind = 4 ) h
  integer ( kind = 4 ) m
  integer ( kind = 4 ) mm
  character ( len = 9 ), parameter, dimension(12) :: month = (/ &
    'January  ', 'February ', 'March    ', 'April    ', &
    'May      ', 'June     ', 'July     ', 'August   ', &
    'September', 'October  ', 'November ', 'December ' /)
  integer ( kind = 4 ) n
  integer ( kind = 4 ) s
  integer ( kind = 4 ) values(8)
  integer ( kind = 4 ) y

  call date_and_time ( values = values )

  y = values(1)
  m = values(2)
  d = values(3)
  h = values(5)
  n = values(6)
  s = values(7)
  mm = values(8)

  if ( h < 12 ) then
    ampm = 'AM'
  else if ( h == 12 ) then
    if ( n == 0 .and. s == 0 ) then
      ampm = 'Noon'
    else
      ampm = 'PM'
    end if
  else
    h = h - 12
    if ( h < 12 ) then
      ampm = 'PM'
    else if ( h == 12 ) then
      if ( n == 0 .and. s == 0 ) then
        ampm = 'Midnight'
      else
        ampm = 'AM'
      end if
    end if
  end if

  write ( *, '(i2,1x,a,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' ) &
    d, trim ( month(m) ), y, h, ':', n, ':', s, '.', mm, trim ( ampm )

  return
end

On the other hand the M_time module has a formatted time function:

function fmtdate(values,format) RESULT (timestr)
    program demo_fmtdate
    use M_time, only : fmtdate
    implicit none
    integer :: dat(8)
       call date_and_time(values=dat)
       write(*,*)fmtdate(dat,"current date: %w, %l %d, %Y %H:%m:%s %N")
       call showme()
    contains
    subroutine showme()
       use M_time, only : fmtdate_usage
       call fmtdate_usage() ! see all formatting options
    end subroutine showme
    end program demo_fmtdate

Here are some options from other languages:

Some open issues to discuss are:

  • fixed vs flexible format
  • input argument type (datetime object, integer :: dat(8) returned by intrinsic date_and_time, other )
  • interface (function vs subroutine)

ivan-pi avatar Jul 15 '21 11:07 ivan-pi

Perhaps this is a bad idea, but I wonder if there is any advantage to write into the format string directly?

integer :: dat(8)
call date_and_time(values=dat)
write(*,fmtdate(dat))
! vs
write(*,'(A)') datestr(dat)

ivan-pi avatar Jul 15 '21 12:07 ivan-pi

Somewhat related is #106.

Rather than implementing a specific (fixed-format) time stamp, I recommend simply providing a binding to C strftime, which is a much more versatile solution with less code.

The Forlab implementation looks like it was adapted from John Burkardt's. timestamp(). Should probably note that in the Forlab LICENSE file.

milancurcic avatar Jul 15 '21 14:07 milancurcic

The Forlab implementation looks like it was adapted from John Burkardt's. timestamp(). Should probably note that in the Forlab LICENSE file.

Thanks for reminding. I have only come into contact with open source code not long ago, and have not been very familiar with open source licenses. If it is a relatively short function, do I need to follow its license because I changed it? Can a project simply combine multiple open source licenses?

zoziha avatar Jul 15 '21 14:07 zoziha

do I need to follow its license because I changed it?

Absolutely. Adopting the same interface is okay, I believe, but you have to respect the license when it comes to the implementation. That's why looking too closely at GPL code for the standard library isn't such a good idea IMO. The standard library is aiming for MIT or BSD licensing isn't it?

nncarlson avatar Jul 15 '21 14:07 nncarlson

I'm very sorry about that, I didn't realize this before. John Burkardt/timestamp was a subroutine, but now forlab/times_stamp becomes a module function. Isn’t it OK? I made this git push today, can I remove this license issue by just deleting this LGPL code git push? (I am scared😢, I just deleted it just now.)

zoziha avatar Jul 15 '21 14:07 zoziha

How about simply creating a fixed format time_stamp function to start stdlib_time. It's simple, but it's also useful. This reminds people that there is still some work in stdlib_time, remember to improve stdlib_time. 😂

zoziha avatar Jul 15 '21 16:07 zoziha

How about simply creating a fixed format time_stamp function to start stdlib_time. It's simple, but it's also useful.

NAG has a simple function called nagf_time_date_array_string that takes as input an integer :: itime(7) (kind of similar to the return value of subroutine date_and_time and returns a formatted string.

If we can reach an agreement on the name and format I'm fine to have this. But in general the solution of @milancurcic will be more helpful. A downside of c_strftime is one needs to size the buffer correctly. If we could have function which returns a character(len=:), allocatable and accepts a custom format it would be more convenient. Then everyone can have the format they likes best and write a simple wrapper function

function nowstr()
character(len=:), allocatable :: nowstr
integer :: vals(8)
call date_and_time(values=vals)
! %c returns a date and time representation like:
! Sun Aug 19 02:56:02 2012
nowstr = fstrftime('%c',vals) 
end function

ivan-pi avatar Jul 23 '21 11:07 ivan-pi

I would have use for stdlib provided derived type to express a time stamp since it would allow to bridge TOML Fortran and stdlib. This would allow to directly retrieve TOML documents as stdlib hash map including date time values from the TOML document as stdlib compatible derived type.

awvwgk avatar Jul 30 '22 21:07 awvwgk

A (simple) time stamp is already implemented in stdlib_logger. Could it be an idea to move it to e.g., stdlib_time and discuss its API and implementation based on the different needs?

jvdp1 avatar Aug 01 '22 09:08 jvdp1