UNIX時間(1)からの続き
他の言語の場合,対応する組み込み関数が用意されているので簡単に実現できるのだけれど,Fortranの場合,date_and_timeという日時取得関数やsystem_clockというシステム時間取得関数などがあるが,いずれもUNIX時間には対応していない。
ChatGPTやBingChatにきいても,Fortranの場合はシステム依存性があるので処理系によってまちまちだというばかり,macOSではどうかと水を向けても思わしい答えが返ってこない。
仕方がないので,ユーザ関数として定義することにするが,適当な例題がみつからない。C言語の例ならすぐに見つかった。これをChatGPTにFortranに変換してもらったが,うまくいなかい。そもそも,例題のアルゴリズムが,西暦0年3月を起点にしてとか,UNIX日から月の算出にmonth = (unixday * 5 + 2) / 153 を使うとか技巧的すぎるのだ。
そこで,シンプルに,与えられたUNIX時間(秒)を24*60*60=86400秒で割ったUNIX日(日)から毎年の日数を引き算することにした。グレゴリオ暦のある年がうるう年かどうかの判定なら簡単である。これが負になるところが対応する年であり,足し戻したUNIX日から月単位で引き算し,これが負になるところが対応する月である。これを足し戻せば対応する日付にたどりつく。
このプログラムでは,整数を4バイト=32ビットの符号付き整数として扱っているため,2038年問題に引っかかる。ut = (2**15-1)*(2**16+1) +2**15 -9*3600 =2**31-1 -9*3600 に1加えると異常値が出ることを確かめられる。
!------- time.f95 ------- 2023.02.22 ------- K.Koshigiri -------!
!-------+-------+-------+-------+-------+-------+-------+-------!
program time_code
!-------+-------+-------+-------+-------+-------+-------+-------!
implicit none
integer :: dtm(8),dtm0(8),ut,ut0,jst;
integer(8) :: ut8
character*10 a,b,c,fmt
!
interface
function dtm2ut(dtm)
integer :: dtm(8),dtm2ut
end function dtm2ut
function ut2dtm(ut)
integer :: ut2dtm(8),ut
end function ut2dtm
end interface
!
!現在時刻の取得
call date_and_time(a,b,c, dtm)
call system_clock(count=ut)
! call gtime(count=ut)
print *, ut
print *, ' '//a(1:4)//'-'//a(5:6)//'-'//a(7:8)
print *, ' '//b(1:2)//':'//b(3:4)//':'//b(5:10)
jst = dtm(4) ; print *, c, jst ; write(*, *)
!UNIX時間へ変換
ut = dtm2ut(dtm)
write(*,'("unixtime = ",i10)') ut
!年月日時分秒へ変換
write(*,'(i6,"-",i2,"-",i2,i6,i3,":",i2,":",i2,".",i3)') ut2dtm(ut)
!UNIX基準時(JST)
dtm0 = [1970,1,1,jst,9,0,0,0]
write(*,'("unixtime = ",i11)') dtm2ut(dtm0)
ut0 = 0
write(*,'(i6,"-",i2,"-",i2,i6,i3,":",i2,":",i2,".",i3)') ut2dtm(ut0)
!2038年問題(JST)
dtm = [2038,1,19,jst,12,14,7,0]
write(*,'("unixtime = ",i11)') dtm2ut(dtm)
ut = (2**15-1)*(2**16+1) +2**15 -9*3600
write(*,'(i6,"-",i2,"-",i2,i6,i3,":",i2,":",i2,".",i3)') ut2dtm(ut)
!
end program time_code
!-------+-------+-------+-------+-------+-------+-------+-------!
function dtm2ut(dtm) result(ut)
!-------+-------+-------+-------+-------+-------+-------+-------!
! dtm=[y,m,d,dev,hour,min,sec,msec]@JST ->
! unixtime@GMT (formal seconds from 1970-1-1 00:00:00)
implicit none
integer :: ut, dtm(8), ud, y, m, d, hour, min, sec
integer, parameter :: ed = 719468 ! 1970_1_1 <= 1900_1_1
integer, parameter :: md(13) = &
[0,31,61,92,122,153,184,214,245,275,306,337,365]
!
y = dtm(1) ; m = dtm(2) ; d = dtm(3)
hour = dtm(5) - 9 ; min = dtm(6) ; sec = dtm(7)
if (m<3) then
m = m + 12; y = y - 1
endif
m = m - 3 ! 0:March
ud = y*365 + y/4 - y/100 + y/400 + md(m+1) + d - 1 - ed
ut = (ud * 24 + hour) * 60 + min
ut = (ut * 60 + sec) ! return unixtime(s)
end function dtm2ut
!-------+-------+-------+-------+-------+-------+-------+-------!
function ut2dtm(ut) result(dtm)
!-------+-------+-------+-------+-------+-------+-------+-------!
! ut=unixtime to dtm[y,m,d,dev,hour,min,sec,msec] for JST
implicit none
integer :: dtm(8), ut, jst, ud, wd, y, m, d, hour, min, sec
integer, parameter :: md(12) = [31,28,31,30,31,30,31,31,30,31,30,31]
!
interface
function lp(y, m)
integer :: lp, y, m
end function lp
end interface
!
jst = 9*60
ut = ut + jst*60
sec = mod(ut, 60)
min = mod(ut / 60, 60)
hour = mod(ut / 3600, 24)
ud = ut / (24*60*60)
! wd = mod(ud + 3, 7)
!
y = 1969
do while (ud >= 0)
y = y + 1 ; ud = ud - 365 - lp(y,2)
end do
ud = ud + 365 + lp(y,2)
!
m = 0
do while (ud >= 0)
m = m + 1 ; ud = ud - md(m) - lp(y,m)
end do
d = ud + md(m) + lp(y,m) + 1
!
dtm = [y,m,d,jst,hour,min,sec,0]
end function ut2dtm
!-------+-------+-------+-------+-------+-------+-------+-------!
function lp(y,m) result(leap)
!-------+-------+-------+-------+-------+-------+-------+-------!
implicit none
integer y, m, leap
!
leap = 0
if(m == 2) then
if( mod(y,4)==0 .and. mod(y,100)/=0 .or. mod(y,400)==0 ) then
leap = 1
endif
endif
end function lp
!-------+-------+-------+-------+-------+-------+-------+-------!
0 件のコメント:
コメントを投稿