doomsday.f
1 ! @section Synopsis
2 !
3 ! Doomsday algorithm giving the day of the week for a date.
4 !
5 ! @author J. Marcel van der Veer
6 !
7 ! @section copyright
8 !
9 ! This file is part of VIF - vintage fortran compiler.
10 ! Copyright 2020-2025 J. Marcel van der Veer <algol68g@xs4all.nl>.
11 !
12 ! @section license
13 !
14 ! This program is free software; you can redistribute it and/or modify it
15 ! under the terms of the gnu general public license as published by the
16 ! free software foundation; either version 3 of the license, or
17 ! (at your option) any later version.
18 !
19 ! This program is distributed in the hope that it will be useful, but
20 ! without any warranty; without even the implied warranty of merchantability
21 ! or fitness for a particular purpose. See the GNU general public license for
22 ! more details. You should have received a copy of the GNU general public
23 ! license along with this program. If not, see <http://www.gnu.org/licenses/>.
24 !
25 subroutine doomsday_gregorian ( y, m, d, w )
26
27 c DOOMSDAY_GREGORIAN(): weekday given any date in Gregorian calendar.
28 c
29 c Discussion:
30 c
31 c This procedure does not include any procedure to switch to the Julian
32 c calendar for dates early enough that that calendar was used instead.
33 c
34 c Licensing:
35 c
36 c This code is distributed under the MIT license.
37 c
38 c Modified:
39 c
40 c 28 May 2012
41 c
42 c Author:
43 c
44 c John Burkardt
45 c
46 c Reference:
47 c
48 c John Conway,
49 c Tomorrow is the Day After Doomsday,
50 c Eureka,
51 c Volume 36, October 1973, pages 28-31.
52 c
53 c Parameters:
54 c
55 c Input, integer Y, M, D, the year, month and day of the date.
56 c Note that the year must be positive.
57 c
58 c Output, integer W, the weekday of the date.
59 c
60 implicit none
61
62 integer anchor(4)
63 integer c
64 integer d
65 integer drd
66 integer drdr
67 integer i4_wrap
68 integer l
69 integer m
70 integer mdoom(12)
71 integer w
72 integer y
73 integer ydoom
74 logical year_is_leap_gregorian
75 integer yy
76 integer yy12d
77 integer yy12r
78 integer yy12r4d
79
80 save anchor
81 save mdoom
82
83 data anchor / 1, 6, 4, 3 /
84 data mdoom / 3, 28, 0, 4, 9, 6, 11, 8, 5, 10, 7, 12 /
85 c
86 c Refuse to handle Y <= 0.
87 c
88 if ( y .le. 0 ) then
89 write ( *, '(a)' ) ' '
90 write ( *, '(a)' ) 'DOOMSDAY_GREGORIAN - Fatal error!'
91 write ( *, '(a)' ) ' Y <= 0.'
92 stop
93 end if
94 c
95 c Determine the century C.
96 c
97 c = y / 100
98 c
99 c Determine the last two digits of the year, YY
100 c
101 yy = mod ( y, 100 )
102 c
103 c Divide the last two digits of the year by 12.
104 c
105 yy12d = yy / 12
106 yy12r = mod ( yy, 12 )
107 yy12r4d = yy12r / 4
108 drd = yy12d + yy12r + yy12r4d
109
110 drdr = mod ( drd, 7 )
111 ydoom = anchor( mod ( c-1, 4 ) + 1 ) + drdr
112 ydoom = i4_wrap ( ydoom, 1, 7 )
113 c
114 c If M = 1 or 2, and Y is a leap year, add 1.
115 c
116 if ( ( m .eq. 1 .or. m .eq. 2 ) .and.
117 & year_is_leap_gregorian ( y ) ) then
118 l = 1
119 else
120 l = 0
121 end if
122
123 w = ydoom + ( d - mdoom(m) - l )
124 w = i4_wrap ( w, 1, 7 )
125
126
127 return
128 end
129
130 function i4_modp ( i, j )
131
132 cc I4_MODP returns the nonnegative remainder of integer division.
133 c
134 c Discussion:
135 c
136 c If
137 c NREM = I4_MODP ( I, J )
138 c NMULT = ( I - NREM ) / J
139 c then
140 c I = J * NMULT + NREM
141 c where NREM is always nonnegative.
142 c
143 c The MOD function computes a result with the same sign as the
144 c quantity being divided. Thus, suppose you had an angle A,
145 c and you wanted to ensure that it was between 0 and 360.
146 c Then mod(A,360) would do, if A was positive, but if A
147 c was negative, your result would be between -360 and 0.
148 c
149 c On the other hand, I4_MODP(A,360) is between 0 and 360, always.
150 c
151 c Example:
152 c
153 c I J MOD I4_MODP Factorization
154 c
155 c 107 50 7 7 107 = 2 * 50 + 7
156 c 107 -50 7 7 107 = -2 * -50 + 7
157 c -107 50 -7 43 -107 = -3 * 50 + 43
158 c -107 -50 -7 43 -107 = 3 * -50 + 43
159 c
160 c Licensing:
161 c
162 c This code is distributed under the MIT license.
163 c
164 c Modified:
165 c
166 c 30 December 2006
167 c
168 c Author:
169 c
170 c John Burkardt
171 c
172 c Parameters:
173 c
174 c Input, integer I, the number to be divided.
175 c
176 c Input, integer J, the number that divides I.
177 c
178 c Output, integer I4_MODP, the nonnegative remainder when I is
179 c divided by J.
180 c
181 implicit none
182
183 integer i
184 integer i4_modp
185 integer j
186 integer value
187
188 if ( j .eq. 0 ) then
189 call xerabt ('i4_modp: illegal divisor', 1)
190 end if
191
192 value = mod ( i, j )
193
194 if ( value .lt. 0 ) then
195 value = value + abs ( j )
196 end if
197
198 i4_modp = value
199
200 return
201 end
202
203 function i4_wrap ( ival, ilo, ihi )
204
205 c I4_WRAP forces an I4 to lie between given limits by wrapping.
206 c
207 c Example:
208 c
209 c ILO = 4, IHI = 8
210 c
211 c I Value
212 c
213 c -2 8
214 c -1 4
215 c 0 5
216 c 1 6
217 c 2 7
218 c 3 8
219 c 4 4
220 c 5 5
221 c 6 6
222 c 7 7
223 c 8 8
224 c 9 4
225 c 10 5
226 c 11 6
227 c 12 7
228 c 13 8
229 c 14 4
230 c
231 c Licensing:
232 c
233 c This code is distributed under the MIT license.
234 c
235 c Modified:
236 c
237 c 31 December 2006
238 c
239 c Author:
240 c
241 c John Burkardt
242 c
243 c Parameters:
244 c
245 c Input, integer IVAL, an integer value.
246 c
247 c Input, integer ILO, IHI, the desired bounds for the integer value.
248 c
249 c Output, integer I4_WRAP, a "wrapped" version of IVAL.
250 c
251 implicit none
252
253 integer i4_modp
254 integer i4_wrap
255 integer ihi
256 integer ilo
257 integer ival
258 integer jhi
259 integer jlo
260 integer value
261 integer wide
262
263 jlo = min ( ilo, ihi )
264 jhi = max ( ilo, ihi )
265
266 wide = jhi - jlo + 1
267
268 if ( wide .eq. 1 ) then
269 value = jlo
270 else
271 value = jlo + i4_modp ( ival - jlo, wide )
272 end if
273
274 i4_wrap = value
275
276 return
277 end
278
279 subroutine weekday_to_name_common ( w, s )
280
281 c WEEKDAY_TO_NAME_COMMON returns the name of a Common weekday.
282 c
283 c Licensing:
284 c
285 c This code is distributed under the MIT license.
286 c
287 c Modified:
288 c
289 c 28 August 1999
290 c
291 c Author:
292 c
293 c John Burkardt
294 c
295 c Parameters:
296 c
297 c Input, integer W, the weekday index.
298 c
299 c Output, character * ( * ) S, the weekday name.
300 c
301 implicit none
302
303 character * 9 name(7)
304 character * ( * ) s
305 integer w
306 integer w2
307
308 save name
309
310 data name /
311 & 'Sunday ', 'Monday ', 'Tuesday ', 'Wednesday',
312 & 'Thursday ', 'Friday ', 'Saturday ' /
313 c
314 c Make a local copy of the weekday number.
315 c
316 w2 = w
317 c
318 c Return the weekday name.
319 c
320 s = name ( w2 )
321
322 return
323 end
324
325 subroutine weekday_values ( n_data, y, m, d, w )
326
327 c WEEKDAY_VALUES returns the day of the week for various dates.
328 c
329 c Discussion:
330 c
331 c The CE or Common Era calendar is used, under the
332 c hybrid Julian/Gregorian Calendar, with a transition from Julian
333 c to Gregorian. The day after 04 October 1582 was 15 October 1582.
334 c
335 c The year before 1 AD or CE is 1 BC or BCE. In this data set,
336 c years BC/BCE are indicated by a negative year value.
337 c
338 c Licensing:
339 c
340 c This code is distributed under the MIT license.
341 c
342 c Modified:
343 c
344 c 26 May 2012
345 c
346 c Author:
347 c
348 c John Burkardt
349 c
350 c Reference:
351 c
352 c Edward Reingold, Nachum Dershowitz,
353 c Calendrical Calculations: The Millennium Edition,
354 c Cambridge University Press, 2001,
355 c ISBN: 0 521 77752 6
356 c LC: CE12.R45.
357 c
358 c Parameters:
359 c
360 c Input/output, integer N_DATA. The user sets N_DATA to 0
361 c before the first call. On each call, the routine increments N_DATA by 1,
362 c and returns the corresponding data; when there is no more data, the
363 c output value of N_DATA will be 0 again.
364 c
365 c Output, integer Y, M, D, the Common Era date.
366 c
367 c Output, integer W, the day of the week. Sunday = 1.
368 c
369 implicit none
370
371 integer n_max
372 parameter ( n_max = 34 )
373
374 integer d
375 integer d_vec(n_max)
376 integer m
377 integer m_vec(n_max)
378 integer n_data
379 integer w
380 integer w_vec(n_max)
381 integer y
382 integer y_vec(n_max)
383
384 save d_vec
385 save m_vec
386 save w_vec
387 save y_vec
388
389 data d_vec /
390 & 30,
391 & 8,
392 & 26,
393 & 3,
394 & 7,
395 & 18,
396 & 7,
397 & 19,
398 & 14,
399 & 18,
400 & 16,
401 & 3,
402 & 26,
403 & 20,
404 & 4,
405 & 25,
406 & 31,
407 & 9,
408 & 24,
409 & 10,
410 & 30,
411 & 24,
412 & 19,
413 & 2,
414 & 27,
415 & 19,
416 & 25,
417 & 29,
418 & 19,
419 & 7,
420 & 17,
421 & 25,
422 & 10,
423 & 18 /
424 data m_vec /
425 & 7,
426 & 12,
427 & 9,
428 & 10,
429 & 1,
430 & 5,
431 & 11,
432 & 4,
433 & 10,
434 & 5,
435 & 3,
436 & 3,
437 & 3,
438 & 4,
439 & 6,
440 & 1,
441 & 3,
442 & 9,
443 & 2,
444 & 6,
445 & 6,
446 & 7,
447 & 6,
448 & 8,
449 & 3,
450 & 4,
451 & 8,
452 & 9,
453 & 4,
454 & 10,
455 & 3,
456 & 2,
457 & 11,
458 & 7 /
459 data w_vec /
460 & 1,
461 & 4,
462 & 4,
463 & 1,
464 & 4,
465 & 2,
466 & 7,
467 & 1,
468 & 7,
469 & 1,
470 & 6,
471 & 7,
472 & 6,
473 & 1,
474 & 1,
475 & 4,
476 & 7,
477 & 7,
478 & 7,
479 & 4,
480 & 1,
481 & 6,
482 & 1,
483 & 2,
484 & 4,
485 & 1,
486 & 1,
487 & 2,
488 & 2,
489 & 5,
490 & 3,
491 & 1,
492 & 4,
493 & 1 /
494 data y_vec /
495 & - 587,
496 & - 169,
497 & 70,
498 & 135,
499 & 470,
500 & 576,
501 & 694,
502 & 1013,
503 & 1066,
504 & 1096,
505 & 1190,
506 & 1240,
507 & 1288,
508 & 1298,
509 & 1391,
510 & 1436,
511 & 1492,
512 & 1553,
513 & 1560,
514 & 1648,
515 & 1680,
516 & 1716,
517 & 1768,
518 & 1819,
519 & 1839,
520 & 1903,
521 & 1929,
522 & 1941,
523 & 1943,
524 & 1943,
525 & 1992,
526 & 1996,
527 & 2038,
528 & 2094 /
529
530 if ( n_data .lt. 0 ) then
531 n_data = 0
532 end if
533
534 n_data = n_data + 1
535
536 if ( n_max .lt. n_data ) then
537 n_data = 0
538 y = 0
539 m = 0
540 d = 0
541 w = 0
542 else
543 y = y_vec(n_data)
544 m = m_vec(n_data)
545 d = d_vec(n_data)
546 w = w_vec(n_data)
547 end if
548
549 return
550 end
551
552 function year_is_leap_gregorian ( y )
553
554 c YEAR_IS_LEAP_GREGORIAN returns TRUE if the Gregorian year was a leap year.
555 c
556 c Licensing:
557 c
558 c This code is distributed under the MIT license.
559 c
560 c Modified:
561 c
562 c 21 May 2000
563 c
564 c Author:
565 c
566 c John Burkardt
567 c
568 c Parameters:
569 c
570 c Input, integer Y, the year to be checked.
571 c
572 c Output, logical YEAR_IS_LEAP_GREGORIAN, TRUE if the year was a leap year,
573 c FALSE otherwise.
574 c
575 implicit none
576
577 integer y
578 logical year_is_leap_gregorian
579
580 if ( y .le. 0 ) then
581 call xerabt ('year_is_leap_gregorian: invalid year', 1)
582 end if
583
584 if ( mod ( y, 400 ) .eq. 0 ) then
585 year_is_leap_gregorian = .true.
586 else if ( mod ( y, 100 ) .eq. 0 ) then
587 year_is_leap_gregorian = .false.
588 else if ( mod ( y, 4 ) .eq. 0 ) then
589 year_is_leap_gregorian = .true.
590 else
591 year_is_leap_gregorian = .false.
592 end if
593
594 return
595 end
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|