Fortran日期时间处理模块

      Fortran自身并不带有日期时间处理函数,故仿照vb.net编写 Mod_DateTime 模块(点击下载,文后同样附有代码),其中包含两个结构体TimeSpan 和 DateTime。模块内部采用32位整型数据和64位浮点数据,主要功能:1、计算两个时间间隔(TimeSpan类型)之间的时间间隔;2、计算两个时刻(DateTime类型)之间的时间间隔;3、计算与某时刻相距一定时间间隔的时刻。

一、TimeSpan类型

1.1 结构体声明

  type, public:: TimeSpan
    !定义TimeSpan结构体
    integer(IP) :: Sign = 1 !用1、-1分别表示正负
    integer(IP) :: Days = 0, Hours = 0, Minutes = 0, Seconds = 0, &
      Milliseconds = 0, Microseconds = 0, Nanoseconds = 0
  contains
  procedure, pass :: TotalDays, TotalHours, TotalMinutes, TotalSeconds, &
    TotalMilliseconds, TotalMicroseconds, TotalNanoseconds
  procedure, pass :: CompareTo
  procedure, pass :: ToString
  procedure, pass :: Set
  procedure, pass :: Add
  procedure, pass :: Subtract
  end type TimeSpan

1.2 成员 

Sign

当前TimeSpan结构所表示的时间间隔的正(1)负(-1)

Days

当前TimeSpan结构所表示的时间间隔的天数部分

Hours

当前TimeSpan结构所表示的时间间隔的小时数部分

Minutes

当前TimeSpan结构所表示的时间间隔的分钟数部分

Seconds

当前TimeSpan结构所表示的时间间隔的秒数部分

Milliseconds

当前TimeSpan结构所表示的时间间隔的毫秒数部分

Microseconds

当前TimeSpan结构所表示的时间间隔的微秒数部分

Nanoseconds

当前TimeSpan结构所表示的时间间隔的纳秒数部分

1.3 方法

返回值

函数名(参数)

功能

double

TotalDays

返回以天为单位表示的当前TimeSpan结构的值

double

TotalHours

返回以小时为单位表示的当前TimeSpan结构的值

double

TotalMinutes

返回以分钟为单位表示的当前TimeSpan结构的值

double

TotalSeconds

返回以秒为单位表示的当前TimeSpan结构的值

double

TotalMilliseconds

返回以毫秒为单位表示的当前TimeSpan结构的值

double

TotalMicroseconds

返回以微秒为单位表示的当前​​​​​​​TimeSpan结构的值

double

TotalNanoseconds

返回以纳秒为单位表示的当前​​​​​​​TimeSpan结构的值

Int32

CompareTo(TimeSpan)

将此实例与指定​​TimeSpan对象进行比较,并返回一个整数,该整数指示此实例是小于(-1)、等于(0)还是大于(1)指定对象

string

ToString

将当前​​​​​​​TimeSpan对象的值转换为字符串表示形式

void

Set(Sign, Days, Hours Minutes, Seconds, Milliseconds, Microseconds, Nanoseconds, status )

Set(Sign, Days, Hours Minutes, Seconds, Milliseconds, Microseconds, Nanoseconds)

Set(seconds)

1. 设置​​​​​​​TimeSpan结构的变量,参数含义见成员列表。具有status参数,时间参数必须符合时间格式(最大23:59:59.999999999)。status值为0表示数据无误,-1表示出现赋值,1表示超过范围

2. 设置​​​​​​​TimeSpan结构的变量,参数含义见成员列表。无status参数,时间参数无需符合时间格式(25:62:59.999999999也可)

3. 将双精度的秒数转为​​​​​​​TimeSpan结构的变量

void

Add(​​​​​​​TimeSpan)

将此实例与指定TimeSpan对象相加

void

Subtract(​​​​​​​TimeSpan)

将此实例与指定​​​​​​​TimeSpan对象相减

二、DateTime类型

