!# This source file is distributed with code Pégase.3.0.1 (2019-02-21).
!# Copyright: Michel Fioc (Michel.Fioc@iap.fr), Sorbonne université, 
!# Institut d'astrophysique de Paris/CNRS, France.
!# 
!# Pégase.3.0.1 is governed by the CeCILL license under French law and abides 
!# by the rules of distribution of free software. You can use, modify and/or 
!# redistribute this software under the terms of the CeCILL license as circulated 
!# by CEA, CNRS and INRIA at "http://www.cecill.info". The text of this license
!# is also available in French and in English in directory "doc_dir/" of this
!# code.
!# 
!# As a counterpart to the access to the source code and to the rights to copy,
!# modify and redistribute it granted by the license, users are provided only
!# with a limited warranty, and the software's author, the holder of the
!# economic rights, and the successive licensors have only limited
!# liability. 
!# 
!# The fact that you are presently reading this means that you have had
!# knowledge of the CeCILL license and that you accept its terms.
!#====================================================================== 

module mod_ISO_8601
  
  implicit none
  private
  public ISO_8601
  
contains

!#======================================================================
  
  subroutine ISO_8601(local_time_extended, UTC_time_basic)

    implicit none
    character(len=25), optional :: local_time_extended
    character(len=14), optional :: UTC_time_basic
!#......................................................................
    integer, dimension(8) :: values
    integer, save :: local_year, local_month, local_day, local_hour, &
         local_minute, second, zone, &
         UTC_minute_time, zone_hour, zone_minute, zone_sign, UTC_year, &
         UTC_month, UTC_day, UTC_hour, UTC_minute
    logical :: leap_year
    integer, parameter :: dim_month = 12
    integer, dimension(dim_month), parameter :: common_year_month_length = &
         (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
    integer, dimension(dim_month) :: month_length

    character(len=4) :: string
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call date_and_time(values = values)
    local_year = values(1)
    local_month = values(2)
    local_day = values(3)
    zone = values(4)
    local_hour = values(5)
    local_minute = values(6)
    second = values(7)
!# `values(8)` (in thousand-ths of seconds) not used.

    if (zone >= 0) then
       zone_sign = +1
    else
       zone_sign = -1
    endif
    zone_hour = (zone_sign*zone)/60
    zone_minute = zone_sign*zone - 60*zone_hour
    zone_hour = zone_sign*zone_hour

    if (present(local_time_extended)) then
       write(string, "(i4.4)") local_year
       local_time_extended = trim(string) // "-"
       write(string, "(i2.2)") local_month
       local_time_extended = trim(local_time_extended) // trim(string) // "-"
       write(string, "(i2.2)") local_day
       local_time_extended = trim(local_time_extended) // trim(string) // "T"
       write(string, "(i2.2)") local_hour
       local_time_extended = trim(local_time_extended) // trim(string) // ":"
       write(string, "(i2.2)") local_minute
       local_time_extended = trim(local_time_extended) // trim(string) // ":"
       write(string, "(i2.2)") second
       local_time_extended = trim(local_time_extended) // trim(string)
       write(string, "(SP,i3.2)") zone_hour
       local_time_extended = trim(local_time_extended) // trim(string) // ":"
       write(string, "(i2.2)") zone_minute
       local_time_extended = trim(local_time_extended) // trim(string)
    endif

    leap_year = .false.
    if (mod(local_year, 4) == 0) leap_year = .true.
    if (mod(local_year, 100) == 0) leap_year = .false.
    if (mod(local_year, 400) == 0) leap_year = .true.
    month_length(:) = common_year_month_length(:)
    if (leap_year) month_length(2) = 29

    UTC_year = local_year
    UTC_month = local_month
    UTC_day = local_day
    UTC_hour = local_hour
    UTC_minute = local_minute
    
    UTC_minute_time = UTC_hour*60 + UTC_minute - zone
    if (UTC_minute_time < 0) then
       UTC_minute_time = UTC_minute_time + 24*60
       UTC_day = UTC_day - 1
       if (UTC_day == 0) then
          UTC_month = UTC_month - 1
          if (UTC_month == 0) then
             UTC_year = UTC_year - 1
             UTC_month = 12
          endif
          UTC_day = month_length(UTC_month)
       endif
    else if (UTC_minute_time >= 24*60) then
       UTC_minute_time = UTC_minute_time - 24*60
       UTC_day = UTC_day + 1
       if (UTC_day > month_length(UTC_month)) then
          UTC_month = UTC_month + 1
          if (UTC_month == 13) then 
             UTC_year = UTC_year + 1
             UTC_month = 1
          endif
          UTC_day = 1
       endif
    endif
    UTC_hour = UTC_minute_time/60
    UTC_minute = UTC_minute_time - 60*UTC_hour
    
    if (present(UTC_time_basic)) then
       write(string, "(i4.4)") UTC_year
       UTC_time_basic = string
       write(string, "(i2.2)") UTC_month
       UTC_time_basic = trim(UTC_time_basic) // string
       write(string, "(i2.2)") UTC_day
       UTC_time_basic = trim(UTC_time_basic) // string
       write(string, "(i2.2)") UTC_hour
       UTC_time_basic = trim(UTC_time_basic) // string
       write(string, "(i2.2)") UTC_minute
       UTC_time_basic = trim(UTC_time_basic) // string
       write(string, "(i2.2)") second
       UTC_time_basic = trim(UTC_time_basic) // string
    end if

  end subroutine ISO_8601

end module mod_ISO_8601
