0.6.2-dev0
FORCES
FORtran lib for Comp. Env. Sys.
Loading...
Searching...
No Matches
mo_julian.f90
Go to the documentation of this file.
1!> \file mo_julian.f90
2!> \brief \copybrief mo_julian
3!> \details \copydetails mo_julian
4
5!> \brief Julian date conversion routines
6!> \details Julian date to and from day, month, year, and also from day, month, year, hour, minute, and second.
7!! Also convience routines for Julian dates of IMSL are provided.
8!! \note Julian day definition starts at noon of the 1st January 4713 BC.\n
9!! Here, the astronomical definition is used,
10!! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
11!! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
12!! \n
13!! julday and caldat start at midnight of the 1st January 4713 BC.
14!! So date2dec and julday as well as dec2date and caldat are shifted by half a day.\n
15!! Use date2dec with dec2date together for fractional Julian dates
16!! and use julday with caldat together for integer Julian days.
17!> \changelog
18!! - Matthias Cuntz, Dec 2011
19!! - Matthias Cuntz, Jan 2013
20!! - added date2dec and dec2date
21!! - Matthias Cuntz, May 2014
22!! - changed to new algorithm with astronomical units removed numerical recipes
23!! - David Schaefer, Oct 2015
24!! - addded 360 day calendar procedures
25!! - David Schaefer, Jan 2016
26!! - addded 365 day calendar procedures
27!! - David Schaefer, Feb 2016
28!! - implemented wrapper function and the module calendar state
29!> \author Matthias Cuntz
30!> \date Dec 2011
31!> \copyright Copyright 2005-\today, the CHS Developers, Sabine Attinger: All rights reserved.
32!! FORCES is released under the LGPLv3+ license \license_note
34
35 USE mo_kind, ONLY : i4, i8, dp
36
37 IMPLICIT NONE
38
39 PRIVATE
40
41 PUBLIC :: caldat
42 PUBLIC :: date2dec ! Fractional Julian day from day, month, year, hour, minute, and second
43 PUBLIC :: dec2date ! Day, month, year, hour, minute, and second from fractional Julian day
44 PUBLIC :: julday ! Julian day from day, month and year
45 PUBLIC :: ndays ! IMSL Julian day from day, month and year
46 PUBLIC :: ndyin ! Day, month and year from IMSL Julian day
47 public :: setcalendar
48 public :: caldatjulian
49
50 integer(i4), save, private :: calendar = 1
51
52 ! ------------------------------------------------------------------
53
54 !> \brief Set module private variable calendar
55
56 !> \details
57 !! Set which type of calendar to use.
58 !!
59 !! \b Example
60 !!
61 !! Set to Julian calendar.
62 !! \code{.f90}
63 !! call caldat("julian")
64 !! call caldat(1)
65 !! \endcode
66
67 !> \param[in] "character(len=*)/integer(i4) :: selector" {"julian"/1|"365day"/2|"360day"/3}
68
69 !> \author David Schaefer
70 !> \date Jan 2015
71
72 interface setcalendar
73 module procedure setcalendarinteger, setcalendarstring
74 end interface setcalendar
75
76CONTAINS
77
78 subroutine setcalendarstring(selector)
79 character(*), intent(in) :: selector
80
81 select case(selector)
82 case("julian")
83 call setcalendarinteger(1)
84 case("365day")
85 call setcalendarinteger(2)
86 case("360day")
87 call setcalendarinteger(3)
88 case default
89 print*, "Unknown selector! Select on of 'julian', '365day', '360day'."
90 stop 1
91 end select
92 end subroutine setcalendarstring
93
94
95 subroutine setcalendarinteger(selector)
96 integer(i4), intent(in) :: selector
97
98 if ((selector .lt. 1) .or. (selector .gt. 3)) then
99 print*, "Unknown selector! Select on of 1, 2, 3."
100 stop 1
101 end if
102 calendar = selector
103
104 end subroutine setcalendarinteger
105
106 ! ------------------------------------------------------------------
107
108 !> \brief Select a calendar
109
110 !> \details Returns a valid calendar index, based on the given optional argument
111 !! and/or the module global private variable calendar. If an invalid selector is passed,
112 !! its value is ignored and the global calendar value retuned instead.
113 !!
114 !! \b Example
115 !!
116 !! Returns a valid index which is 3
117 !! \code{.f90}
118 !! idx = selectCalendar(3)
119 !! \endcode
120
121 !> \param[in] "integer(i4), optional :: selector" Calendar selector {1|2|3}
122
123 !> \author David Schaefer
124 !> \date Jan 2015
125 pure function selectcalendar(selector)
126 integer(i4), intent(in), optional :: selector
127 integer(i4) :: selectcalendar
128
129 selectcalendar = calendar
130 if (present(selector)) then
131 if ((selector .gt. 0) .and. (selector .lt. 4)) then
132 selectcalendar = selector
133 end if
134 end if
135
136 end function selectcalendar
137
138 ! ------------------------------------------------------------------
139
140 !> \brief Day, month and year from Julian day in the current or given calendar
141
142 !> \details
143 !! Wrapper around the calendar specific caldat procedures.
144 !! Inverse of the function julday. Here julian is input as a Julian Day Number,
145 !! and the routine outputs d0d, mm, and yy as the day, month, and year on which the specified
146 !! Julian Day started at noon.\n
147 !!
148 !! The zeroth Julian Day depends on the called procedure. See their documentation for details.
149 !!
150 !! \b Example
151 !!
152 !! Converts julday to dd, mm, yy format
153 !! \code{.f90}
154 !! call caldat(julday, dd, mm, yy)
155 !! \endcode
156
157 !> \param[in] "integer(i4) :: julday" Julian day
158 !> \param[out] "integer(i4) :: dd" Day in month of Julian day
159 !> \param[out] "integer(i4) :: mm" Month in year of Julian day
160 !> \param[out] "integer(i4) :: yy" Year of Julian day
161 !> \param[in] "integer(i4) :: calendar" The calendar to use, the global calendar
162 !! will be used by default
163
164 !> \author David Schaefer
165 !> \date Jan 2015
166 elemental subroutine caldat(julian, dd, mm, yy, calendar)
167
168 implicit none
169
170 integer(i4), intent(in) :: julian
171 integer(i4), intent(out) :: dd, mm, yy
172 integer(i4), intent(in), optional :: calendar
173
174 select case(selectcalendar(calendar))
175 case(1)
176 call caldatjulian(julian, dd, mm, yy)
177 case(2)
178 call caldat365(julian, dd, mm, yy)
179 case(3)
180 call caldat360(julian, dd, mm, yy)
181 end select
182
183 end subroutine caldat
184
185 ! ------------------------------------------------------------------
186
187 !> \brief Day, month, year, hour, minute, and second from fractional Julian day in the current or given calendar
188
189 !> \details Wrapper around the calendar specific dec2date procedures.
190 !! Inverse of the function date2dec. Here dec2date is input as a fractional Julian Day.
191 !! The routine outputs dd, mm, yy, hh, nn, ss as the day, month, year, hour, minute, and second
192 !! on which the specified Julian Day started at noon.
193 !!
194 !! The zeroth Julian Day depends on the called procedure. See their documentation for details.
195 !!
196 !! \b Example
197 !!
198 !! Takes in fraction julian date fJulian to covert to dd, mm, yy, hh, nn, ss
199 !! \code{.f90}
200 !! call dec2date(fJulian, dd, mm, yy, hh, nn, ss)
201 !! \endcode
202
203 !> \param[in] "real(dp) :: fJulian" fractional Julian day
204 !> \param[in] "integer(i4), optional :: calendar" The calendar to use, the global calendar
205 !! will be used by default
206 !> \param[out] "integer(i4), optional :: dd" Day in month of Julian day
207 !> \param[out] "integer(i4), optional :: mm" Month in year of Julian day
208 !> \param[out] "integer(i4), optional :: yy" Year of Julian day
209 !> \param[out] "integer(i4), optional :: hh" Hour of Julian day
210 !> \param[out] "integer(i4), optional :: nn" Minute in hour of Julian day
211 !> \param[out] "integer(i4), optional :: ss" Second in minute of hour of Julian day
212
213
214 ! HISTORY
215 !> \author David Schaefer
216 !> \date Jan 2015
217 elemental subroutine dec2date(julian, dd, mm, yy, hh, nn, ss, calendar)
218
219 implicit none
220
221 real(dp), intent(in) :: julian
222 integer(i4), intent(out), optional :: dd, mm, yy, hh, nn, ss
223 integer(i4), intent(in), optional :: calendar
224
225 select case(selectcalendar(calendar))
226 case(1)
227 call dec2datejulian(julian, dd, mm, yy, hh, nn, ss)
228 case(2)
229 call dec2date365(julian, dd, mm, yy, hh, nn, ss)
230 case(3)
231 call dec2date360(julian, dd, mm, yy, hh, nn, ss)
232 end select
233
234 end subroutine dec2date
235
236 ! ------------------------------------------------------------------
237
238 !> \brief Fractional Julian day from day, month, year, hour, minute, second in the current calendar
239
240 !> \details Wrapper around the calendar specific date2dec procedures.
241 !! In this routine date2dec returns the fractional Julian Day that begins at noon
242 !! of the calendar date specified by month mm, day dd, and year yy, all integer variables.
243 !!
244 !! The zeroth Julian Day depends on the called procedure. See their documentation for details.
245 !!
246 !! \b Example
247 !!
248 !! Take dd, mm, yy, hh, nn, ss to fractional Julian date
249 !! \code{.f90}
250 !! date2dec = date2dec(dd, mm, yy, hh, nn, ss)
251 !! \endcode
252
253 !> \param[in] "integer(i4), optional :: dd" Day in month of Julian day (default: 1)
254 !> \param[in] "integer(i4), optional :: mm" Month in year of Julian day (default: 1)
255 !> \param[in] "integer(i4), optional :: yy" Year of Julian day (default: 1)
256 !> \param[in] "integer(i4), optional :: hh" Hours of Julian day (default: 0)
257 !> \param[in] "integer(i4), optional :: nn" Minutes of hour of Julian day (default: 0)
258 !> \param[in] "integer(i4), optional :: ss" Secondes of minute of hour of Julian day (default: 0)
259 !> \param[in] "integer(i4), optional :: calendar" The calendar to use, the global calendar
260 !! will be used by default
261 !> \retval "real(dp) :: date2dec" Fractional Julian day
262
263 !> \author David Schaefer
264 !> \date Jan 2015
265 elemental function date2dec(dd, mm, yy, hh, nn, ss, calendar)
266
267 implicit none
268
269 integer(i4), intent(in), optional :: dd, mm, yy
270 integer(i4), intent(in), optional :: hh, nn, ss
271 integer(i4), intent(in), optional :: calendar
272 real(dp) :: date2dec
273
274 select case(selectcalendar(calendar))
275 case(1)
276 date2dec = date2decjulian(dd, mm, yy, hh, nn, ss)
277 case(2)
278 date2dec = date2dec365(dd, mm, yy, hh, nn, ss)
279 case(3)
280 date2dec = date2dec360(dd, mm, yy, hh, nn, ss)
281 end select
282
283 end function date2dec
284
285 ! ------------------------------------------------------------------
286
287 !> \brief Julian day from day, month and year in the current or given calendar
288
289 !> \details Wrapper around the calendar specific julday procedures.
290 !! In this routine julday returns the Julian Day Number that begins at noon of the calendar
291 !! date specified by month mm, day dd, and year yy, all integer variables.
292 !!
293 !! The zeroth Julian Day depends on the called procedure. See their documentation for details.
294 !!
295 !! \b Example
296 !!
297 !! Take dd, mm, yy, hh, nn, ss to Julian date
298 !! \code{.f90}
299 !! date2dec = date2dec(dd, mm, yy)
300 !! \endcode
301
302 !> \param[in] "integer(i4) :: dd" Day in month of Julian day
303 !> \param[in] "integer(i4) :: mm" Month in year of Julian day
304 !> \param[in] "integer(i4) :: yy" Year of Julian day
305 !> \param[in] "integer(i4), optional :: calendar" The calendar to use, the global calendar
306 !! will be used by default
307
308 !> \retval "integer(i4) :: julian" Julian day
309
310 !> \author David Schaefer
311 !> \date Jan 2015
312 elemental function julday(dd, mm, yy, calendar)
313
314 implicit none
315
316 integer(i4), intent(in) :: dd, mm, yy
317 integer(i4), intent(in), optional :: calendar
318 integer(i4) :: julday
319
320 select case(selectcalendar(calendar))
321 case(1)
322 julday = juldayjulian(dd, mm, yy)
323 case(2)
324 julday = julday365(dd, mm, yy)
325 case(3)
326 julday = julday360(dd, mm, yy)
327 end select
328
329 end function julday
330
331 ! ------------------------------------------------------------------
332
333 !> \brief Day, month and year from Julian day
334
335 !> \details Inverse of the function juldayJulian. Here julian is input as a Julian Day Number,
336 !! and the routine outputs id, mm, and yy as the day, month, and year on which the specified
337 !! Julian Day started at noon.
338 !!
339 !! The zeroth Julian Day is 01.01.-4712, i.e. the 1st January 4713 BC.
340 !!
341 !! Julian day definition starts at 1st January 4713 BC.\n
342 !! Here, the astronomical definition is used,
343 !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
344 !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
345 !!
346 !! \b Example
347 !!
348 !! \code{.f90}
349 !! 2415021 is 01.01.1900
350 !! call caldatJulian(2415021, dd, mm, yy)
351 !! \endcode
352 !!
353 !! \b Literature
354 !! 1. http://de.wikipedia.org/wiki/Julianisches_Datum
355 !! which is different to the english Wiki\n
356 !! 2. http://en.wikipedia.org/wiki/Julian_day
357 !! It is essentially the same as Numerical Recipes but uses astronomical instead of historical units.
358
359
360 !> \param[in] "integer(i4) :: Julday" Julian day
361 !> \param[out] "integer(i4) :: dd" Day in month of Julian day
362 !> \param[out] "integer(i4) :: mm" Month in year of Julian day
363 !> \param[out] "integer(i4) :: yy" Year of Julian day
364
365 !> \note Julian day definition starts at noon of the 1st January 4713 BC.\n
366 !! Here, the astronomical definition is used,
367 !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
368 !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
369 !!
370 !! julday and caldat start at midnight of the 1st January 4713 BC.
371 !! So date2decJulian and juldayJulian as well as dec2dateJulian and caldatJulian are shifted by half a day.\n
372 !! Use date2decJulian with dec2dateJulian together for fractional Julian dates
373 !! and use juldayJulian with caldatJulian together for integer Julian days.
374
375 !> \author Matthias Cuntz
376 !> \date Dec 2011
377 !! - modified julday from Numerical Recipes
378 !> \date May 2014
379 !! - changed to new algorithm with astronomical units
380 !! - removed numerical recipes
381
382 !> \author David Schaefer
383 !> \date Jan 2016
384 !! - renamed procodure
385 ELEMENTAL SUBROUTINE caldatjulian(julian, dd, mm, yy)
386
387 IMPLICIT NONE
388
389 INTEGER(i4), INTENT(IN) :: julian
390 INTEGER(i4), INTENT(OUT) :: dd, mm, yy
391
392 INTEGER(i8) :: a, b, c, d, e, g
393 INTEGER(i4), PARAMETER :: igreg = 2299161_i4
394
395 if (julian < igreg) then
396 a = int(julian, i8) ! julian
397 else
398 g = int((real(julian, dp) - 1867216.25_dp) / 36524.25_dp, i8) ! gregorian
399 a = julian + 1_i8 + g - g / 4_i8
400 end if
401
402 b = a + 1524_i8
403 c = int((real(b, dp) - 122.1_dp) / 365.25_dp, i8)
404 d = int(365.25_dp * real(c, dp), i8)
405 e = int(real(b - d, dp) / 30.6001_dp, i8)
406
407 dd = int(b - d - int(30.6001_dp * real(e, dp), i8), i4)
408
409 if (e<14_i8) then
410 mm = int(e - 1_i8, i4)
411 else
412 mm = int(e - 13_i8, i4)
413 end if
414
415 if (mm > 2) then
416 yy = int(c - 4716_i8, i4)
417 else
418 yy = int(c - 4715_i8, i4)
419 end if
420
421 END SUBROUTINE caldatjulian
422
423
424 ! ------------------------------------------------------------------
425
426 !> \brief Fractional Julian day from day, month, year, hour, minute, second
427
428 !> \details In this routine date2decJulian returns the fractional Julian Day that begins at noon
429 !! of the calendar date specified by month mm, day dd, and year yy, all integer variables.
430 !!
431 !! The zeroth Julian Day is 01.01.-4712 at noon, i.e. the 1st January 4713 BC 12:00:00 h.
432 !!
433 !! Julian day definition starts at noon of the 1st January 4713 BC.\n
434 !! Here, the astronomical definition is used,
435 !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
436 !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
437 !!
438 !! \b Example
439 !!
440 !! 2415020.5 is 01.01.1900 00:00
441 !! \code{.f90}
442 !! julian = date2decJulian(01,01,1990)
443 !! \endcode
444 !! \code{.f90}
445 !! 2415021.0 is 01.01.1900 12:00
446 !! \endcode
447 !! julian = date2decJulian(01,01,1990,12,00)
448 !!
449 !! \b Literature
450 !!
451 !! 1. http://de.wikipedia.org/wiki/Julianisches_Datum
452 !! which is different to the english Wiki \n
453 !! 2. http://en.wikipedia.org/wiki/Julian_day
454 !! It is essentially the same as Numerical Recipes but uses astronomical instead of historical units.
455 !! Numerical regulation of fractions is after \n
456 !! 3. IDL routine julday.pro. Copyright (c) 1988-2011, ITT Visual Information Solutions.
457
458 !> \param[in] "integer(i4), optional :: dd" Day in month of Julian day (default: 1)
459 !> \param[in] "integer(i4), optional :: mm" Month in year of Julian day (default: 1)
460 !> \param[in] "integer(i4), optional :: yy" Year of Julian day (default: 1)
461 !> \param[in] "integer(i4), optional :: hh" Hours of Julian day (default: 0)
462 !> \param[in] "integer(i4), optional :: nn" Minutes of hour of Julian day (default: 0)
463 !> \param[in] "integer(i4), optional :: ss" Secondes of minute of hour of Julian day (default: 0)
464 !> \retval "real(dp) :: date2dec" Fractional Julian day
465
466 !> \note Julian day definition starts at noon of the 1st January 4713 BC.\n
467 !! Here, the astronomical definition is used,
468 !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
469 !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
470 !!
471 !! juldayJulian and caldatJulian start at midnight of the 1st January 4713 BC.
472 !! So date2decJulian and juldayJulian as well as dec2dateJulian and caldatJulian are shifted by half a day.\n
473 !! Use date2decJulian with dec2dateJulian together for fractional Julian dates
474 !! and use juldayJulian with caldatJulian together for integer Julian days.
475
476 !> \author Matthias Cuntz
477 !> \date Jan 2013
478 !> \date May 2014
479 !! - changed to new algorithm with astronomical units
480 !> - removed numerical recipes
481
482 !> \author David Schaefer
483 !> \date Jan 2016
484 !! - renamed procodure
485
486 ELEMENTAL FUNCTION date2decjulian(dd, mm, yy, hh, nn, ss)
487
488 IMPLICIT NONE
489
490 INTEGER(i4), INTENT(IN), OPTIONAL :: dd, mm, yy
491 INTEGER(i4), INTENT(IN), OPTIONAL :: hh, nn, ss
492 REAL(dp) :: date2decjulian
493
494 INTEGER(i4), PARAMETER :: igreg2 = 15 + 31 * (10 + 12 * 1582)
495 INTEGER(i4), PARAMETER :: igreg1 = 4 + 31 * (10 + 12 * 1582)
496 INTEGER(i4) :: idd, imm, iyy
497 REAL(dp) :: ihh, inn, iss
498 INTEGER(i8) :: jm, jy
499 REAL(dp) :: jd, h, eps
500 INTEGER(i8) :: a, b
501
502 ! Presets
503 idd = 1
504 if (present(dd)) idd = dd
505 imm = 1
506 if (present(mm)) imm = mm
507 iyy = 1
508 if (present(yy)) iyy = yy
509 ihh = 0.0_dp
510 if (present(hh)) ihh = real(hh, dp)
511 inn = 0.0_dp
512 if (present(nn)) inn = real(nn, dp)
513 iss = 0.0_dp
514 if (present(ss)) iss = real(ss, dp)
515
516 if (imm > 2) then
517 jm = int(imm, i8)
518 jy = int(iyy, i8)
519 else
520 jm = int(imm + 12, i8)
521 jy = int(iyy - 1, i8)
522 end if
523
524 jd = real(idd, dp)
525
526 h = ihh / 24._dp + inn / 1440._dp + iss / 86400._dp
527
528 if (dd + 31 * (mm + 12 * yy) >= igreg2) then ! gregorian
529 a = jy / 100_i8
530 b = 2_i8 - a + a / 4_i8
531 else if (dd + 31 * (mm + 12 * yy) <= igreg1) then ! julian
532 b = 0_i8
533 ! else
534 ! stop 'No Gregorian dates between 04.10.1582 and 15.10.1582'
535 end if
536
537 ! Fractional Julian day starts at noon
538 date2decjulian = floor(365.25_dp * real(jy + 4716_i8, dp)) + &
539 floor(30.6001_dp * real(jm + 1_i8, dp)) + jd + h + real(b, dp) - 1524.5_dp
540
541 ! Add a small offset (proportional to julian date) for correct re-conversion.
542 eps = epsilon(1.0_dp)
543 eps = max(eps * abs(date2decjulian), eps)
545
546 END FUNCTION date2decjulian
547
548 ! ------------------------------------------------------------------
549
550 !> \brief Day, month, year, hour, minute, and second from fractional Julian day
551
552 !> \details Inverse of the function date2decJulian. Here dec2dateJulian is input as a fractional Julian Day,
553 !! which starts at noon of the 1st January 4713 BC, i.e. 01.01.-4712.
554 !! The routine outputs dd, mm, yy, hh, nn, ss as the day, month, year, hour, minute, and second
555 !! on which the specified Julian Day started at noon.
556 !!
557 !! The zeroth Julian Day is 01.01.-4712 at noon, i.e. the 1st January 4713 BC at noon.
558 !!
559 !! Julian day definition starts at 1st January 4713 BC.\n
560 !! Here, the astronomical definition is used,
561 !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
562 !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
563 !!
564 !! \b Example
565 !!
566 !! 2415020.5 is 01.01.1900 00:00
567 !! \code{.f90}
568 !! call caldatJulian(2415020.5, dd, mm, yy, hh, nn)
569 !! \endcode
570 !! 2415021.0 is 01.01.1900 12:00
571 !! \code{.f90}
572 !! call caldatJulian(2415021., dd, mm, yy, hh, nn, ss)
573 !! \endcode
574 !!
575 !! \b Literature
576 !!
577 !! 1. http://de.wikipedia.org/wiki/Julianisches_Datum
578 !! which is different to the english Wiki\n
579 !! 2. http://en.wikipedia.org/wiki/Julian_day
580 !! It is essentially the same as Numerical Recipes but uses astronomical instead of historical units.
581 !! Here the sometimes 60 sec as output are corrected at the end.
582
583 !> \param[in] "real(dp) :: fJulian" fractional Julian day
584 !> \param[out] "integer(i4), optional :: dd" Day in month of Julian day
585 !> \param[out] "integer(i4), optional :: mm" Month in year of Julian day
586 !> \param[out] "integer(i4), optional :: yy" Year of Julian day
587 !> \param[out] "integer(i4), optional :: hh" Hour of Julian day
588 !> \param[out] "integer(i4), optional :: nn" Minute in hour of Julian day
589 !> \param[out] "integer(i4), optional :: ss" Second in minute of hour of Julian day
590
591 !> \note Julian day definition starts at noon of the 1st January 4713 BC.\n
592 !! Here, the astronomical definition is used,
593 !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
594 !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
595 !!
596 !! juldayJulian and caldatJulian start at midnight of the 1st January 4713 BC.
597 !! So date2decJulian and juldayJulian as well as dec2dateJulian and caldatJulian are shifted by half a day.\n
598 !! Use date2decJulian with dec2dateJulian together for fractional Julian dates
599 !! and use juldayJulian with caldatJulian together for integer Julian days.
600
601 !> \author Matthias Cuntz
602 !> \date Jan 2013
603 !> \date May 2014
604 !! - changed to new algorithm with astronomical units
605 !> - removed numerical recipes
606
607 !> \author David Schaefer
608 !> \date Jan 2016
609 !! - renamed procodure
610 ELEMENTAL SUBROUTINE dec2datejulian(julian, dd, mm, yy, hh, nn, ss)
611
612 IMPLICIT NONE
613
614 REAL(dp), INTENT(IN) :: julian
615 INTEGER(i4), INTENT(OUT), OPTIONAL :: dd, mm, yy
616 INTEGER(i4), INTENT(OUT), OPTIONAL :: hh, nn, ss
617
618 INTEGER(i4) :: day, month, year, hour, minute, second
619 REAL(dp) :: fraction
620 ! REAL(dp) :: eps
621
622 INTEGER(i8) :: a, b, c, d, e, g, z
623 INTEGER(i4), PARAMETER :: igreg = 2299161_i4
624
625 z = int(julian + 0.5, i8)
626
627 if (z < igreg) then
628 a = z ! julian
629 else
630 g = int((real(z, dp) - 1867216.25_dp) / 36524.25_dp, i8) ! gregorian
631 a = z + 1_i8 + g - g / 4_i8
632 end if
633
634 b = a + 1524_i8
635 c = int((real(b, dp) - 122.1_dp) / 365.25_dp, i8)
636 d = int(365.25_dp * real(c, dp), i8)
637 e = int(real(b - d, dp) / 30.6001_dp, i8)
638
639 day = int(b - d - int(30.6001_dp * real(e, dp), i8), i4)
640
641 if (e<14_i8) then
642 month = int(e - 1_i8, i4)
643 else
644 month = int(e - 13_i8, i4)
645 end if
646
647 if (month > 2) then
648 year = int(c - 4716_i8, i4)
649 else
650 year = int(c - 4715_i8, i4)
651 end if
652
653 ! ! Fractional part
654 ! eps = 1e-12_dp ! ~ 5000*epsilon(1.0_dp)
655 ! eps = max(eps * abs(real(Z,dp)), eps)
656 ! fraction = julian + 0.5_dp - real(Z,dp)
657 ! hour = min(max(floor(fraction * 24.0_dp + eps), 0), 23)
658 ! fraction = fraction - real(hour,dp)/24.0_dp
659 ! minute = min(max(floor(fraction*1440.0_dp + eps), 0), 59)
660 ! second = max(nint((fraction - real(minute,dp)/1440.0_dp)*86400.0_dp), 0)
661
662 ! Fractional part
663 fraction = julian + 0.5_dp - real(z, dp)
664 hour = min(max(floor(fraction * 24.0_dp), 0), 23)
665 fraction = fraction - real(hour, dp) / 24.0_dp
666 minute = min(max(floor(fraction * 1440.0_dp), 0), 59)
667 second = max(nint((fraction - real(minute, dp) / 1440.0_dp) * 86400.0_dp), 0)
668
669 ! If seconds==60
670 if (second==60) then
671 second = 0
672 minute = minute + 1
673 if (minute==60) then
674 minute = 0
675 hour = hour + 1
676 if (hour==24) then
677 hour = 0
678 call caldat(julday(day, month, year) + 1, day, month, year)
679 end if
680 end if
681 end if
682
683 if (present(dd)) dd = day
684 if (present(mm)) mm = month
685 if (present(yy)) yy = year
686 if (present(hh)) hh = hour
687 if (present(nn)) nn = minute
688 if (present(ss)) ss = second
689
690 END SUBROUTINE dec2datejulian
691
692 ! ------------------------------------------------------------------
693
694 !> \brief Julian day from day, month and year
695
696 !> \details In this routine juldayJulian returns the Julian Day Number that begins at noon of the calendar
697 !! date specified by month mm, day dd, and year yy, all integer variables.
698 !!
699 !! The zeroth Julian Day is 01.01.-4712 at noon, i.e. the 1st January 4713 BC 12:00:00 h.
700 !!
701 !! Julian day definition starts at noon of the 1st January 4713 BC.\n
702 !! Here, the astronomical definition is used,
703 !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
704 !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
705 !!
706 !! \b Example
707 !!
708 !! 2415021 is 01.01.1900 and 2440588 is 01.01.1970
709 !! \code{.f90}
710 !! julian = juldayJulian(01,01,1990)
711 !! \endcode
712 !! See also example in test directory
713 !!
714 !! \b Literature
715 !! 1. http://de.wikipedia.org/wiki/Julianisches_Datum
716 !! which is different to the english Wiki \n
717 !! 2. http://en.wikipedia.org/wiki/Julian_day
718 !! It is essentially the same as Numerical Recipes but uses astronomical instead of historical units.
719
720 !> \param[in] "integer(i4) :: dd" Day in month of Julian day
721 !> \param[in] "integer(i4) :: mm" Month in year of Julian day
722 !> \param[in] "integer(i4) :: yy" Year of Julian day
723 !> \retval "integer(i4) :: julian" Julian day
724
725 !> \note Julian day definition starts at noon of the 1st January 4713 BC.\n
726 !! Here, the astronomical definition is used,
727 !! i.e. the year 1 BC (historic) is counted as 0 (astronomic), 2 BC is -1, etc.\n
728 !! This means that Julian day definition starts as 01.01.-4712 in astronomical units.\n
729 !!
730 !! juldayJulian and caldatJulian start at midnight of the 1st January 4713 BC.
731 !! So date2decJulian and juldayJulian as well as dec2dateJulian and caldatJulian are shifted by half a day.\n
732 !! Use date2decJulian with dec2dateJulian together for fractional Julian dates
733 !! and use juldayJulian with caldatJulian together for integer Julian days.
734
735 !> \author Matthias Cuntz
736 !> \date Dec 2011
737 !! - modified julday from Numerical Recipes
738 !> \date May 2014
739 !! - changed to new algorithm with astronomical units
740 !! - removed numerical recipes
741 !> \author David Schaefer
742 !> \date Jan 2016
743 !! - renamed procodure
744 ELEMENTAL FUNCTION juldayjulian(dd, mm, yy)
745
746 IMPLICIT NONE
747
748 INTEGER(i4), INTENT(IN) :: dd, mm, yy
749 INTEGER(i4) :: juldayjulian
750
751 INTEGER(i4), PARAMETER :: igreg2 = 15 + 31 * (10 + 12 * 1582)
752 INTEGER(i4), PARAMETER :: igreg1 = 4 + 31 * (10 + 12 * 1582)
753 INTEGER(i8) :: jd, jm, jy
754 INTEGER(i8) :: a, b
755
756 if (mm > 2) then
757 jm = int(mm, i8)
758 jy = int(yy, i8)
759 else
760 jm = int(mm + 12, i8)
761 jy = int(yy - 1, i8)
762 end if
763
764 jd = int(dd, i8)
765
766 if (dd + 31 * (mm + 12 * yy) >= igreg2) then ! gregorian
767 a = jy / 100_i8
768 b = 2_i8 - a + a / 4_i8
769 else if (dd + 31 * (mm + 12 * yy) <= igreg1) then ! julian
770 b = 0_i8
771 ! else
772 ! stop 'No Gregorian dates between 04.10.1582 and 15.10.1582'
773 end if
774
775 ! add 0.5 to Wiki formula because formula was for fractional day
776 ! juldayJulian = int(365.25_dp*real(jy+4716_i8,dp) + real(int(30.6001*real(jm+1_i8,dp),i8),dp) + real(jd+B,dp) - 1524.5_dp, i4)
777 juldayjulian = int(365.25_dp * real(jy + 4716_i8, dp) + real(int(30.6001 * real(jm + 1_i8, dp), i8), dp) &
778 + real(jd + b, dp) - 1524.5_dp + 0.5_dp, i4)
779
780 END FUNCTION juldayjulian
781
782 ! ------------------------------------------------------------------
783
784 !> \brief IMSL Julian day from day, month and year
785
786 !> \details In this routine ndays returns the IMSL Julian Day Number. Julian days begin at noon of the calendar
787 !! date specified by month mm, day dd, and year yy, all integer variables. IMSL treats 01.01.1900
788 !! as a reference and assigns a Julian day 0 to it.
789 !!
790 !! ndays = julday(dd,mm,yy) - julday(01,01,1900)
791 !!
792 !! \b Example
793 !!
794 !! 0 is 01.01.1900
795 !! \code{.f90}
796 !! julian = ndays(01,01,1990)
797 !! \endcode
798 !! See also example in test directory
799
800 !> \param[in] "integer(i4) :: dd" Day in month of IMSL Julian day
801 !> \param[in] "integer(i4) :: mm" Month in year of IMSL Julian day
802 !> \param[in] "integer(i4) :: yy" Year of IMSL Julian day
803 !> \retval "integer(i4) :: julian" IMSL Julian day, i.e. days before or after 01.01.1900
804
805 !> \author Matthias Cuntz
806 !> \date Dec 2011
807
808 ELEMENTAL FUNCTION ndays(dd, mm, yy)
809
810 IMPLICIT NONE
811
812 INTEGER(i4), INTENT(IN) :: dd, mm, yy
813 INTEGER(i4) :: ndays
814
815 INTEGER(i4), PARAMETER :: imslday = 2415021_i4
816
817 ndays = julday(dd, mm, yy) - imslday
818
819 END FUNCTION ndays
820
821 ! ------------------------------------------------------------------
822
823 !> \brief Day, month and year from IMSL Julian day
824
825 !> \details Inverse of the function ndys. Here ISML Julian is input as a Julian Day Number
826 !! minus the Julian Day Number of 01.01.1900, and the routine outputs id, mm, and yy
827 !! as the day, month, and year on which the specified Julian Day started at noon.
828 !!
829 !! ndyin is caldat(IMSLJulian + 2415021, dd, mm, yy)
830 !!
831 !! \b Example
832 !!
833 !! 0 is 01.01.1900
834 !! \code{.f90}
835 !! call ndyin(0,dd,mm,yy)
836 !! \endcode
837 !! See also example in test directory
838
839 !> \param[in] "integer(i4) :: julian" IMSL Julian day, i.e. days before or after 01.01.1900
840 !> \param[out] "integer(i4) :: dd" Day in month of IMSL Julian day
841 !> \param[out] "integer(i4) :: mm" Month in year of IMSL Julian day
842 !> \param[out] "integer(i4) :: yy" Year of IMSL Julian day
843
844 !> \author Matthias Cuntz
845 !> \date Dec 2011
846
847 ELEMENTAL SUBROUTINE ndyin(julian, dd, mm, yy)
848
849 IMPLICIT NONE
850
851 INTEGER(i4), INTENT(IN) :: julian
852 INTEGER(i4), INTENT(OUT) :: dd, mm, yy
853
854 INTEGER(i4), PARAMETER :: imslday = 2415021_i4
855
856 call caldat(julian + imslday, dd, mm, yy)
857
858 END SUBROUTINE ndyin
859
860 ! ------------------------------------------------------------------
861
862 !> \brief Day, month and year from Julian day in a 360 day calendar
863
864 !> \details Inverse of the function julday360. Here julian is input as a Julian Day Number,
865 !! and the routine outputs dd, mm, and yy as the day, month, and year on which the specified
866 !! Julian Day started at noon.
867 !!
868 !! The zeroth Julian Day here is 01.01.0000
869 !!
870 !! \b Example
871 !!
872 !! \code{.f90}
873 !! call caldat360(julday, dd, mm, yy)
874 !! \endcode
875
876 !> \param[in] "integer(i4) :: julday" Julian day
877 !> \param[out] "integer(i4) :: dd" Day in month of Julian day
878 !> \param[out] "integer(i4) :: mm" Month in year of Julian day
879 !> \param[out] "integer(i4) :: yy" Year of Julian day
880
881 !> \author David Schaefer
882 !> \date Oct 2015
883 elemental subroutine caldat360(julian, dd, mm, yy)
884
885 implicit none
886
887 integer(i4), intent(in) :: julian
888 integer(i4), intent(out) :: dd, mm, yy
889 integer(i4), parameter :: year = 360, month = 30
890 integer(i4) :: remainder
891
892 yy = julian / year
893 remainder = mod(abs(julian), year)
894 mm = remainder / month + 1
895 dd = mod(abs(julian), month) + 1
896
897 end subroutine caldat360
898
899 ! ------------------------------------------------------------------
900
901 !> \brief Julian day from day, month and year in a 360_day calendar
902
903 !> \details In this routine julday360 returns the Julian Day Number that begins at noon of the calendar
904 !! date specified by month mm, day dd, and year yy, all integer variables.
905 !!
906 !! The zeroth Julian Day is 01.01.0000
907 !!
908 !! \b Example
909 !!
910 !! \code{.f90}
911 !! julian = julday360(dd, mm, yy)
912 !! \endcode
913
914 !> \param[in] "integer(i4) :: dd" Day in month of Julian day
915 !> \param[in] "integer(i4) :: mm" Month in year of Julian day
916 !> \param[in] "integer(i4) :: yy" Year of Julian day
917 !> \retval "integer(i4) :: julian" Julian day
918
919 !> \author David Schaefer
920 !> \date Oct 2015
921 elemental function julday360(dd, mm, yy)
922
923 implicit none
924
925 integer(i4), intent(in) :: dd, mm, yy
926 integer(i4) :: julday360
927 integer(i4), parameter :: year = 360, month = 30
928
929 julday360 = abs(yy) * year + (mm - 1) * month + (dd - 1)
930 if (yy < 0) julday360 = julday360 * (-1)
931
932 end function julday360
933
934 ! ------------------------------------------------------------------
935
936 !> \brief Day, month, year, hour, minute, and second from fractional Julian day in a 360_day calendar
937
938 !> \details Inverse of the function date2dec360. Here dec2date360 is input as a fractional Julian Day.
939 !! The routine outputs dd, mm, yy, hh, nn, ss as the day, month, year, hour, minute, and second
940 !! on which the specified Julian Day started at noon.
941 !!
942 !! The zeroth Julian Day is 01.01.0000 at noon.
943 !!
944 !! \b Example
945 !!
946 !! \code{.f90}
947 !! call dec2date360(fJulian, dd, mm, yy, hh, nn, ss)
948 !! \endcode
949
950 !> \param[in] "real(dp) :: fJulian" fractional Julian day
951 !> \param[out] "integer(i4), optional :: dd" Day in month of Julian day
952 !> \param[out] "integer(i4), optional :: mm" Month in year of Julian day
953 !> \param[out] "integer(i4), optional :: yy" Year of Julian day
954 !> \param[out] "integer(i4), optional :: hh" Hour of Julian day
955 !> \param[out] "integer(i4), optional :: nn" Minute in hour of Julian day
956 !> \param[out] "integer(i4), optional :: ss" Second in minute of hour of Julian day
957
958 !> \author David Schaefer
959 !> \date Oct 2015
960 elemental subroutine dec2date360(julian, dd, mm, yy, hh, nn, ss)
961
962 implicit none
963
964 real(dp), intent(in) :: julian
965 integer(i4), intent(out), optional :: dd, mm, yy
966 integer(i4), intent(out), optional :: hh, nn, ss
967 integer(i4) :: day, month, year
968 real(dp) :: fraction, fjulian
969 integer(i4) :: hour, minute, second
970
971 fjulian = julian + .5_dp
972 call caldat360(int(floor(fjulian), i4), day, month, year)
973
974 fraction = fjulian - floor(fjulian)
975 hour = min(max(floor(fraction * 24.0_dp), 0), 23)
976 fraction = fraction - real(hour, dp) / 24.0_dp
977 minute = min(max(floor(fraction * 1440.0_dp), 0), 59)
978 second = max(nint((fraction - real(minute, dp) / 1440.0_dp) * 86400.0_dp), 0)
979
980 ! If seconds==60
981 if (second==60) then
982 second = 0
983 minute = minute + 1
984 if (minute==60) then
985 minute = 0
986 hour = hour + 1
987 if (hour==24) then
988 hour = 0
989 call caldat360(julday360(day, month, year) + 1, day, month, year)
990 end if
991 end if
992 end if
993
994 if (present(dd)) dd = day
995 if (present(mm)) mm = month
996 if (present(yy)) yy = year
997 if (present(hh)) hh = hour
998 if (present(nn)) nn = minute
999 if (present(ss)) ss = second
1000
1001 end subroutine dec2date360
1002
1003 ! ------------------------------------------------------------------
1004
1005 !> \brief Fractional Julian day from day, month, year, hour, minute, second in 360 day calendar
1006
1007 !> \details In this routine date2dec360 returns the fractional Julian Day that begins at noon
1008 !! of the calendar date specified by month mm, day dd, and year yy, all integer variables.
1009 !!
1010 !! The zeroth Julian Day is 01.01.0000 at noon.
1011 !!
1012 !! \b Example
1013 !!
1014 !! \code{.f90}
1015 !! date2dec360 = date2dec360(dd, mm, yy, hh, nn, ss)
1016 !! \endcode
1017
1018 !> \param[in] "integer(i4), optional :: dd" Day in month of Julian day (default: 1)
1019 !> \param[in] "integer(i4), optional :: mm" Month in year of Julian day (default: 1)
1020 !> \param[in] "integer(i4), optional :: yy" Year of Julian day (default: 1)
1021 !> \param[in] "integer(i4), optional :: hh" Hours of Julian day (default: 0)
1022 !> \param[in] "integer(i4), optional :: nn" Minutes of hour of Julian day (default: 0)
1023 !> \param[in] "integer(i4), optional :: ss" Secondes of minute of hour of Julian day (default: 0)
1024 !> \retval "real(dp) :: date2dec360" Fractional Julian day
1025
1026 !> \author David Schaefer
1027 !> \date Oct 2015
1028 elemental function date2dec360(dd, mm, yy, hh, nn, ss)
1029
1030 implicit none
1031
1032 integer(i4), intent(in), optional :: dd, mm, yy
1033 integer(i4), intent(in), optional :: hh, nn, ss
1034 real(dp) :: date2dec360, eps
1035 integer(i4) :: idd, imm, iyy
1036 real(dp) :: ihh, inn, iss
1037 real(dp) :: hour
1038
1039 ! Presets
1040 idd = 1
1041 if (present(dd)) idd = dd
1042 imm = 1
1043 if (present(mm)) imm = mm
1044 iyy = 1
1045 if (present(yy)) iyy = yy
1046 ihh = 0.0_dp
1047 if (present(hh)) ihh = real(hh, dp)
1048 inn = 0.0_dp
1049 if (present(nn)) inn = real(nn, dp)
1050 iss = 0.0_dp
1051 if (present(ss)) iss = real(ss, dp)
1052
1053 hour = ihh / 24._dp + inn / 1440._dp + iss / 86400._dp - .5_dp
1054
1055 ! Fractional Julian day starts at noon
1056 date2dec360 = real(julday360(idd, imm, iyy), dp) + hour
1057
1058 ! Add a small offset (proportional to julian date) for correct re-conversion.
1059 eps = epsilon(1.0_dp)
1060 eps = max(eps * abs(date2dec360), eps)
1061 date2dec360 = date2dec360 + eps
1062
1063 end function date2dec360
1064
1065 ! ------------------------------------------------------------------
1066
1067 !> \brief Day, month and year from Julian day in a 365 day calendar
1068
1069 !> \details Inverse of the function julday365. Here julian is input as a Julian Day Number,
1070 !! and the routine outputs dd, mm, and yy as the day, month, and year on which the specified
1071 !! Julian Day started at noon.
1072 !!
1073 !! The zeroth Julian Day here is 01.01.0000
1074 !!
1075 !! \b Example
1076 !!
1077 !! \code{.f90}
1078 !! call caldat365(julday, dd, mm, yy)
1079 !! \endcode
1080
1081 !> \param[in] "integer(i4) :: julday" Julian day
1082 !> \param[out] "integer(i4) :: dd" Day in month of Julian day
1083 !> \param[out] "integer(i4) :: mm" Month in year of Julian day
1084 !> \param[out] "integer(i4) :: yy" Year of Julian day
1085
1086 !> \author David Schaefer
1087 !> \date Dec 2015
1088 elemental subroutine caldat365(julian, dd, mm, yy)
1089
1090 implicit none
1091
1092 integer(i4), intent(in) :: julian
1093 integer(i4), intent(out) :: dd, mm, yy
1094 integer(i4), parameter :: year = 365
1095 integer(i4), dimension(12), parameter :: months = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
1096 integer(i4) :: remainder
1097
1098 yy = julian / year
1099 remainder = mod(abs(julian), year) + 1
1100
1101 do mm = 1, size(months)
1102 if (remainder .le. months(mm)) then
1103 exit
1104 end if
1105 remainder = remainder - months(mm)
1106 end do
1107
1108 dd = remainder
1109
1110 end subroutine caldat365
1111
1112 ! ------------------------------------------------------------------
1113
1114 !> \brief Julian day from day, month and year in a 365_day calendar
1115
1116 !> \details In this routine julday365 returns the Julian Day Number that begins at noon of the calendar
1117 !! date specified by month mm, day dd, and year yy, all integer variables.
1118 !!
1119 !! The zeroth Julian Day is 01.01.0000
1120 !!
1121 !! \b Example
1122 !!
1123 !! \code{.f90}
1124 !! julian = julday365(dd, mm, yy)
1125 !! \endcode
1126
1127 !> \param[in] "integer(i4) :: dd" Day in month of Julian day
1128 !> \param[in] "integer(i4) :: mm" Month in year of Julian day
1129 !> \param[in] "integer(i4) :: yy" Year of Julian day
1130 !> \retval "integer(i4) :: julian" Julian day
1131
1132 !> \author David Schaefer
1133 !> \date Dec 2015
1134 elemental function julday365(dd, mm, yy)
1135
1136 implicit none
1137
1138 integer(i4), intent(in) :: dd, mm, yy
1139 integer(i4) :: julday365
1140 integer(i4), parameter :: year = 365
1141 integer(i4), dimension(12), parameter :: months = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
1142
1143 julday365 = abs(yy) * year + sum(months(1 : mm - 1)) + (dd - 1)
1144
1145 if (yy < 0) julday365 = julday365 * (-1)
1146
1147 end function julday365
1148
1149 ! ------------------------------------------------------------------
1150
1151 !> \brief Day, month, year, hour, minute, and second from fractional Julian day in a 365_day calendar
1152
1153 !> \details Inverse of the function date2dec. Here dec2date365 is input as a fractional Julian Day.
1154 !! The routine outputs dd, mm, yy, hh, nn, ss as the day, month, year, hour, minute, and second
1155 !! on which the specified Julian Day started at noon.
1156 !!
1157 !! The zeroth Julian Day is 01.01.0000 at noon.
1158 !!
1159 !! \b Example
1160 !!
1161 !! \code{.f90}
1162 !! call dec2date365(fJulian, dd, mm, yy, hh, nn, ss)
1163 !! \endcode
1164
1165 !> \param[in] "real(dp) :: fJulian" fractional Julian day
1166 !> \param[out] "integer(i4), optional :: dd" Day in month of Julian day
1167 !> \param[out] "integer(i4), optional :: mm" Month in year of Julian day
1168 !> \param[out] "integer(i4), optional :: yy" Year of Julian day
1169 !> \param[out] "integer(i4), optional :: hh" Hour of Julian day
1170 !> \param[out] "integer(i4), optional :: nn" Minute in hour of Julian day
1171 !> \param[out] "integer(i4), optional :: ss" Second in minute of hour of Julian day
1172
1173 !> \author David Schaefer
1174 !> \date Dec 2015
1175 elemental subroutine dec2date365(julian, dd, mm, yy, hh, nn, ss)
1176
1177 implicit none
1178
1179 real(dp), intent(in) :: julian
1180 integer(i4), intent(out), optional :: dd, mm, yy
1181 integer(i4), intent(out), optional :: hh, nn, ss
1182 integer(i4) :: day, month, year
1183 real(dp) :: fraction, fjulian
1184 integer(i4) :: hour, minute, second
1185
1186 fjulian = julian + .5_dp
1187 call caldat365(int(floor(fjulian), i4), day, month, year)
1188
1189 fraction = fjulian - floor(fjulian)
1190 hour = min(max(floor(fraction * 24.0_dp), 0), 23)
1191 fraction = fraction - real(hour, dp) / 24.0_dp
1192 minute = min(max(floor(fraction * 1440.0_dp), 0), 59)
1193 second = max(nint((fraction - real(minute, dp) / 1440.0_dp) * 86400.0_dp), 0)
1194
1195 ! If seconds==60
1196 if (second==60) then
1197 second = 0
1198 minute = minute + 1
1199 if (minute==60) then
1200 minute = 0
1201 hour = hour + 1
1202 if (hour==24) then
1203 hour = 0
1204 call caldat365(julday365(day, month, year) + 1, day, month, year)
1205 end if
1206 end if
1207 end if
1208
1209 if (present(dd)) dd = day
1210 if (present(mm)) mm = month
1211 if (present(yy)) yy = year
1212 if (present(hh)) hh = hour
1213 if (present(nn)) nn = minute
1214 if (present(ss)) ss = second
1215
1216 end subroutine dec2date365
1217
1218 ! ------------------------------------------------------------------
1219
1220 !> \brief Fractional Julian day from day, month, year, hour, minute, second in 365 day calendar
1221
1222 !> \details In this routine date2dec365 returns the fractional Julian Day that begins at noon
1223 !! of the calendar date specified by month mm, day dd, and year yy, all integer variables.
1224 !!
1225 !! The zeroth Julian Day is 01.01.0000 at noon.
1226 !!
1227 !! \b Example
1228 !!
1229 !! \code{.f90}
1230 !! date2dec365 = date2dec365(dd, mm, yy, hh, nn, ss)
1231 !! \endcode
1232
1233 !> \param[in] "integer(i4), optional :: dd" Day in month of Julian day (default: 1)
1234 !> \param[in] "integer(i4), optional :: mm" Month in year of Julian day (default: 1)
1235 !> \param[in] "integer(i4), optional :: yy" Year of Julian day (default: 1)
1236 !> \param[in] "integer(i4), optional :: hh" Hours of Julian day (default: 0)
1237 !> \param[in] "integer(i4), optional :: nn" Minutes of hour of Julian day (default: 0)
1238 !> \param[in] "integer(i4), optional :: ss" Secondes of minute of hour of Julian day (default: 0)
1239 !> \retval "real(dp) :: date2dec365" Fractional Julian day
1240
1241 !> \author David Schaefer
1242 !> \date Dec 2015
1243 elemental function date2dec365(dd, mm, yy, hh, nn, ss)
1244
1245 implicit none
1246
1247 integer(i4), intent(in), optional :: dd, mm, yy
1248 integer(i4), intent(in), optional :: hh, nn, ss
1249 real(dp) :: date2dec365, eps
1250 integer(i4) :: idd, imm, iyy
1251 real(dp) :: ihh, inn, iss
1252 real(dp) :: hour
1253
1254 ! Presets
1255 idd = 1
1256 if (present(dd)) idd = dd
1257 imm = 1
1258 if (present(mm)) imm = mm
1259 iyy = 1
1260 if (present(yy)) iyy = yy
1261 ihh = 0.0_dp
1262 if (present(hh)) ihh = real(hh, dp)
1263 inn = 0.0_dp
1264 if (present(nn)) inn = real(nn, dp)
1265 iss = 0.0_dp
1266 if (present(ss)) iss = real(ss, dp)
1267
1268 hour = ihh / 24._dp + inn / 1440._dp + iss / 86400._dp - .5_dp
1269
1270 ! Fractional Julian day starts at noon
1271 date2dec365 = real(julday365(idd, imm, iyy), dp) + hour
1272
1273 ! Add a small offset (proportional to julian date) for correct re-conversion.
1274 eps = epsilon(1.0_dp)
1275 eps = max(eps * abs(date2dec365), eps)
1276 date2dec365 = date2dec365 + eps
1277
1278 end function date2dec365
1279
1280
1281 ! ------------------------------------------------------------------
1282
1283END MODULE mo_julian
Set module private variable calendar.
Definition mo_julian.f90:72
Julian date conversion routines.
Definition mo_julian.f90:33
pure integer(i4) function selectcalendar(selector)
Select a calendar.
elemental real(dp) function, public date2dec(dd, mm, yy, hh, nn, ss, calendar)
Fractional Julian day from day, month, year, hour, minute, second in the current calendar.
elemental real(dp) function date2decjulian(dd, mm, yy, hh, nn, ss)
Fractional Julian day from day, month, year, hour, minute, second.
elemental subroutine, public caldat(julian, dd, mm, yy, calendar)
Day, month and year from Julian day in the current or given calendar.
elemental subroutine, public dec2date(julian, dd, mm, yy, hh, nn, ss, calendar)
Day, month, year, hour, minute, and second from fractional Julian day in the current or given calenda...
elemental real(dp) function date2dec365(dd, mm, yy, hh, nn, ss)
Fractional Julian day from day, month, year, hour, minute, second in 365 day calendar.
elemental subroutine dec2date365(julian, dd, mm, yy, hh, nn, ss)
Day, month, year, hour, minute, and second from fractional Julian day in a 365_day calendar.
elemental subroutine caldat365(julian, dd, mm, yy)
Day, month and year from Julian day in a 365 day calendar.
elemental integer(i4) function juldayjulian(dd, mm, yy)
Julian day from day, month and year.
elemental subroutine caldat360(julian, dd, mm, yy)
Day, month and year from Julian day in a 360 day calendar.
elemental integer(i4) function julday365(dd, mm, yy)
Julian day from day, month and year in a 365_day calendar.
elemental subroutine dec2datejulian(julian, dd, mm, yy, hh, nn, ss)
Day, month, year, hour, minute, and second from fractional Julian day.
elemental integer(i4) function, public julday(dd, mm, yy, calendar)
Julian day from day, month and year in the current or given calendar.
elemental integer(i4) function, public ndays(dd, mm, yy)
IMSL Julian day from day, month and year.
elemental subroutine dec2date360(julian, dd, mm, yy, hh, nn, ss)
Day, month, year, hour, minute, and second from fractional Julian day in a 360_day calendar.
elemental subroutine, public caldatjulian(julian, dd, mm, yy)
Day, month and year from Julian day.
elemental integer(i4) function julday360(dd, mm, yy)
Julian day from day, month and year in a 360_day calendar.
elemental real(dp) function date2dec360(dd, mm, yy, hh, nn, ss)
Fractional Julian day from day, month, year, hour, minute, second in 360 day calendar.
elemental subroutine, public ndyin(julian, dd, mm, yy)
Day, month and year from IMSL Julian day.
Define number representations.
Definition mo_kind.F90:17
integer, parameter i4
4 Byte Integer Kind
Definition mo_kind.F90:40
integer, parameter i8
8 Byte Integer Kind
Definition mo_kind.F90:42
integer, parameter dp
Double Precision Real Kind.
Definition mo_kind.F90:46