2.1 结构体声明

  type DateTime
    integer(IP) :: Year = 1800, Month = 1, Day = 1
    integer(IP) :: Hour = 0, Minute = 0, Second = 0, Millisecond = 0
  contains
  procedure, pass :: DayOfYear
  procedure, pass :: DayOfWeek
  procedure, pass :: CompareTo
  procedure, pass :: ToString
  procedure, pass :: IsLeapYear
  procedure, pass :: Now
  procedure, pass :: Set
  procedure, pass :: Add
  procedure, pass :: SubtractTimeSpan
  procedure, pass :: SubtractDateTime
  end type DateTime

2.2 成员

Year

当前DateTime结构所表示日期的年份部分

Month

当前DateTime结构所表示日期的月份部分

Day

当前DateTime结构所表示日期为该月中的第几天

Hour

当前DateTime结构所表示日期的小时部分

Minute

当前DateTime结构所表示日期的分钟部分

Second

当前DateTime结构所表示日期的秒部分

Millisecond

当前DateTime结构所表示日期的毫秒部分

2.3 方法

返回值

函数名(参数)

功能

Int32

DayOfYear

获取此实例所表示的日期是该年中的第几天

Int32

DayOfWeek

获取此实例所表示的日期是星期几(1-7)

Int32

CompareTo(DateTime)

将此实例的值与指定的​​​​​​​DateTime值相比较,并返回一个整数,该整数指示此实例是早于(-1)、等于(0)还是晚于(1)指定的DateTime值

string

ToString

当前​​​​​​​DateTime对象的值转换为字符串表示形式

logical

IsLeapYear

当前​​​​​​​DateTime对象是否为闰年

void

Now

获取一个DateTime对象,该对象设置为此计算机上的当前日期和时间,表示为本地时间

void

Set(yy, mm, dd, h, m, s, ms, status)

设置日期时间, status参数可选

void

Add(TimeSpan)

将指定TimeSpan​​​​​​​的值添加到此实例的值上

void

SubtractTimeSpan(TimeSpan)

从此实例的值中减去指定持续时间间隔

TimeSpan

SubtractDateTime(DateTime)

从此实例的值中减去指定时刻,返回时间间隔

