1 |
C $Header: /u/gcmpack/MITgcm/pkg/cal/cal_addtime.F,v 1.3 2003/10/20 06:25:16 dimitri Exp $ |
2 |
C $Name: checkpoint54 $ |
3 |
|
4 |
#include "CAL_OPTIONS.h" |
5 |
|
6 |
subroutine cal_AddTime( |
7 |
I date, |
8 |
I interval, |
9 |
O added, |
10 |
I mythid |
11 |
& ) |
12 |
|
13 |
c ================================================================== |
14 |
c SUBROUTINE cal_AddTime |
15 |
c ================================================================== |
16 |
c |
17 |
c o Add a time interval either to a calendar date or to a time |
18 |
c interval. |
19 |
c |
20 |
c started: Christian Eckert eckert@mit.edu 30-Jun-1999 |
21 |
c |
22 |
c changed: Christian Eckert eckert@mit.edu 29-Dec-1999 |
23 |
c |
24 |
c - restructured the original version in order to have a |
25 |
c better interface to the MITgcmUV. |
26 |
c |
27 |
c Christian Eckert eckert@mit.edu 03-Feb-2000 |
28 |
c |
29 |
c - Introduced new routine and function names, cal_<NAME>, |
30 |
c for verion 0.1.3. |
31 |
c |
32 |
c ralf.giering@fastopt.de 31-May-2000 |
33 |
c datesecs was computed at wrong place (cph) |
34 |
c |
35 |
c menemenlis@jpl.nasa.gov 8-Oct-2003 |
36 |
c speed-up computations for long integration interval |
37 |
c |
38 |
c ================================================================== |
39 |
c SUBROUTINE cal_AddTime |
40 |
c ================================================================== |
41 |
|
42 |
implicit none |
43 |
|
44 |
c == global variables == |
45 |
|
46 |
#include "cal.h" |
47 |
|
48 |
c == routine arguments == |
49 |
|
50 |
integer date(4) |
51 |
integer interval(4) |
52 |
integer added(4) |
53 |
integer mythid |
54 |
|
55 |
c == local variables == |
56 |
|
57 |
integer intsecs |
58 |
integer datesecs |
59 |
integer nsecs |
60 |
integer hhmmss |
61 |
integer yi,mi,di,si,li,wi |
62 |
integer ndays, ndays_left, days_in_year |
63 |
integer date_1,date_2 |
64 |
integer intv_1,intv_2 |
65 |
integer fac |
66 |
integer iday |
67 |
integer switch |
68 |
integer ndayssub |
69 |
integer ierr |
70 |
|
71 |
c == external == |
72 |
|
73 |
integer cal_IsLeap |
74 |
external cal_IsLeap |
75 |
|
76 |
c == end of interface == |
77 |
|
78 |
if (interval(4) .ne. -1) then |
79 |
ierr = 601 |
80 |
call cal_PrintError( ierr, mythid) |
81 |
stop ' stopped in cal_AddTime.' |
82 |
endif |
83 |
|
84 |
date_1 = 0 |
85 |
date_2 = 0 |
86 |
fac = 1 |
87 |
|
88 |
if (date(4) .eq. -1) then |
89 |
if (date(1) .ge. 0) then |
90 |
date_1 = date(1) |
91 |
date_2 = date(2) |
92 |
intv_1 = interval(1) |
93 |
intv_2 = interval(2) |
94 |
else |
95 |
if (interval(1) .lt. 0) then |
96 |
date_1 = -date(1) |
97 |
date_2 = -date(2) |
98 |
intv_1 = -interval(1) |
99 |
intv_2 = -interval(2) |
100 |
fac = -1 |
101 |
else |
102 |
date_1 = interval(1) |
103 |
date_2 = interval(2) |
104 |
intv_1 = date(1) |
105 |
intv_2 = date(2) |
106 |
fac = 1 |
107 |
endif |
108 |
endif |
109 |
else |
110 |
if (interval(1) .ge. 0) then |
111 |
intv_1 = interval(1) |
112 |
intv_2 = interval(2) |
113 |
else |
114 |
intv_1 = -interval(1) |
115 |
intv_2 = -interval(2) |
116 |
fac = -1 |
117 |
endif |
118 |
endif |
119 |
|
120 |
intsecs = fac*(intv_2/10000*secondsperhour + |
121 |
& (mod(intv_2/100,100)*secondsperminute + |
122 |
& mod(intv_2,100))) |
123 |
|
124 |
if (date(4) .eq. -1) then |
125 |
datesecs = date_2/10000*secondsperhour + |
126 |
& mod(date_2/100,100)*secondsperminute + |
127 |
& mod(date_2,100) |
128 |
date_1 = date_1 + intv_1 |
129 |
nsecs = datesecs + intsecs |
130 |
if ((date_1 .gt. 0) .and. |
131 |
& (nsecs .lt. 0)) then |
132 |
date_1 = date_1 - 1 |
133 |
nsecs = nsecs + secondsperday |
134 |
endif |
135 |
nsecs = fac*nsecs |
136 |
yi = 0 |
137 |
mi = 0 |
138 |
di = fac*date_1 |
139 |
li = 0 |
140 |
wi = -1 |
141 |
else |
142 |
call cal_ConvDate( date,yi,mi,di,si,li,wi,mythid ) |
143 |
if ((interval(1) .ge. 0) .and. |
144 |
& (interval(2) .ge. 0)) then |
145 |
nsecs = si + intsecs |
146 |
ndays = interval(1)+nsecs/secondsperday |
147 |
nsecs = mod(nsecs,secondsperday) |
148 |
|
149 |
c This used to be called by exf_getffieldrec -> cal_GetDate |
150 |
c and was very slow for a long integration interval. |
151 |
c do iday = 1,ndays |
152 |
c di = di + 1 |
153 |
c if (di .gt. ndaymonth(mi,li)) then |
154 |
c di = 1 |
155 |
c mi = mi + 1 |
156 |
c endif |
157 |
c switch = (mi-1)/nmonthyear |
158 |
c yi = yi + switch |
159 |
c mi = mod(mi-1,nmonthyear)+1 |
160 |
c if (switch .eq. 1) li = cal_IsLeap( yi, mythid ) |
161 |
c enddo |
162 |
|
163 |
c Set start value |
164 |
ndays_left=ndays |
165 |
|
166 |
c First take care of February 29 |
167 |
if ( usingGregorianCalendar ) then |
168 |
if ( mi.eq.2 .and. di.eq.29 .and. ndays_left.gt.1 ) then |
169 |
mi = 3 |
170 |
di = 1 |
171 |
ndays_left = ndays_left - 1 |
172 |
endif |
173 |
endif |
174 |
|
175 |
c Next compute year |
176 |
days_in_year=ndaysnoleap |
177 |
if ((mi.gt.2.and.cal_IsLeap(yi+1,mythid).eq.2).or. |
178 |
& (mi.le.2.and.cal_IsLeap(yi,mythid).eq.2) ) |
179 |
& days_in_year=ndaysleap |
180 |
do while (ndays_left .ge. days_in_year) |
181 |
ndays_left = ndays_left - days_in_year |
182 |
yi = yi + 1 |
183 |
days_in_year=ndaysnoleap |
184 |
if ((mi.gt.2.and.cal_IsLeap(yi+1,mythid).eq.2).or. |
185 |
& (mi.le.2.and.cal_IsLeap(yi,mythid).eq.2) ) |
186 |
& days_in_year=ndaysleap |
187 |
enddo |
188 |
li = cal_IsLeap( yi, mythid ) |
189 |
|
190 |
c Finally compute day and month |
191 |
do iday = 1,ndays_left |
192 |
di = di + 1 |
193 |
if (di .gt. ndaymonth(mi,li)) then |
194 |
di = 1 |
195 |
mi = mi + 1 |
196 |
endif |
197 |
switch = (mi-1)/nmonthyear |
198 |
yi = yi + switch |
199 |
mi = mod(mi-1,nmonthyear)+1 |
200 |
if (switch .eq. 1) li = cal_IsLeap( yi, mythid ) |
201 |
enddo |
202 |
wi = mod(wi+ndays-1,7)+1 |
203 |
|
204 |
else |
205 |
nsecs = si + intsecs |
206 |
if (nsecs .ge. 0) then |
207 |
ndayssub = intv_1 |
208 |
else |
209 |
nsecs = nsecs + secondsperday |
210 |
ndayssub = intv_1 + 1 |
211 |
endif |
212 |
do iday = 1,ndayssub |
213 |
di = di - 1 |
214 |
if (di .eq. 0) then |
215 |
mi = mod(mi+10,nmonthyear)+1 |
216 |
switch = mi/nmonthyear |
217 |
yi = yi - switch |
218 |
if (switch .eq. 1) li = cal_IsLeap( yi, mythid ) |
219 |
di = ndaymonth(mi,li) |
220 |
endif |
221 |
enddo |
222 |
wi = mod(wi+6-mod(ndayssub,7),7)+1 |
223 |
endif |
224 |
endif |
225 |
|
226 |
c Convert to calendar format. |
227 |
added(1) = yi*10000 + mi*100 + di |
228 |
hhmmss = nsecs/secondsperminute |
229 |
added(2) = hhmmss/minutesperhour*10000 + |
230 |
& (mod(fac*hhmmss,minutesperhour)*100 + |
231 |
& mod(fac*nsecs,secondsperminute))*fac |
232 |
added(3) = li |
233 |
added(4) = wi |
234 |
|
235 |
return |
236 |
end |