Date time compatibility#

TOML values can represent date times and are also accessible via the build interfaces get_value and set_value. However, the internal representation of a date time value might not be compatible with other libraries dealing with date times. This recipes show how the build interface can be extended to also support common date time libraries.

datetime-fortran#

The datetime-fortran library provides an opaque object representing a date time value and several features for manipulating it. An fpm project using both TOML Fortran and datetime-fortran can be setup using the following dependencies section in the manifest.

[dependencies]
toml-f.git = "https://github.com/toml-f/toml-f.git"
datetime.git = "https://github.com/wavebitscientific/datetime-fortran.git"

To define a compatibility between the two derived types representing a date time value we extend the get_value and set_value generic interfaces.

src/compat.f90#
!> Compatibility module to allow working with [[datetime]] objects and TOML data structures
module demo_compat
  use datetime_module, only : datetime
  use tomlf, only : toml_table, toml_array, toml_keyval, toml_key, toml_stat, toml_datetime, &
    & get_value, set_value, add_keyval, len
  implicit none
  private

  public :: get_value, set_value
  public :: assignment(=)

  !> Getter functions to manipulate TOML values
  interface get_value
    module procedure :: get_value_datetime_fortran
    module procedure :: get_child_value_datetime_fortran
    module procedure :: get_key_value_datetime_fortran
    module procedure :: get_elem_value_datetime_fortran
  end interface get_value

  !> Setter functions to manipulate TOML values
  interface set_value
    module procedure :: set_value_datetime_fortran
    module procedure :: set_child_value_datetime_fortran
    module procedure :: set_key_value_datetime_fortran
    module procedure :: set_elem_value_datetime_fortran
  end interface set_value

  !> Define assignment operation between [[toml_datatime]] and [[datetime]] objects
  interface assignment(=)
    module procedure :: convert_to_datetime
    module procedure :: convert_from_datetime
  end interface assignment(=)