三、使用

      将代码Module_DateTime.f90加入项目即可。该源文件中包含两个模块Mod_TimeSpan和Mod_DateTime,前者为后者的子集,使用时可只use后者。

 四、示例

  program Test
  use Mod_DateTime
  implicit none
  type(TimeSpan) ts1, ts2
  type(DateTime) DT1, DT2
  integer i
  call ts1%Set(-86521.123456789D0)      !以秒设置时间间隔 -1::00:02:01.123456789
  write(*,"('ts1            = ',a)") ts1%ToString() !输出字符形式的时间间隔
  call ts1%Set(1,0,0,61,0,0,0,0,i)      !设置时间间隔, 有status参数, 检查数据格式. 分钟大于59, 不符合时间格式
  write(*,"('status         = ',g0)") i !输出1. 数据合法(0), 数据小于零(-1), 数据超过限制(1)
  call ts1%Set(1,3,1,63,4,5,6,301)      !设置时间间隔, 无status参数, 不检查时间格式,  +3::02:03:04.005006301
  write(*,"('ts1            = ',a)") ts1%ToString() !输出字符形式的时间间隔
  call ts2%Set(-1,2,3,5,1,1,121,405)   !设置时间间隔 -2::03:05:01.001121405
  write(*,"('ts2            = ',a)") ts2%ToString()
  write(*,"('ts1==ts2?      = ',g0)") ts1%CompareTo(ts2) !两个时间间隔比较,1,0,-1分别表示大于、等于、小于
  call ts1%Add(ts2)                    !两个时间间隔相加 0::22:58:03.003884896
  write(*,"('ts1+ts2        = ',a)") ts1%ToString()
  call ts1%subtract(ts2)               !两个时间间隔相减 3::02:03:04.005006301
  write(*,"('(ts1+ts2)-ts2  = ',a)") ts1%ToString()
  !时间间隔转为 天,小时,分钟,秒,毫秒,微秒,纳秒
  write(*,"('ts1: ')")
  write(*,"('转为   天: ',g0)") ts1%TotalDays()
  write(*,"('转为 小时: ',g0)") ts1%TotalHours()
  write(*,"('转为 分钟: ',g0)") ts1%TotalMinutes()
  write(*,"('转为   秒: ',g0)") ts1%TotalSeconds()
  write(*,"('转为 毫秒: ',g0)") ts1%TotalMilliseconds()
  write(*,"('转为 微秒: ',g0)") ts1%TotalMicroseconds()
  write(*,"('转为 纳秒: ',g0)") ts1%TotalNanoseconds()
  !----------------------------------------------------
  write(*,*)
  call DT1%Now()                       !获取当前的日期时间
  write(*,"('当前日期时间   = ',a)") DT1%ToString() !输出字符形式的日期时间
  write(*,"('在当年的天数   = ',g0)") DT1%DayOfYear() !该日期是当年的第几天
  write(*,"('星期           = ',g0)") DT1%DayOfWeek()        !该日期是星期几  
  call DT1%Set(2020,3,1,2,16,30,123)   !设置日期时间
  write(*,"('日期时间DT1    = ',a)") DT1%ToString()               
  write(*,"('是否闰年       = ',g0)")  DT1%IsLeapYear() !是否闰年
  call DT2%Set(2020,2,27,2,16,30,124)
  write(*,"('日期时间DT2    = ',a)") DT2%ToString() 
  write(*,"('DT1==DT2?      = ',g0)") DT1%CompareTo(DT2)   !两个日期时间比较,1,0,-1分别表示大于、等于、小于
  ts1 = DT2%SubtractDateTime(DT1)      !两个日期时间相减, 得到时间间隔
  write(*,"('DT2-DT1        = ',a)") ts1%ToString()
  call DT2%SubtractTimeSpan(ts1)       !日期减去时间间隔, 得到日期
  write(*,"('DT2-(DT2-DT1)  = ',a)") DT2%ToString()
  call DT2%Add(ts1)                    !日期加上时间间隔, 得到日期
  write(*,"('DT1+(DT2-DT1)  = ',a)") DT2%ToString()
  pause
  end program

 五、其他说明

  1. 为保证计算精度,日期应不早于1800年;如有特殊需求,可自行修改代码;
  2. 代码未经过严格测试,可能存在bug,如有发现请联系作者修订;
  3. 作者不对因使用该代码造成的任何后果负责,请酌情采用;
  4. 使用和传播时请保留作者版权信息。

