My contribution to the 2038 problem:
----- o< ---------------------------------------------------
program p2038
! (c) Klaus Wacker
use datesub, only: jd,cdate
implicit none
integer, parameter :: minute=60
integer, parameter :: hour=60*minute
integer, parameter :: day=24*hour
integer, parameter :: maxepoch=(2**30-1)+2**30
integer date_time(8), jdmax, jdnow,jd1970,yyyy,mm,dd
integer secsmax,hoursmax,minsmax,yyyymax,mmmax,ddmax,daysub
integer monthstil
integer until(6)
integer i,ia,is,cnt
character*12 arg,lang
logical test,verbose
character*8, pointer :: texte(:,:)
character*8, target :: de_texte(2,9) = reshape( ['Jahr ','Jahre ','Monat ',&
&'Monate ', 'Tag ','Tage ','Stunde ','Stunden ','Minute ','Minuten ',&
&'Sekunde ','Sekunden','Noch ',' ',' und ',', ','Ende: ',&
&' '], shape(de_texte))
character*8, target :: en_texte(2,9) = reshape( ['year ','years ','month ',&
&'months ', 'day ','days ','hour ','hours ','minute ','minutes ',&
&'second ','seconds ',' ','left ',' and ',', ','The end:',&
&' '], shape(en_texte))
character*5 between
!
test=.false.
verbose=.false.
jd1970=jd(1970,1,1)
call date_and_time(values=date_time)
i=0
do ia=1,iargc()
call getarg(ia,arg)
if(arg.eq."-t") then
test=.true.
else if(arg.eq."-v") then
verbose=.true.
else
! numerical command line values override corresponding date_time values
i=i+1
read(arg,*,err=99) date_time(i)
endif
enddo
!
call getenv("LANG",lang)
if(test) write(*,*) "LANG=",lang
if(lang(1:2)=="de") then
texte => de_texte
else
texte => en_texte
endif
!
jdnow=jd(date_time(1),date_time(2),date_time(3))
if(test) write(*,*) date_time
jdmax=maxepoch/day+jd1970
secsmax=mod(maxepoch,day)
call hms(hoursmax,minsmax,secsmax)
call cdate(jdmax,yyyymax,mmmax,ddmax)
if(verbose) write(*,'(a,i4.4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a)') &
&trim(texte(1,9))//" ",&
&yyyymax,"-",mmmax,"-",ddmax,"-",hoursmax,":",minsmax,":",secsmax," UTC"
until(3)=jdmax-jdnow
until(6)=(jdnow-jd1970)*day - date_time(4)*minute &
& + date_time(5)*hour + date_time(6)*minute + date_time(7)
! this should be the same as $(date +%s)
if(test) write(*,*) until(6)
until(6) = maxepoch - until(6) - until(3)*day
daysub = 0
if(until(6)<0) then
daysub = 1
until(6) = until(6)+day
endif
call hms(until(4),until(5),until(6))
until(1) = yyyymax-date_time(1)
until(3) = jdmax - jd(date_time(1)+until(1),date_time(2),date_time(3)) - daysub
if(until(3)<0) then
until(1) = until(1)-1
! until(3) = jdmax - jd(date_time(1)+until(1),date_time(2),date_time(3)) - daysub
endif
! until(2) cannot be a do variable
do monthstil=11,0,-1
until(3) = jdmax - jd(date_time(1)+until(1) + (date_time(2)+monthstil-1)/12,&
&mod(date_time(2)+monthstil-1,12)+1,date_time(3)) - daysub
if(until(3)>=0) exit
enddo
until(2)=monthstil
cnt = count(until>0)
if(texte(1,7)/=" ") write(*,'(a)',advance="no") trim(texte(1,7))//" "
do i=1,6
if(cnt==2) then
between=texte(1,8)
elseif(cnt==1) then
between=""
else
between=texte(2,8)
endif
if(until(i)/=0) then
is=min(until(i),2)
write(*,'(i0,a)',advance="no") until(i)," "//trim(texte(is,i))//trim(between)//" "
cnt=cnt-1
endif
enddo
write(*,'(a)') trim(texte(2,7))
stop
!
99 write(*,*) "Invalid argument ",ia,": ",arg
stop 1
!
contains
subroutine hms(hours,mins,secs)
implicit none
integer, intent(inout) :: secs
integer, intent(out) :: hours,mins
hours=secs/hour
secs=mod(secs,hour)
mins=secs/minute
secs=mod(secs,minute)
end subroutine hms
end program p2038
----- o< ---------------------------------------------------
DATESUB is a piece of software that I got really long time ago via
this newsgroup (with some trivial cahnges in lowercase, mainly to turn
it into a module):
----- o< ---------------------------------------------------
module datesub
contains
SUBROUTINE CALEND(YYYY,DDD,MM,DD)
!=============CALEND WHEN GIVEN A VALID YEAR, YYYY, AND DAY OF THE
! YEAR, DDD, RETURNS THE MONTH, MM, AND DAY OF THE
! MONTH, DD.
! SEE ACM ALGORITHM 398, TABLELESS DATE CONVERSION, BY
! DICK STONE, CACM 13(10):621.
implicit none
INTEGER YYYY,DDD,MM,DD,T
T=0
IF(MOD(YYYY,4).EQ.0) T=1
!-----------THE FOLLOWING STATEMENT IS NECESSARY IF YYYY IS LESS TNAN
! 1900 OR GREATER THAN 2100.
IF(MOD(YYYY,400).NE.0.AND.MOD(YYYY,100).EQ.0) T=0
DD=DDD
IF(DDD.GT.59+T) DD=DD+2-T
MM=((DD+91)*100)/3055
DD=(DD+91)-(MM*3055)/100
MM=MM-2
!----------MM WILL BE CORRECT IFF DDD IS CORRECT FOR YYYY.
IF(MM.GE.1 .AND. MM.LE.12) RETURN
WRITE(*,1) DDD
1 FORMAT('0$$$CALEND: DAY OF THE YEAR INPUT =',I11,' IS OUT OF RANGE.')
STOP
END SUBROUTINE
SUBROUTINE CDATE(JD,YYYY,MM,DD)
!=======GIVEN A JULIAN DAY NUMBER, NNNNNNNN, YYYY,MM,DD ARE RETURNED AS
! AS THE CALENDAR DATE. JD=NNNNNNNN IS THE JULIAN DATE
! FROM AN EPOCK IN THE VERY DISTANT PAST. SEE CACM
! 1968 11(10):657, LETTER TO THE EDITOR BY FLIEGEL AND
! VAN FLANDERN.
! EXAMPLE CALL CDATE(2440588,YYYY,MM,DD) RETURNS 1970 1 1 .
!
implicit none
INTEGER JD,YYYY,MM,DD,L,N
L=JD+68569
N=4*L/146097
L=L-(146097*N + 3)/4
YYYY=4000*(L+1)/1461001
L=L-1461*YYYY/4+31
MM=80*L/2447
DD=L-2447*MM/80
L=MM/11
MM=MM + 2 - 12*L
YYYY=100*(N-49) + YYYY + L
RETURN
END SUBROUTINE CDATE
SUBROUTINE DAYSUB(JD,YYYY,MM,DD,WD,DDD)
!========GIVEN JD, A JULIAN DAY # (SEE ASF JD), THIS ROUTINE
! CALCULATES DD, THE DAY NUMBER OF THE MONTH; MM, THE MONTH
! NUMBER; YYYY THE YEAR; WD THE WEEKDAY NUMBER, AND DDD
! THE DAY NUMBER OF THE YEAR.
! ARITHMETIC STATEMENT FUNCTIONS 'IZLR' AND 'IDAY' ARE TAKEN
! FROM REMARK ON ALGORITHM 398, BY J. DOUGLAS ROBERTSON,
! CACM 15(10):918.
!
! EXAMPLE: CALL DAYSUB(2440588,YYYY,MM,DD,WD,DDD) YIELDS 1970 1 1 4 1.
!
implicit none
INTEGER JD,YYYY,MM,DD,WD,DDD
integer iday,izlr
!
!------IZLR(YYYY,MM,DD) GIVES THE WEEKDAY NUMBER 0=SUNDAY, 1=MONDAY,
! ... 6=SATURDAY. EXAMPLE: IZLR(1970,1,1)=4=THURSDAY
!
IZLR(YYYY,MM,DD)=MOD((13*(MM+10-(MM+10)/13*12)-1)/5+DD+77 &
+5*(YYYY+(MM-14)/12-(YYYY+(MM-14)/12)/100*100)/4 &
+ (YYYY+(MM-14)/12)/400-(YYYY+(MM-14)/12)/100*2,7)
!
!------IDAY IS A COMPANION TO CALEND; GIVEN A CALENDAR DATE, YYYY, MM,
! DD, IDAY IS RETURNED AS THE DAY OF THE YEAR.
! EXAMPLE: IDAY(1984,4,22)=113
!
IDAY(YYYY,MM,DD)=3055*(MM+2)/100-(MM+10)/13*2-91 &
+(1-(MOD(YYYY,4)+3)/4+(MOD(YYYY,100)+99)/100 &
-(MOD(YYYY,400)+399)/400)*(MM+10)/13+DD
!
CALL CDATE(JD,YYYY,MM,DD)
WD=IZLR(YYYY,MM,DD)
DDD=IDAY(YYYY,MM,DD)
RETURN
END SUBROUTINE DAYSUB
FUNCTION JD(YYYY,MM,DD)
implicit none
integer jd
INTEGER YYYY,MM,DD
! DATE ROUTINE JD(YYYY,MM,DD) CONVERTS CALENDER DATE TO
! JULIAN DATE. SEE CACM 1968 11(10):657, LETTER TO THE
! EDITOR BY HENRY F. FLIEGEL AND THOMAS C. VAN FLANDERN.
! EXAMPLE JD(1970,1,1)=2440588
JD=DD-32075+1461*(YYYY+4800+(MM-14)/12)/4 &
+367*(MM-2-((MM-14)/12)*12)/12-3* &
((YYYY+4900+(MM-14)/12)/100)/4
RETURN
END FUNCTION JD
FUNCTION NDAYS(MM1,DD1,YYYY1, MM2,DD2,YYYY2)
implicit none
integer ndays
INTEGER YYYY1,MM1,DD1,YYYY2,MM2,DD2
!==============NDAYS IS RETURNED AS THE NUMBER OF DAYS BETWEEN TWO
! DATES; THAT IS MM1/DD1/YYYY1 MINUS MM2/DD2/YYYY2,
! WHERE DATEI AND DATEJ HAVE ELEMENTS MM, DD, YYYY.
!-------NDAYS WILL BE POSITIVE IFF DATE1 IS MORE RECENT THAN DATE2.
NDAYS=JD(YYYY1,MM1,DD1)-JD(YYYY2,MM2,DD2)
RETURN
END FUNCTION NDAYS
end module datesub
----- o< ---------------------------------------------------
--
Klaus Wacker
klaus.w...@t-online.de
51°29'7"N 7°25'7"E