! Copyright 2020 Florida State University, Center for Ocean-Atmospheric Prediction Studies ! Permission is hereby granted, free of charge, to any person obtaining a copy ! of this software and associated documentation files (the "Software"), to deal ! in the Software without restriction, including without limitation the rights ! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! copies of the Software, and to permit persons to whom the Software is ! furnished to do so, subject to the following conditions: ! The above copyright notice and this permission notice shall be included in ! all copies or substantial portions of the Software. ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ! SOFTWARE. module coapstime private public :: invtime, convtime contains logical function is_leap_year(year) implicit none integer :: year if (mod(year, 400).eq.0) then is_leap_year = .TRUE. return else if (mod(year, 100).eq.0) then is_leap_year = .FALSE. return else if (mod(year, 4).eq.0) then is_leap_year = .TRUE. return else is_leap_year = .FALSE. endif return end function is_leap_year integer function minutes_in_month(month, year) implicit none integer :: month, year integer, dimension(12) :: minutes_per_month minutes_per_month = (/44640,40320,44640,43200,44640,43200, 44640,44640,43200,44640,43200,44640 /) if (is_leap_year(year)) then ! add another day to February if it's a leap year minutes_per_month(2) = minutes_per_month(2) + 1440 endif minutes_in_month = minutes_per_month(month) return end function minutes_in_month integer function minutes_in_year(year) implicit none integer :: year ! 525600 is the number of minutes in a common year minutes_in_year = 525600 if (is_leap_year(year)) then ! add another days worth of minutes if this is a leap year minutes_in_year = minutes_in_year + 1440 endif return end function minutes_in_year integer function days_in_month(year, month) implicit none integer :: year, month integer, dimension(12) :: days_per_month days_per_month = (/31,28,31,30,31,30,31,31,30,31,30,31 /) if (is_leap_year(year)) then days_per_month(2) = days_per_month(2) + 1 endif days_in_month = days_per_month(month) end function days_in_month subroutine invtime(timestamp,year,month,day,hour,minute) ! This subroutine will convert a minutes timestamp to a year/month ! date. Based on the function convtime by Shawn Smith (COAPS). ! ! Written the spring of 1995, several iterations. ! James N. Stricherz (stricherz@coaps.fsu.edu) ! ! Updated for Y2K July 1999. ! Shyam Lakshmin (lakshmin@coaps.fsu.edu) ! ! Updated to handle datetimes past 2019-12-31 23:59 in November 2019 ! Homer McMillan (hmcmillan@coaps.fsu.edu) integer, intent(in) :: timestamp integer year, month, day, hour, minute, temp, temp_time temp_time = timestamp year = 1980 month = 1 day = 1 hour = 0 minute = 0 if (timestamp.lt.0) then print *, "ERROR: invtime: timestamp must be greater than 0, found ", timestamp year = -9999 month = 0 day = 0 hour = 0 minute = 0 return endif 10 temp = minutes_in_year(year) if (temp_time.ge.temp) then temp_time = temp_time - temp year = year + 1 goto 10 endif if (temp_time.eq.0) then return endif 20 temp = minutes_in_month(month, year) if (temp_time.ge.temp) then temp_time = temp_time - temp month = month + 1 goto 20 endif if (temp_time.eq.0) then return endif 30 if (temp_time.ge.1440) then temp_time = temp_time - 1440 day = day + 1 goto 30 endif if (temp_time.eq.0) then return endif 40 if (temp_time.ge.60) then temp_time = temp_time - 60 hour = hour + 1 goto 40 endif ! The leftover temp_time is the minutes minute = temp_time return end subroutine invtime integer function convtime(year,month,day,hour,minute) ! Originally written by Shawn Smith (smith@coaps.fsu.edu) ! Updated Spring 1999 for Y2K compliance by Anthony Arguez ! (anthony@coaps.fsu.edu). ! ! Updated to handle datetimes past 2019-12-31 23:59 in November 2019 ! Homer McMillan (hmcmillan@coaps.fsu.edu) ! ! ! This function will convert a given year, month, day, hour, and ! minutes to a minutes from 1-1-1980 00:00 time stamp. integer, intent(in) :: year, month, day, hour, minute integer local_year, local_month, local_day, local_hour, result, temp logical error error = .false. result = 0 ! validate the input date if (year .lt. 1980) then print *, "ERROR: convtime: year out of range (must be greater than 1979) ", year error = .true. endif if (month.lt.1 .or. 12.lt.month) then print *, "ERROR: convtime: month out of range ", month error = .true. endif if (day.lt.1 .or. days_in_month(year, month).lt.day) then print *, "ERROR: convtime: day out of range ", day error = .true. endif if (hour.lt.0 .or. 23.lt.hour) then print *, "ERROR: convtime: hour out of range ", hour error = .true. endif if (minute.lt.0 .or. 59.lt.minute) then print *, "ERROR: convtime: minute out of range ", minute error = .true. endif if (error) then convtime = -9999 return endif local_year = year - 1 10 if (local_year.gt.1979) then temp = minutes_in_year(local_year) result = result + temp local_year = local_year - 1 goto 10 endif local_month = month - 1 20 if (local_month.gt.0) then temp = minutes_in_month(local_month, year) result = result + temp local_month = local_month - 1 goto 20 endif local_day = day - 1 30 if (local_day.gt.0) then result = result + 1440 local_day = local_day - 1 goto 30 endif local_hour = hour 40 if (local_hour.gt.0) then result = result + 60 local_hour = local_hour - 1 goto 40 endif result = result + minute convtime = result return end function convtime end module coapstime