附代码:

  !************************************************************
  ! 自定义TimeSpan类数据类型
  ! 作者:lixingwang@chd.edu.cn, 2022-12-02
  !************************************************************
  module Mod_TimeSpan
  implicit none
  private
  integer(4), parameter :: IP = 4, RP = 8
  type, public:: TimeSpan
    !定义TimeSpan结构体
    integer(IP) :: Sign = 1 !用1、-1分别表示正负
    integer(IP) :: Days = 0, Hours = 0, Minutes = 0, Seconds = 0, &
      Milliseconds = 0, Microseconds = 0, Nanoseconds = 0
  contains
  procedure, pass :: TotalDays, TotalHours, TotalMinutes, TotalSeconds, &
    TotalMilliseconds, TotalMicroseconds, TotalNanoseconds
  procedure, pass :: CompareTo
  procedure, pass :: ToString
  procedure, pass :: SetTimeSpan, SetFromSeconds
  procedure, pass :: Add
  procedure, pass :: Subtract
  generic:: Set => SetTimeSpan, SetFromSeconds
  end type TimeSpan
  contains
  !************************************************************
  !获取以整天数和天的小数部分表示的当前 TimeSpan 结构的值。
  !************************************************************
  elemental function TotalDays(ts) result(res)
  implicit none
  class(TimeSpan), intent(in):: ts
  real(RP) res
  res = TotalSeconds(ts) / 86400D0
  end function

  !************************************************************
  !获取以整小时数和小时的小数部分表示的当前 TimeSpan 结构的值。
  !************************************************************
  elemental function TotalHours(ts) result(res)
  implicit none
  class(TimeSpan), intent(in):: ts
  real(RP) res
  res = TotalSeconds(ts) / 3600D0
  end function

  !************************************************************
  !获取以整分钟数和分钟的小数部分表示的当前 TimeSpan 结构的值。
  !************************************************************
  elemental function TotalMinutes(ts) result(res)
  implicit none
  class(TimeSpan), intent(in):: ts
  real(RP) res
  res = TotalSeconds(ts) / 60D0
  end function

  !************************************************************
  !获取以整秒数和秒的小数部分表示的当前 TimeSpan 结构的值。
  !************************************************************
  elemental function TotalSeconds(ts) result(res)
  implicit none
  class(TimeSpan), intent(in):: ts
  real(RP) res
  res = 86400D0*ts%Days + 3600D0*ts%Hours + 60D0*ts%Minutes + &
    ts%Seconds + 1D-3*ts%Milliseconds + 1D-6*ts%Microseconds + &
    1D-9*ts%Nanoseconds
  if(ts%Sign<0) res = -res
  end function

  !************************************************************
  !获取以整毫秒数和毫秒的小数部分表示的当前 TimeSpan 结构的值
  !************************************************************
  elemental function TotalMilliseconds(ts) result(res)
  implicit none
  class(TimeSpan), intent(in):: ts
  real(RP) res
  res = TotalSeconds(ts) * 1D3
  end function

  !************************************************************
  !获取以整微秒和小数微秒表示的当前 TimeSpan 结构的值。
  !************************************************************
  elemental function TotalMicroseconds(ts) result(res)
  implicit none
  class(TimeSpan), intent(in):: ts
  real(RP) res
  res = TotalSeconds(ts) * 1D6
  end function

  !************************************************************
  !获取以整数和小数纳秒表示的当前 TimeSpan 结构的值。
  !************************************************************
  elemental function TotalNanoseconds(ts) result(res)
  implicit none
  class(TimeSpan), intent(in):: ts
  real(RP) res
  res = TotalSeconds(ts) * 1D9
  end function

  !************************************************************
  !返回一个新的 TimeSpan 对象
  !其值为指定的 TimeSpan 对象与此实例的值之和.
  !************************************************************
  elemental subroutine Add(ts1, ts2)
  implicit none
  class(TimeSpan), intent(inout):: ts1
  class(TimeSpan), intent(in):: ts2
  integer(IP), parameter :: SPAN(7) = [huge(1_IP), 24, 60, 60, 1000, 1000, 1000]
  integer(IP) IA(7), IB(7)
  integer(IP) i
  IA = [ts1%Days, ts1%Hours, ts1%Minutes, ts1%Seconds, ts1%Milliseconds, ts1%Microseconds, ts1%Nanoseconds]
  if(ts1%Sign<0) IA = -IA
  IB = [ts2%Days, ts2%Hours, ts2%Minutes, ts2%Seconds, ts2%Milliseconds, ts2%Microseconds, ts2%Nanoseconds]
  if(ts2%Sign<0) IB = -IB
  IA = IA + IB
  !确定正负
  ts1%Sign = 1
  do i = 1, size(IA)
    if(IA(i)>0) then
      exit
    else if(IA(i)<0) then
      ts1%Sign = -1
      IA = -IA
      exit
    end if
  end do
  !进位
  do i = size(IA), 2, -1
    if(IA(i)<0) then
      IA(i) = IA(i) + SPAN(i)
      IA(i-1) = IA(i-1) - 1
    else if(IA(i)>=SPAN(i)) then
      IA(i) = IA(i) - SPAN(i)
      IA(i-1) = IA(i-1) + 1
    end if
  end do
  call SetTimeSpan(ts1,ts1%Sign,IA(1),IA(2),IA(3),IA(4),IA(5),IA(6),IA(7))
  end subroutine

  !************************************************************
  !返回一个新的 TimeSpan 对象
  !其值为指定的 TimeSpan 对象与此实例的差值.
  !************************************************************
  elemental subroutine Subtract(ts1, ts2)
  implicit none
  class(TimeSpan), intent(inout):: ts1
  class(TimeSpan), intent(in):: ts2
  type(TimeSpan) ts
  ts = ts2; ts%Sign = -ts%Sign
  call Add(ts1, ts)
  end subroutine

  !************************************************************
  !比较两个 TimeSpan 值,并返回一个整数,
  !该整数指示第一个值是短于(-1)、等于(0)还是长于(1)第二个值。
  !************************************************************
  elemental function CompareTo(ts1, ts2) result(res)
  implicit none
  class(TimeSpan), intent(in):: ts1, ts2
  integer(IP) res
  integer(IP) IA(7), IB(7)
  integer(IP) i
  IA = [ts1%Days, ts1%Hours, ts1%Minutes, ts1%Seconds, ts1%Milliseconds, ts1%Microseconds, ts1%Nanoseconds]
  if(ts1%Sign<0) IA = -IA
  IB = [ts2%Days, ts2%Hours, ts2%Minutes, ts2%Seconds, ts2%Milliseconds, ts2%Microseconds, ts2%Nanoseconds]
  if(ts2%Sign<0) IB = -IB
  IA = IA - IB
  !确定正负
  res = 0
  do i = 1, size(IA)
    if(IA(i)>0) then
      res = 1
      exit
    else if(IA(i)<0) then
      res = -1
      exit
    end if
  end do
  end function

  !************************************************************
  !赋值TimeSpan类
  !************************************************************
  pure subroutine SetTimeSpan(ts, sign, d, h, m, s, ms, us, ns, status)
  implicit none
  class(TimeSpan), intent(out) :: ts
  integer(IP), intent(in):: sign, d, h, m, s, ms, us, ns
  integer(IP), intent(out), optional:: status
  integer(IP), parameter :: SPAN(7) = [huge(1_IP), 24, 60, 60, 1000, 1000, 1000]
  integer(IP) IA(7), i, n
  logical(IP) sta
  !判断是否有小于零的值
  IA = [d, h, m, s, ms, us, ns]
  if(any(IA<0)) then
    if(present(status)) then
      status = -1 !数据小于零
    else
      error stop 'the value of TimeSpan is wrong.'
    end if
    return
  end if
  !数据不符合时间格式
  if(present(status) .and. any(IA>=SPAN)) then
    status = 1 !数据超过上限
    return
  end if
  !数据处理
  do i = 7, 2, -1 !进位
    n = IA(i) / SPAN(i)
    IA(i) = IA(i) - n*SPAN(i)
    IA(i-1) = IA(i-1) + n
  end do
  !赋值
  if(sign>=0) then
    ts%Sign = 1
  else
    ts%Sign = -1
  end if
  ts%Days = IA(1); ts%Hours = IA(2); ts%Minutes = IA(3); ts%Seconds = IA(4)
  ts%Milliseconds = IA(5); ts%Microseconds = IA(6); ts%Nanoseconds = IA(7)
  !检查值是否合法
  sta = checkTimeSpan(ts)
  if(present(status)) then
    status = merge(0,-1,sta) !无误返回0,否则-1
  else
    if(.not.sta) error stop 'the value of TimeSpan is wrong.'
  end if
  end subroutine

  !************************************************************
  !赋值TimeSpan类
  !************************************************************
  pure subroutine SetFromSeconds(ts, seconds)
  implicit none
  class(TimeSpan), intent(out) :: ts
  real(RP), intent(in):: seconds
  logical(IP) sta
  integer(8) s, n
  if(seconds>=0) then
    ts%Sign = 1
  else
    ts%Sign = -1
  end if
  s = abs(seconds) !整数部分
  n = s / 86400; s = s - n*86400; ts%Days = n
  n = s / 3600;  s = s - n*3600;  ts%Hours = n
  n = s / 60;    s = s - n*60;    ts%Minutes = n
  ts%Seconds = s
  s = mod(abs(seconds),1D0)*1D9 + 0.01 !小数部分, 纳秒
  n = s / 1000000; s = s - n*1000000; ts%Milliseconds = n
  n = s / 1000;    s = s - n*1000;    ts%Microseconds = n
  ts%Nanoseconds = s
  !检查值是否合法
  sta = checkTimeSpan(ts)
  if(.not.sta) error stop 'the value of TimeSpan is wrong.'
  end subroutine

  !************************************************************
  !将当前 TimeSpan 对象的值转换为其等效的字符串表示形式。
  !************************************************************
  elemental function ToString(ts) result(res)
  implicit none
  class(TimeSpan), intent(in) :: ts
  character res*40, str*18
  res = ''
  write(res,*) ts%Days
  res = adjustl(res)
  if(ts%Sign<0) then
    res = '-' // res
  else
    res = '+' // res
  end if
  str = '12:45:78.123456789'
  write(str(1:2),'(i2.2)') ts%Hours
  write(str(4:5),'(i2.2)') ts%Minutes
  write(str(7:8),'(i2.2)') ts%Seconds
  write(str(10:12),'(i3.3)') ts%Milliseconds
  write(str(13:15),'(i3.3)') ts%Microseconds
  write(str(16:18),'(i3.3)') ts%Nanoseconds
  res = trim(res) // '::' // str
  end function ToString

  !************************************************************
  !检查 TimeSpan 对象的值是否正确。
  !************************************************************
  elemental function checkTimeSpan(ts) result(res)
  implicit none
  type(TimeSpan), intent(in) :: ts
  integer(IP), parameter :: SPAN(7) = [huge(1_IP), 24, 60, 60, 1000, 1000, 1000]
  integer(IP) IA(7)
  logical(IP) res
  res = .true.
  IA = [ts%Days, ts%Hours, ts%Minutes, ts%Seconds, ts%Milliseconds, ts%Microseconds, ts%Nanoseconds]
  if(any(IA>=SPAN) .or. any(IA<0)) res = .false.
  end function
  end module


  !************************************************************
  ! 自定义Date类数据类型
  ! 作者:lixingwang@chd.edu.cn, 2022-12-02
  !************************************************************
  module Mod_DateTime
  use Mod_TimeSpan, only: TimeSpan
  implicit none
  private
  public TimeSpan, DateTime
  integer(4),  parameter:: IP = 4
  integer(IP), parameter:: baseYear = 1800, maxYear = 5000 !能处理的日期上下界
  integer(IP), parameter:: DaysOfMonth(12)=[31,28,31,30,31,30,31,31,30,31,30,31]
  type DateTime
    integer(IP) :: Year = baseYear, Month = 1, Day = 1
    integer(IP) :: Hour = 0, Minute = 0, Second = 0, Millisecond = 0
  contains
  procedure, pass :: DayOfYear
  procedure, pass :: DayOfWeek
  procedure, pass :: CompareTo
  procedure, pass :: ToString
  procedure, pass :: IsLeapYear => fun_IsLeapYear
  procedure, pass :: Now
  procedure, pass :: Set
  procedure, pass :: Add
  procedure, pass :: SubtractTimeSpan
  procedure, pass :: SubtractDateTime
  end type DateTime

  contains
  !************************************************************
  !返回一个新的 DateTime
  !它将指定 TimeSpan 的值加到此实例的值上。
  !************************************************************
  elemental subroutine Add(DT, ts)
  implicit none
  class(DateTime), intent(inout) :: DT
  class(TimeSpan), intent(in) :: ts
  type(TimeSpan) ts0
  integer(IP) days(12)
  integer(IP) y, m, d, i
  !寻找基准时间
  y = DT%Year
  m = 1
  d = DayOfYear(DT) - 1
  if(ts%Sign<0) then
    do while(d<=ts%days)
      y = y - 1
      d = d + 365
      if(IsLeapYear(y)) d = d + 1
    end do
  end if
  !相加, 结果肯定为正
  call ts0%Set(1, d, DT%Hour, DT%Minute, DT%Second, DT%Millisecond, 0, 0)
  call ts0%Add(ts)
  !转为时间
  do !年
    if(IsLeapYear(y)) then
      d = 366
    else
      d = 365
    end if
    if(ts0%Days>=d) then
      y = y + 1
      ts0%Days = ts0%Days - d
    else
      d = ts0%Days + 1 !日期比天数多1
      exit
    end if
  end do
  !月
  days = DaysOfMonth
  if(IsLeapYear(y)) days(2) = days(2) + 1
  do i = 1, 11
    if(d>=days(i)) then
      m = m + 1
      d = d - days(i)
    else
      exit
    end if
  end do
  !设置时间
  call Set(DT, y, m, d, ts0%Hours, ts0%Minutes, ts0%Seconds, ts0%Milliseconds)
  end subroutine

  !************************************************************
  !将此实例的值与包含指定的 DateTime 值的指定对象相比较
  !并返回一个整数
  !该整数指示此实例是早于(-1)、等于(0)还是晚于(1)指定的 DateTime 值。
  !************************************************************
  elemental function CompareTo(DT1, DT2) result(Res)
  implicit none
  class(DateTime), intent(in) :: DT1, DT2
  integer(IP) Res, IA(7), IB(7), i
  IA = [DT1%Year, DT1%Month, DT1%Day, DT1%Hour, DT1%Minute, DT1%Second, DT1%Millisecond]
  IB = [DT2%Year, DT2%Month, DT2%Day, DT2%Hour, DT2%Minute, DT2%Second, DT2%Millisecond]
  Res = 0
  do i = 1, 7
    if(IA(i)>IB(i)) then
      Res = 1
      exit
    else if(IA(i)<IB(i)) then
      Res = -1
      exit
    end if
  end do
  end function

  !************************************************************
  !返回一个新的 DateTime
  !从此实例中减去指定持续时间间隔。
  !************************************************************
  elemental subroutine SubtractTimeSpan(DT, ts)
  implicit none
  class(DateTime), intent(inout) :: DT
  class(TimeSpan), intent(in) :: ts
  type(TimeSpan) ts0
  ts0 = ts
  ts0%Sign = -ts0%Sign
  call Add(DT, ts0)
  end subroutine

  !************************************************************
  !返回一个新的 TimeSpan
  !从此实例中减去指定的日期时间。
  !************************************************************
  elemental function SubtractDateTime(DT1, DT2) result(res)
  implicit none
  class(DateTime), intent(in):: DT1, DT2
  type(DateTime) p1, p2
  type(TimeSpan) res, ts
  integer(IP) sign, i, d
  !排序
  i = CompareTo(DT1, DT2)
  if(i<0) then
    p1 = DT2; p2 = DT1
    sign = -1
  elseif(i==0) then
    call res%Set(1,0,0,0,0,0,0,0)
    return
  else
    p1 = DT1; p2 = DT2
    sign = 1
  end if
  d = DayOfYear(p1)
  do i = p2%Year, p1%Year-1
    d = d + 365
    if(IsLeapYear(i)) d = d + 1
  end do
  call res%Set(1, d, p1%Hour, p1%Minute, p1%Second, p1%Millisecond, 0, 0)
  call ts%Set(1, DayOfYear(p2), p2%Hour, p2%Minute, p2%Second, p2%Millisecond, 0, 0)
  call res%Subtract(ts)
  res%sign = sign
  end function

  !************************************************************
  !赋值DateTime类
  !************************************************************
  pure subroutine Set(DT, yy, mm, dd, h, m, s, ms, status)
  implicit none
  class(DateTime), intent(out) :: DT
  integer(IP), intent(in) :: yy, mm, dd, h, m, s, ms
  integer(IP), intent(out), optional:: status
  logical(IP) sta
  DT%Year = yy; DT%Month = mm; DT%Day = dd; DT%Hour = h
  DT%Minute = m; DT%Second = s; DT%Millisecond = ms
  sta = checkDateTime(DT) !检查数据
  if(present(status)) then
    status = merge(0,-1,sta) !无误返回0,否则-1
  else
    if(.not.sta) error stop 'the value of DateTime is wrong.'
  end if
  end subroutine

  !************************************************************
  !将当前 DateTime 对象的值转换为它的等效字符串表示形式。
  !************************************************************
  elemental function ToString(DT) Result(Res)
  implicit none
  class(DateTime), intent(in) :: DT
  character Res*23
  Res = '2015-05-12 21:01:25.345'
  write(Res(1:4),'(i4.4)') DT%Year
  write(Res(6:7),'(i2.2)') DT%Month
  write(Res(9:10),'(i2.2)') DT%Day
  write(Res(12:13),'(i2.2)') DT%Hour
  write(Res(15:16),'(i2.2)') DT%Minute
  write(Res(18:19),'(i2.2)') DT%Second
  write(Res(21:23),'(i3.3)') DT%Millisecond
  end function

  !************************************************************
  !获取此实例所表示的日期是该年中的第几天。
  !************************************************************
  elemental function DayOfYear(DT) result(res)
  implicit none
  class(Datetime), intent(in) :: DT
  integer(IP) res
  res = sum(DaysOfMonth(1:DT%Month-1)) + DT%Day
  if(DT%Month>2 .and. IsLeapYear(DT%Year)) res = res + 1
  end function DayOfYear

  !************************************************************
  !获取此实例所表示的日期是星期几。
  !************************************************************
  elemental function DayOfWeek(DT) Result(Res)
  implicit none
  class(Datetime), intent(in) :: DT
  integer(IP) Res, year, month, day
  year = DT%Year
  month = DT%Month
  day = DT%Day
  Res = Week(year, month, day)
  if(res==0) res = 7
  contains
  !***************************************************
  ! 利用蔡勒(Zeller)公式计算星期
  !***************************************************
  elemental function Week(year, month, day)
  implicit none
  integer(IP), intent(in) :: year, month, day
  integer(IP) week, c
  integer(IP) y, m
  y = year; m = month
  !每年1、2月当做上一年的13、14月处理
  if(m < 3) then
    y = y-1; m = m+12
  end if
  c = int(y/100); y = mod(y,100); m = (m+1)*13
  y = y + day - 1 - (c+c) + int(c/4) + int(y/4) + int(m/5)
  week = mod(y,7)
  !防止取余结果为负数
  if(week < 0) week = week + 7
  end function
  end function

  !************************************************************
  !获取一个 DateTime 对象
  !该对象设置为此计算机上的当前日期和时间,表示为本地时间。
  !************************************************************
  subroutine Now(DT)
  implicit none
  class(DateTime), intent(out):: DT
  integer(IP) Date_Time(8)
  call date_and_time(values = Date_Time)
  DT%Year        = Date_Time(1)
  DT%Month       = Date_Time(2)
  DT%Day         = Date_Time(3)
  DT%Hour        = Date_Time(5)
  DT%Minute      = Date_Time(6)
  DT%Second      = Date_Time(7)
  DT%Millisecond = Date_Time(8)
  end subroutine

  !************************************************************
  ! 功能:     判断是否闰年
  ! 返回值:   IsLeapYear(4字节逻辑型),闰年则返回.true.
  ! 输入参数: year(4字节整型),代表年份
  !************************************************************
  elemental function IsLeapYear(year)
  implicit none
  integer(IP), intent(in) :: year
  logical(IP) IsLeapYear
  IsLeapYear = .false.
  if(mod(year,400)==0 .or. (mod(year,100)/=0.and.mod(year,4)==0) ) IsLeapYear = .true.
  end function IsLeapYear

  elemental function fun_IsLeapYear(DT) result(res)
  class(DateTime), intent(in) :: DT
  logical(IP) res
  res = IsLeapYear(DT%Year)
  end function

  !************************************************************
  !检查 DateTime 对象的值是否合法。
  !************************************************************
  elemental function checkDateTime(DT) result(res)
  implicit none
  type(DateTime), intent(in) :: DT
  integer(IP) SPAN(7)
  integer(IP) IA(7)
  logical(IP) res
  res = .true.
  if(DT%Month<1 .or. DT%Month>12) then
    res = .false.
    return
  end if
  !数据合理范围
  SPAN(:) = [maxYear, 13, DaysOfMonth(DT%Month)+1, 24, 60, 60, 1000]
  if(DT%Month==2 .and. IsLeapYear(DT%Year)) SPAN(3) = SPAN(3) + 1
  !检验
  IA = [DT%Year, DT%Month, DT%Day, DT%Hour, DT%Minute, DT%Second, DT%Millisecond]
  if(DT%Year<baseYear .or. any(IA>=SPAN) .or. any(IA<0)) res = .false.
  end function
  end module

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地球屋里老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值