FV3 Bundle
Date_Utility.f90
Go to the documentation of this file.
1 !
2 ! Date_Utility
3 !
4 ! Module containing date conversion routines
5 !
6 !
7 ! CREATION HISTORY:
8 ! Written by: Paul van Delst, 03-Apr-2000
9 ! paul.vandelst@noaa.gov
10 
12 
13  ! -----------------
14  ! Environment setup
15  ! -----------------
16  IMPLICIT NONE
17 
18 
19 
20  ! ------------
21  ! Visibilities
22  ! ------------
23  PRIVATE
24  ! Parameters
25  PUBLIC :: n_months
27  PUBLIC :: month_name
28  PUBLIC :: n_days
29  PUBLIC :: day_name
30  ! Procedures
31  PUBLIC :: isleapyear
32  PUBLIC :: dayofyear
33  PUBLIC :: daysinmonth
34  PUBLIC :: nameofmonth
35  PUBLIC :: dayofweek
36 
37 
38  ! ----------
39  ! Parameters
40  ! ----------
41  CHARACTER(*), PARAMETER :: module_version_id = &
42  '$Id: Date_Utility.f90 60152 2015-08-13 19:19:13Z paul.vandelst@noaa.gov $'
43  ! String length for character functions
44  INTEGER, PARAMETER :: nl = 20
45  ! Number of Months in a Year
46  INTEGER, PARAMETER :: n_months = 12
47  ! Days per Month in a non leap Year
48  INTEGER, PARAMETER :: days_per_month_in_nonleap(n_months) = &
49  (/ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 /)
50  ! Month names
51  CHARACTER(*), PARAMETER :: month_name(n_months) = &
52  (/'January ','February ','March ','April ','May ','June ', &
53  'July ','August ','September','October ','November ','December ' /)
54  ! Number of Days in a Week
55  INTEGER, PARAMETER :: n_days = 7
56  ! Day names
57  CHARACTER(*), PARAMETER :: day_name(n_days) = &
58  (/'Sunday ','Monday ','Tuesday ','Wednesday','Thursday ','Friday ','Saturday '/)
59 
60 
61 CONTAINS
62 
63 
64 !##############################################################################
65 !##############################################################################
66 !## ##
67 !## ## PUBLIC MODULE ROUTINES ## ##
68 !## ##
69 !##############################################################################
70 !##############################################################################
71 
72 !------------------------------------------------------------------------------
73 !:sdoc+:
74 !
75 ! NAME:
76 ! IsLeapYear
77 !
78 ! PURPOSE:
79 ! Elemental function to determine if a specified year is a leap year.
80 !
81 ! CALLING SEQUENCE:
82 ! Result = IsLeapYear( Year )
83 !
84 ! INPUT ARGUMENTS:
85 ! Year: The year in 4-digit format, e.g. 1997.
86 ! UNITS: N/A
87 ! TYPE: INTEGER
88 ! DIMENSION: Scalar
89 ! ATTRIBUTES: INTENT(IN)
90 !
91 ! FUNCTION RESULT:
92 ! Result: The return value is a logical value indicating whether
93 ! the specified year is a leap year.
94 ! If .TRUE. the specified year IS a leap year.
95 ! .FALSE. the specified year is NOT a leap year.
96 ! UNITS: N/A
97 ! TYPE: LOGICAL
98 ! DIMENSION: Scalar
99 !:sdoc-:
100 !------------------------------------------------------------------------------
101 
102  ELEMENTAL FUNCTION isleapyear( Year )
103  INTEGER, INTENT(IN) :: year
104  LOGICAL :: isleapyear
105 
106  isleapyear = ( (mod(year,4) == 0) .AND. (mod(year,100) /= 0) ) .OR. &
107  (mod(year,400) == 0)
108 
109  END FUNCTION isleapyear
110 
111 
112 !------------------------------------------------------------------------------
113 !:sdoc+:
114 !
115 ! NAME:
116 ! DayOfYear
117 !
118 ! PURPOSE:
119 ! Elemental function to convert input numeric (e.g. DD,MM,YYYY) date
120 ! information to a sequential day of year.
121 !
122 ! CALLING SEQUENCE:
123 ! DoY = DayOfYear ( Day, Month, Year )
124 !
125 ! INPUTS:
126 ! Day: The day-of-month.
127 ! UNITS: N/A
128 ! TYPE: INTEGER
129 ! DIMENSION: Scalar or any rank
130 ! ATTRIBUTES: INTENT(IN)
131 !
132 ! Month: The month-of-year.
133 ! UNITS: N/A
134 ! TYPE: INTEGER
135 ! DIMENSION: Same as Day input
136 ! ATTRIBUTES: INTENT(IN)
137 !
138 ! Year: The year in 4-digit format, e.g. 1997.
139 ! UNITS: N/A
140 ! TYPE: INTEGER
141 ! DIMENSION: Same as Day input
142 ! ATTRIBUTES: INTENT(IN)
143 !
144 ! FUNCTION RESULT:
145 ! DoY: Integer defining the day-of-year.
146 ! Return value is 0 for invalid input.
147 ! UNITS: N/A
148 ! TYPE: INTEGER
149 ! DIMENSION: Same as Day input
150 !:sdoc-:
151 !------------------------------------------------------------------------------
152 
153  ELEMENTAL FUNCTION dayofyear( &
154  Day , & ! Input
155  Month, & ! Input
156  Year ) & ! Input
157  result( doy )
158  ! Arguments
159  INTEGER, INTENT(IN) :: day
160  INTEGER, INTENT(IN) :: month
161  INTEGER, INTENT(IN) :: year
162  ! Function result
163  INTEGER :: doy
164  ! Local variables
165  INTEGER :: days_per_month( n_months )
166 
167  ! Set up
168  doy = 0
169  ! ...Check year and month input
170  IF ( year < 1 .OR. &
171  month < 1 .OR. &
172  month > n_months ) RETURN
173  ! ...Check the day of month
174  days_per_month = days_per_month_in_nonleap
175  IF ( isleapyear(year) ) days_per_month(2) = 29
176  IF ( day > days_per_month(month) ) RETURN
177 
178  ! Compute the day of year
179  doy = sum(days_per_month(1:month-1)) + day
180 
181  END FUNCTION dayofyear
182 
183 
184 !------------------------------------------------------------------------------
185 !:sdoc+:
186 ! NAME:
187 ! DaysInMonth
188 !
189 ! PURPOSE:
190 ! Elemental function to return the number of days in a given
191 ! month and year.
192 !
193 ! CALLING SEQUENCE:
194 ! n_Days = DaysInMonth( Month, Year )
195 !
196 ! INPUTS:
197 ! Month: The month of the year (1-12).
198 ! UNITS: N/A
199 ! TYPE: INTEGER
200 ! DIMENSION: Scalar or any rank
201 ! ATTRIBUTES: INTENT(IN)
202 !
203 ! Year: The year in 4-digit format, e.g. 1997.
204 ! UNITS: N/A
205 ! TYPE: INTEGER
206 ! DIMENSION: Same as Month input
207 ! ATTRIBUTES: INTENT(IN)
208 !
209 ! FUNCTION RESULT:
210 ! n_Days: The number of days in the month.
211 ! Return value is 0 for invalid input.
212 ! UNITS: N/A
213 ! TYPE: INTEGER
214 ! DIMENSION: Same as input
215 !:sdoc-:
216 !------------------------------------------------------------------------------
217 
218  ELEMENTAL FUNCTION daysinmonth(Month, Year) RESULT(n_Days)
219  ! Arguments
220  INTEGER, INTENT(IN) :: month
221  INTEGER, INTENT(IN) :: year
222  ! Function result
223  INTEGER :: n_days
224  ! Local variables
225  INTEGER :: days_per_month(n_months)
226 
227  ! Set up
228  n_days = 0
229  ! ...Check year and month input
230  IF ( year < 1 .OR. &
231  month < 1 .OR. &
232  month > n_months ) RETURN
233 
234  ! Assemble the days of month
235  days_per_month = days_per_month_in_nonleap
236  IF ( isleapyear(year=year) ) days_per_month(2) = 29
237 
238  ! Set the number of days
239  n_days = days_per_month(month)
240 
241  END FUNCTION daysinmonth
242 
243 
244 !------------------------------------------------------------------------------
245 !:sdoc+:
246 !
247 ! NAME:
248 ! NameOfMonth
249 !
250 ! PURPOSE:
251 ! Elemental function to return the name of the month.
252 !
253 ! CALLING SEQUENCE:
254 ! name = NameOfMonth( Month )
255 !
256 ! INPUT ARGUMENTS:
257 ! Month: The month of the year (1-12).
258 ! UNITS: N/A
259 ! TYPE: INTEGER
260 ! DIMENSION: Scalar or any rank.
261 ! ATTRIBUTES: INTENT(IN)
262 !
263 ! FUNCTION RESULT:
264 ! name: The return value is a character string containing the
265 ! name of the month.
266 ! UNITS: N/A
267 ! TYPE: CHARACTER
268 ! DIMENSION: Conformable with input Month arugment
269 !:sdoc-:
270 !------------------------------------------------------------------------------
271 
272  ELEMENTAL FUNCTION nameofmonth( Month )
273  INTEGER, INTENT(IN) :: month
274  CHARACTER(NL) :: nameofmonth
275  nameofmonth = 'Invalid'
276  IF ( month < 1 .OR. month > n_months ) RETURN
277  nameofmonth = month_name( month )
278  END FUNCTION nameofmonth
279 
280 
281 !------------------------------------------------------------------------------
282 !:sdoc+:
283 !
284 ! NAME:
285 ! DayOfWeek
286 !
287 ! PURPOSE:
288 ! Elemental function to return the name of the day of week.
289 !
290 ! NOTE:
291 ! - Only valid for Gregorian calendar.
292 ! - Since different places switched to the Gregorian calendar at
293 ! different times, this routine will only output day of week names
294 ! for dates AFTER 1918 (the year Russia adopted the Gregorian
295 ! calendar).
296 !
297 ! CALLING SEQUENCE:
298 ! name = DayOfWeek ( Day, Month, Year )
299 !
300 ! INPUTS:
301 ! Day: The day of the month.
302 ! UNITS: N/A
303 ! TYPE: INTEGER
304 ! DIMENSION: Scalar or any rank
305 ! ATTRIBUTES: INTENT(IN)
306 !
307 ! Month: The month of the year (1-12).
308 ! UNITS: N/A
309 ! TYPE: INTEGER
310 ! DIMENSION: Conformable with input Day argument.
311 ! ATTRIBUTES: INTENT(IN)
312 !
313 ! Year: The year in 4-digit format, e.g. 1997.
314 ! UNITS: N/A
315 ! TYPE: INTEGER
316 ! DIMENSION: Conformable with input Day argument.
317 ! ATTRIBUTES: INTENT(IN)
318 !
319 ! FUNCTION RESULT:
320 ! name: The return value is a character string containing the
321 ! name of the day-of-week.
322 ! UNITS: N/A
323 ! TYPE: CHARACTER
324 ! DIMENSION: Conformable with input Day argument.
325 !
326 !:sdoc-:
327 !------------------------------------------------------------------------------
328 
329  ELEMENTAL FUNCTION dayofweek( Day, Month, Year )
330  INTEGER, INTENT(IN) :: day
331  INTEGER, INTENT(IN) :: month
332  INTEGER, INTENT(IN) :: year
333  CHARACTER(NL) :: dayofweek
334  INTEGER :: i
335  dayofweek = 'Invalid'
336  i = idayofweek( day, month, year )
337  IF ( i == 0 ) RETURN
338  dayofweek = day_name(i)
339  END FUNCTION dayofweek
340 
341 
342 
343 !##############################################################################
344 !##############################################################################
345 !## ##
346 !## ## PRIVATE MODULE ROUTINES ## ##
347 !## ##
348 !##############################################################################
349 !##############################################################################
350 
351 !------------------------------------------------------------------------------
352 !
353 ! NAME:
354 ! iDayOfWeek
355 !
356 ! PURPOSE:
357 ! Elemental function to convert input numeric (e.g. DD,MM,YYYY) date
358 ! information to a day of week index, 1-7.
359 !
360 ! NOTE:
361 ! - Only valid for Gregorian calendar.
362 ! - Since different places switched to the Gregorian calendar at
363 ! different times, this routine will only output valid day of week
364 ! indices for dates AFTER 1918 (the year Russia adopted the Gregorian
365 ! calendar).
366 !
367 ! CALLING SEQUENCE:
368 ! iDoW = iDayOfWeek ( Day, Month, Year )
369 !
370 ! INPUTS:
371 ! Day: The day of the month.
372 ! UNITS: N/A
373 ! TYPE: INTEGER
374 ! DIMENSION: Scalar or any rank
375 ! ATTRIBUTES: INTENT(IN)
376 !
377 ! Month: The month of the year (1-12).
378 ! UNITS: N/A
379 ! TYPE: INTEGER
380 ! DIMENSION: Same as Day input
381 ! ATTRIBUTES: INTENT(IN)
382 !
383 ! Year: The year in 4-digit format, e.g. 1997.
384 ! UNITS: N/A
385 ! TYPE: INTEGER
386 ! DIMENSION: Same as Day input
387 ! ATTRIBUTES: INTENT(IN)
388 !
389 ! FUNCTION RESULT:
390 ! iDoW: Integer defining the day-of-week (1-7).
391 ! Return value is 0 for invalid input.
392 ! UNITS: N/A
393 ! TYPE: INTEGER
394 ! DIMENSION: Same as Day input
395 !
396 !------------------------------------------------------------------------------
397 
398  ELEMENTAL FUNCTION idayofweek( Day, Month, Year ) RESULT( iDoW )
399  ! Arguments
400  INTEGER, INTENT(IN) :: day
401  INTEGER, INTENT(IN) :: month
402  INTEGER, INTENT(IN) :: year
403  ! Function result
404  INTEGER :: idow
405  ! Local variables
406  INTEGER :: jdn
407 
408  idow = 0
409  jdn = julianday( day, month, year )
410  IF ( jdn < 0 ) RETURN
411 
412  idow = mod(jdn+1, 7) + 1
413  IF ( idow < 1 .OR. idow > 7 ) idow = 0
414 
415  END FUNCTION idayofweek
416 
417 
418 !------------------------------------------------------------------------------
419 !
420 ! NAME:
421 ! JulianDay
422 !
423 ! PURPOSE:
424 ! Elemental function to convert input numeric (e.g. DD,MM,YYYY) date
425 ! information to a Julian Day Number, which is defined as the number of
426 ! days since noon January 1, 4713 BCE.
427 !
428 ! NOTE:
429 ! - Only valid for Gregorian calendar.
430 ! - Since different places switched to the Gregorian calendar at different
431 ! times, this routine will only output valid Julian day numbers for dates
432 ! AFTER 1918 (the year Russia adopted the Gregorian calendar).
433 !
434 ! CALLING SEQUENCE:
435 ! jdn = JulianDay( Day, Month, Year )
436 !
437 ! INPUTS:
438 ! Day: The day of the month.
439 ! UNITS: N/A
440 ! TYPE: INTEGER
441 ! DIMENSION: Scalar or any rank
442 ! ATTRIBUTES: INTENT(IN)
443 !
444 ! Month: The month of the year (1-12).
445 ! UNITS: N/A
446 ! TYPE: INTEGER
447 ! DIMENSION: Same as Day input
448 ! ATTRIBUTES: INTENT(IN)
449 !
450 ! Year: The year in 4-digit format, e.g. 1997.
451 ! UNITS: N/A
452 ! TYPE: INTEGER
453 ! DIMENSION: Same as Day input
454 ! ATTRIBUTES: INTENT(IN)
455 !
456 ! FUNCTION RESULT:
457 ! jdn: Julian Day Number.
458 ! Return value is negative for invalid input.
459 ! UNITS: N/A
460 ! TYPE: INTEGER
461 ! DIMENSION: Same as Day input
462 !
463 ! REFERENCES:
464 ! - http://en.wikipedia.org/wiki/Julian_day
465 ! - http://www.cs.utsa.edu/~cs1063/projects/Spring2011/Project1/jdn-explanation.html
466 !
467 !------------------------------------------------------------------------------
468 
469  ELEMENTAL FUNCTION julianday( Day, Month, Year ) RESULT( jdn )
470  ! Arguments
471  INTEGER, INTENT(IN) :: day
472  INTEGER, INTENT(IN) :: month
473  INTEGER, INTENT(IN) :: year
474  ! Function result
475  INTEGER :: jdn
476  ! Local variables
477  INTEGER :: m, y, a
478 
479  jdn = -1
480  IF ( year <= 1918 ) RETURN
481 
482  ! Compute the number of years and months since March 1, 4801 BCE
483  a = (14 - month)/12 ! 1 for Jan, 2 for Feb, 0 for other months.
484  y = year + 4800 - a ! Add 4800 to start counting from -4800.
485  m = month + (12*a) - 3 ! Pretend the year begins in March and ends in Feb.
486 
487  jdn = day + &
488  (153*m + 2)/5 + & ! Number of days in the previous months
489  (365*y) + & ! Duh.
490  (y/4) - (y/100) + (y/400) - & ! Number of leap years since -4800
491  32045 ! Ensure result is 0 for Jan 1, 4713 BCE.
492 
493  END FUNCTION julianday
494 
495 END MODULE date_utility
elemental logical function, public isleapyear(Year)
integer, parameter nl
character(*), dimension(n_days), parameter, public day_name
integer, parameter, public n_days
integer, dimension(n_months), parameter, public days_per_month_in_nonleap
elemental character(nl) function, public dayofweek(Day, Month, Year)
integer, parameter, public n_months
elemental integer function, public dayofyear(Day, Month, Year)
elemental integer function julianday(Day, Month, Year)
elemental character(nl) function, public nameofmonth(Month)
elemental integer function, public daysinmonth(Month, Year)
character(*), parameter module_version_id
character(*), dimension(n_months), parameter, public month_name
elemental integer function idayofweek(Day, Month, Year)