contains

  !> Set TOML value to datetime
  subroutine set_value_datetime_fortran(self, val, stat, origin)
    !> Instance of the key-value pair
    class(toml_keyval), intent(inout) :: self
    !> Datetime value
    type(datetime), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_datetime) :: tmp

    tmp = val
    call set_value(self, tmp, stat, origin)
  end subroutine set_value_datetime_fortran

  !> Set TOML value to datetime
  subroutine set_child_value_datetime_fortran(table, key, val, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    character(*), intent(in) :: key
    !> Datetime value
    type(datetime), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(table, key, ptr, .true., stat, origin)

    if (associated(ptr)) then
      call set_value(ptr, val, stat, origin)
    else
      if (present(stat)) then
        if (stat == toml_stat%success) stat = toml_stat%fatal
      end if
    end if
  end subroutine set_child_value_datetime_fortran

  !> Set TOML value to datetime
  subroutine set_key_value_datetime_fortran(table, key, val, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    type(toml_key), intent(in) :: key
    !> Datetime value
    type(datetime), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    call set_value(table, key%key, val, stat, origin)
  end subroutine set_key_value_datetime_fortran

  !> Retrieve TOML value as datetime value
  subroutine set_elem_value_datetime_fortran(array, pos, val, stat, origin)
    !> Instance of the TOML array
    class(toml_array), intent(inout) :: array
    !> Position in the array
    integer, intent(in) :: pos
    !> Datetime value
    type(datetime), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(array, pos, ptr, stat, origin)

    if (.not.associated(ptr)) then
      if (pos == len(array) + 1) then
        call add_keyval(array, ptr, stat)
      end if
    end if

    if (associated(ptr)) then
      call set_value(ptr, val, stat, origin)
    else
      if (present(stat)) stat = toml_stat%fatal
    end if
  end subroutine set_elem_value_datetime_fortran

  !> Retrieve TOML value as datetime
  subroutine get_value_datetime_fortran(self, val, stat, origin)
    !> Instance of the key-value pair
    class(toml_keyval), intent(in) :: self
    !> Datetime value
    type(datetime), intent(out) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_datetime) :: tmp

    call get_value(self, tmp, stat, origin)
    val = tmp
  end subroutine get_value_datetime_fortran

  !> Retrieve TOML value as datetime
  subroutine get_child_value_datetime_fortran(table, key, val, default, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    character(*), intent(in) :: key
    !> Datetime value
    type(datetime), intent(out) :: val
    !> Default datetime value
    type(datetime), intent(in), optional :: default
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(table, key, ptr, present(default), stat, origin)

    if (associated(ptr)) then
      if (allocated(ptr%val)) then
        call get_value(ptr, val, stat, origin)
      else
        if (present(default)) then
          call set_value(ptr, default)
          call get_value(ptr, val, stat=stat)
        else
          if (present(stat)) stat = toml_stat%fatal
        end if
      end if
    end if
  end subroutine get_child_value_datetime_fortran

  !> Retrieve TOML value as datetime
  subroutine get_key_value_datetime_fortran(table, key, val, default, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    type(toml_key), intent(in) :: key
    !> Datetime value
    type(datetime), intent(out) :: val
    !> Default datetime value
    type(datetime), intent(in), optional :: default
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    call get_value(table, key%key, val, default, stat, origin)
  end subroutine get_key_value_datetime_fortran

  !> Retrieve TOML value as datetime
  subroutine get_elem_value_datetime_fortran(array, pos, val, stat, origin)
    !> Instance of the TOML array
    class(toml_array), intent(inout) :: array
    !> Position in the array
    integer, intent(in) :: pos
    !> Integer value
    type(datetime), intent(out) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(array, pos, ptr, stat, origin)

    if (associated(ptr)) then
      call get_value(ptr, val, stat, origin)
    else
      if (present(stat)) stat = toml_stat%fatal
    end if
  end subroutine get_elem_value_datetime_fortran

  !> Convert to a TOML representation of a datetime object
  elemental subroutine convert_to_datetime(lhs, rhs)
    !> TOML representation of datetime
    type(toml_datetime), intent(out) :: lhs
    !> Datetime-fortran representation of datetime
    type(datetime), intent(in) :: rhs

    lhs%date%year = rhs%getYear()
    lhs%date%month = rhs%getMonth()
    lhs%date%day = rhs%getDay()
    lhs%time%hour = rhs%getHour()
    lhs%time%minute = rhs%getMinute()
    lhs%time%second = rhs%getSecond()
    lhs%time%msec = rhs%getMillisecond() * 1000
  end subroutine convert_to_datetime

  !> Convert from a TOML representation of a datetime object
  elemental subroutine convert_from_datetime(lhs, rhs)
    !> Datetime-fortran representation of datetime
    type(datetime), intent(out) :: lhs
    !> TOML representation of datetime
    type(toml_datetime), intent(in) :: rhs

    integer, allocatable :: year, month, day, hour, minute, second, millisecond

    if (rhs%date%year > -1) year = rhs%date%year
    if (rhs%date%month > -1) month = rhs%date%month
    if (rhs%date%day > -1) day = rhs%date%day
    if (rhs%time%hour > -1) hour = rhs%time%hour
    if (rhs%time%minute > -1) minute = rhs%time%minute
    if (rhs%time%second > -1) second = rhs%time%second
    if (rhs%time%msec > -1) millisecond = rhs%time%msec / 1000

    lhs = datetime(year=year, month=month, day=day, hour=hour, minute=minute, &
      & second=second, millisecond=millisecond)
  end subroutine convert_from_datetime

end module demo_compat

M_time#

The M_time library provides a transparent object representing a date time value, with a rich functional and object oriented API for inspecting and manipulating it. An fpm project using both TOML Fortran and M_time can be setup using the following dependencies section in the manifest.

[dependencies]
toml-f.git = "https://github.com/toml-f/toml-f.git"
M_time.git = "https://github.com/urbanjost/M_time.git"

To define a compatibility between the two derived types representing a date time value we extend the get_value and set_value generic interfaces.

src/compat.f90#
!> Compatibility module to allow working with [[date_time]] objects and TOML data structures
module demo_compat
  use m_time_oop, only : date_time
  use tomlf, only : toml_table, toml_array, toml_keyval, toml_key, toml_stat, toml_datetime, &
    & get_value, set_value, add_keyval, len
  implicit none
  private

  public :: get_value, set_value
  public :: assignment(=)

  !> Getter functions to manipulate TOML values
  interface get_value
    module procedure :: get_value_datetime_m_time
    module procedure :: get_child_value_datetime_m_time
    module procedure :: get_key_value_datetime_m_time
    module procedure :: get_elem_value_datetime_m_time
  end interface get_value

  !> Setter functions to manipulate TOML values
  interface set_value
    module procedure :: set_value_datetime_m_time
    module procedure :: set_child_value_datetime_m_time
    module procedure :: set_key_value_datetime_m_time
    module procedure :: set_elem_value_datetime_m_time
  end interface set_value

  !> Define assignment operation between [[toml_datatime]] and M_time [[date_time]] objects
  interface assignment(=)
    module procedure :: convert_to_datetime
    module procedure :: convert_from_datetime
  end interface assignment(=)

contains

  !> Set TOML value to datetime
  subroutine set_value_datetime_m_time(self, val, stat, origin)
    !> Instance of the key-value pair
    class(toml_keyval), intent(inout) :: self
    !> Datetime value
    type(date_time), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_datetime) :: tmp

    tmp = val
    call set_value(self, tmp, stat, origin)
  end subroutine set_value_datetime_m_time

  !> Set TOML value to datetime
  subroutine set_child_value_datetime_m_time(table, key, val, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    character(*), intent(in) :: key
    !> Datetime value
    type(date_time), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(table, key, ptr, .true., stat, origin)

    if (associated(ptr)) then
      call set_value(ptr, val, stat, origin)
    else
      if (present(stat)) then
        if (stat == toml_stat%success) stat = toml_stat%fatal
      end if
    end if
  end subroutine set_child_value_datetime_m_time

  !> Set TOML value to datetime
  subroutine set_key_value_datetime_m_time(table, key, val, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    type(toml_key), intent(in) :: key
    !> Datetime value
    type(date_time), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    call set_value(table, key%key, val, stat, origin)
  end subroutine set_key_value_datetime_m_time

  !> Retrieve TOML value as datetime value
  subroutine set_elem_value_datetime_m_time(array, pos, val, stat, origin)
    !> Instance of the TOML array
    class(toml_array), intent(inout) :: array
    !> Position in the array
    integer, intent(in) :: pos
    !> Datetime value
    type(date_time), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(array, pos, ptr, stat, origin)

    if (.not.associated(ptr)) then
      if (pos == len(array) + 1) then
        call add_keyval(array, ptr, stat)
      end if
    end if

    if (associated(ptr)) then
      call set_value(ptr, val, stat, origin)
    else
      if (present(stat)) stat = toml_stat%fatal
    end if
  end subroutine set_elem_value_datetime_m_time

  !> Retrieve TOML value as datetime
  subroutine get_value_datetime_m_time(self, val, stat, origin)
    !> Instance of the key-value pair
    class(toml_keyval), intent(in) :: self
    !> Datetime value
    type(date_time), intent(out) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_datetime) :: tmp

    call get_value(self, tmp, stat, origin)
    val = tmp
  end subroutine get_value_datetime_m_time

  !> Retrieve TOML value as datetime
  subroutine get_child_value_datetime_m_time(table, key, val, default, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    character(*), intent(in) :: key
    !> Datetime value
    type(date_time), intent(out) :: val
    !> Default datetime value
    type(date_time), intent(in), optional :: default
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(table, key, ptr, present(default), stat, origin)

    if (associated(ptr)) then
      if (allocated(ptr%val)) then
        call get_value(ptr, val, stat, origin)
      else
        if (present(default)) then
          call set_value(ptr, default)
          call get_value(ptr, val, stat=stat)
        else
          if (present(stat)) stat = toml_stat%fatal
        end if
      end if
    end if
  end subroutine get_child_value_datetime_m_time

  !> Retrieve TOML value as datetime
  subroutine get_key_value_datetime_m_time(table, key, val, default, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    type(toml_key), intent(in) :: key
    !> Datetime value
    type(date_time), intent(out) :: val
    !> Default datetime value
    type(date_time), intent(in), optional :: default
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    call get_value(table, key%key, val, default, stat, origin)
  end subroutine get_key_value_datetime_m_time

  !> Retrieve TOML value as datetime
  subroutine get_elem_value_datetime_m_time(array, pos, val, stat, origin)
    !> Instance of the TOML array
    class(toml_array), intent(inout) :: array
    !> Position in the array
    integer, intent(in) :: pos
    !> Integer value
    type(date_time), intent(out) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(array, pos, ptr, stat, origin)

    if (associated(ptr)) then
      call get_value(ptr, val, stat, origin)
    else
      if (present(stat)) stat = toml_stat%fatal
    end if
  end subroutine get_elem_value_datetime_m_time

  !> Convert to a TOML representation of a datetime object
  elemental subroutine convert_to_datetime(lhs, rhs)
    !> TOML representation of datetime
    type(toml_datetime), intent(out) :: lhs
    !> M_time representation of datetime
    type(date_time), intent(in) :: rhs

    lhs%date%year = rhs%year
    lhs%date%month = rhs%month
    lhs%date%day = rhs%day
    lhs%time%hour = rhs%hour
    lhs%time%minute = rhs%minute
    lhs%time%second = rhs%second
    lhs%time%msec = rhs%millisecond * 1000
  end subroutine convert_to_datetime

  !> Convert from a TOML representation of a datetime object
  elemental subroutine convert_from_datetime(lhs, rhs)
    !> M_time representation of datetime
    type(date_time), intent(out) :: lhs
    !> TOML representation of datetime
    type(toml_datetime), intent(in) :: rhs

    if (rhs%date%year > -1) lhs%year = rhs%date%year
    if (rhs%date%month > -1) lhs%month = rhs%date%month
    if (rhs%date%day > -1) lhs%day = rhs%date%day
    if (rhs%time%hour > -1) lhs%hour = rhs%time%hour
    if (rhs%time%minute > -1) lhs%minute = rhs%time%minute
    if (rhs%time%second > -1) lhs%second = rhs%time%second
    if (rhs%time%msec > -1) lhs%millisecond = rhs%time%msec / 1000
  end subroutine convert_from_datetime

end module demo_compat