libSUFR
a LIBrary of Some Useful Fortran Routines
All Classes Namespaces Files Functions Variables Pages
date_and_time.f90
Go to the documentation of this file.
1!> \file date_and_time.f90 Procedures to manipulate date and time
2
3
4! Copyright (c) 2002-2025 Marc van der Sluys - Nikhef/Utrecht University - marc.vandersluys.nl
5!
6! This file is part of the libSUFR package,
7! see: http://libsufr.sourceforge.net/
8!
9! This is free software: you can redistribute it and/or modify it under the terms of the European Union
10! Public Licence 1.2 (EUPL 1.2). This software is distributed in the hope that it will be useful, but
11! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12! PURPOSE. See the EU Public Licence for more details. You should have received a copy of the European
13! Union Public Licence along with this code. If not, see <https://www.eupl.eu/1.2/en/>.
14!
15!
16
17
18
19
20!***********************************************************************************************************************************
21!> \brief Procedures for manipulation of date and time
22
24 implicit none
25 save
26
27contains
28
29
30 !*********************************************************************************************************************************
31 !> \brief Convert a calendar date to JD. Input and output in UT.
32 !!
33 !! \param yy The year (int)
34 !! \param mm The month (int)
35 !! \param dd The day (double)
36 !!
37 !! \retval cal2jd The Julian day number (double)
38 !!
39 !! \note The Gregorian calendar is assumed to start on 1582-10-15.
40
41 elemental function cal2jd(yy,mm,dd)
42 use sufr_kinds, only: double
43
44 implicit none
45 real(double), intent(in) :: dd
46 integer, intent(in) :: yy,mm
47
48 real(double) :: cal2jd,d
49 integer :: y,m,a,b,greg
50
51 y = yy
52 m = mm
53 d = dd
54
55 greg = 0 ! Julian or gregorian?
56 if(y.gt.1582) greg = 1
57 if(y.eq.1582) then
58 if(m.gt.10) greg = 1
59 if((m.eq.10).and.(d.ge.15)) greg = 1
60 end if
61 !greg=0 ! Force julian/gregorian calendar
62
63 if(m.le.2) then
64 y = y-1
65 m = m+12
66 end if
67 b = 0
68
69 if(greg.eq.1) then ! Assume a Gregorian date
70 a = floor(y/100.d0)
71 b = 2 - a + floor(a/4.d0)
72 end if
73
74 cal2jd = floor(365.25d0*(y+4716)) + floor(30.6001d0*(m+1)) + d + b - 1524.5d0
75
76 end function cal2jd
77 !*********************************************************************************************************************************
78
79
80
81 !*********************************************************************************************************************************
82 !> \brief Convert a Julian day to a calendar date (fractional day) - in UT
83 !!
84 !! \param jd Julian day (UT)
85 !! \param yy Year (CE) (output)
86 !! \param mm Month (output)
87 !! \param dd Day of month (+ fraction) (output)
88
89 elemental subroutine jd2cal(jd, yy,mm,dd)
90 use sufr_kinds, only: double, dbl, long
91
92 implicit none
93 real(double), intent(in) :: jd
94 integer, intent(out) :: yy,mm
95 real(double), intent(out) :: dd
96 real(double) :: f
97 integer(long) :: z,a,b,c,d,e,alpha
98
99 ! Some programs may return JD=-huge if no solution is found - catch this
100 if(jd.gt.abs(huge(jd))*0.1_dbl) then
101 yy = 0
102 mm = 0
103 dd = 0.0_dbl
104 return
105 end if
106
107
108 z = floor(jd+0.5d0)
109 f = jd + 0.5d0 - z
110 if(z.lt.2299161) then ! Use the Julian calendar
111 a = z
112 else ! Use the Gregorian calendar
113 alpha = floor((z-1867216.25d0)/36524.25d0)
114 a = z + 1 + alpha - floor(alpha/4.d0)
115 end if
116
117 b = a + 1524
118 c = floor((b - 122.1d0)/365.25d0)
119 d = floor(365.25d0*c)
120 e = floor((b-d)/30.6001d0)
121 dd = b - d - floor(30.6001d0*e) + f
122
123 if(e.lt.14) then
124 mm = int(e - 1)
125 else
126 mm = int(e - 13)
127 end if
128
129 if(mm.gt.2) then
130 yy = int(c - 4716)
131 else
132 yy = int(c - 4715)
133 end if
134
135 end subroutine jd2cal
136 !*********************************************************************************************************************************
137
138
139
140 !*********************************************************************************************************************************
141 !> \brief Convert a year (with decimals) to a JD. Input and output in UT.
142 !!
143 !! \param year The year
144 !!
145 !! \retval year2jd The Julian day number
146 !!
147 !! \note The Gregorian calendar is assumed to start on 1582-10-15.
148
149 elemental function year2jd(year)
150 use sufr_kinds, only: double
151
152 implicit none
153 real(double), intent(in) :: year
154
155 real(double) :: year2jd,y
156 integer :: a,b
157
158 y = year - 1.d0
159
160 b = 0
161 if(year .gt. 1582.d0+278.d0/365.25d0) then ! Gregorian calendar starts on 1582-10-15
162 a = floor(y/100.d0)
163 b = 2 - a + floor(a/4.d0)
164 end if
165
166 year2jd = floor(365.25d0*(y+4716)) + floor(30.6001d0*14) + b - 1523.5d0
167
168 end function year2jd
169 !*********************************************************************************************************************************
170
171
172
173 !*********************************************************************************************************************************
174 !> \brief Convert a Julian day to date and time (h,m,s, UT)
175 !!
176 !! \param jd Julian day (UT)
177 !!
178 !! \param yy Year (CE, UT) (output)
179 !! \param mm Month (UT) (output)
180 !! \param d Day (UT) (output)
181 !! \param h Hour (UT) (output)
182 !! \param m Minute (UT) (output)
183 !! \param s Second (+ fraction, UT) (output)
184
185 elemental subroutine jd2ymdhms(jd, yy,mm,d, h,m,s)
186 use sufr_kinds, only: double, dbl
187
188 implicit none
189 real(double), intent(in) :: jd
190 integer, intent(out) :: yy,mm,d,h,m
191 real(double), intent(out) :: s
192 real(double) :: dd,tm
193
194 call jd2cal(jd, yy,mm,dd)
195
196 ! jd2cal returns zeroes if JD is not defined (i.e., JD=-huge) - catch this:
197 if(yy.eq.0.and.mm.eq.0) then
198 d = 0
199 h = 0
200 m = 0
201 s = 0.0_dbl
202 return
203 end if
204
205 d = floor(dd)
206 tm = (dd - dble(d))*24.d0
207 h = floor(tm)
208 m = floor((tm-h)*60.d0)
209 s = (tm-h-m/60.d0)*3600.d0
210
211 end subroutine jd2ymdhms
212 !*********************************************************************************************************************************
213
214
215 !*********************************************************************************************************************************
216 !> \brief Convert a Julian day to a date string (yyyy-mm-dd)
217 !!
218 !! \param jd Julian day (UT)
219 !! \retval jd2datestr The date as a string (yyyy-mm-dd)
220
221 elemental function jd2datestr(jd)
222 use sufr_kinds, only: double
223
224 character :: jd2datestr*(15)
225 real(double), intent(in) :: jd
226
227 integer :: yr,mnt
228 real(double) :: day
229
230 call jd2cal(jd, yr,mnt,day)
231 write(jd2datestr,'(I0,A1,2(I2.2,A1))') yr,'-',mnt,'-',floor(day)
232
233 end function jd2datestr
234 !*********************************************************************************************************************************
235
236
237 !*********************************************************************************************************************************
238 !> \brief Convert a Julian day to time (UT, h)
239 !!
240 !! \param jd Julian day (UT)
241 !! \retval jd2time Time in hours
242
243 elemental function jd2time(jd)
244 use sufr_kinds, only: double
245
246 implicit none
247 real(double), intent(in) :: jd
248 real(double) :: jd2time,dd
249 integer :: mm,yy
250
251 call jd2cal(jd, yy,mm,dd)
252 jd2time = (dd - floor(dd))*24.d0
253
254 end function jd2time
255 !*********************************************************************************************************************************
256
257
258
259 !*********************************************************************************************************************************
260 !> \brief Convert a Julian day to decimal year (e.g. 2000.0)
261 !!
262 !! \param jd Julian day (UT)
263 !! \retval jd2year Decimal year CE
264
265 elemental function jd2year(jd)
266 use sufr_kinds, only: double
267
268 implicit none
269 real(double), intent(in) :: jd
270 real(double) :: jd2year,dd, jd0,jd1, dy
271 integer :: mm,yy
272
273 call jd2cal(jd, yy,mm,dd)
274 jd0 = cal2jd(yy,1,1.d0)
275 jd1 = cal2jd(yy+1,1,1.d0)
276
277 dy = (jd-jd0) / (jd1-jd0)
278 jd2year = dble(yy) + dy
279
280 end function jd2year
281 !*********************************************************************************************************************************
282
283
284
285 !*********************************************************************************************************************************
286 !> \brief Convert a Julian day to a date (y,m,d) and time (UT, h)
287 !!
288 !! \param jd Julian day (UT). In order to obtain a local date and time, add TZ/24 to the JD.
289 !!
290 !! \param year Year CE (output)
291 !! \param month Month of year (output)
292 !! \param day Day of the month (output)
293 !! \param time Time of day (hours) (output)
294
295 elemental subroutine jd2datetime(jd, year,month,day, time)
296 use sufr_kinds, only: double
297
298 implicit none
299 real(double), intent(in) :: jd
300 real(double), intent(out) :: time
301 integer, intent(out) :: year,month,day
302 real(double) :: dd
303
304 call jd2cal(jd, year,month,dd)
305 day = floor(dd)
306 time = (dd - dble(day))*24.d0
307
308 end subroutine jd2datetime
309 !*********************************************************************************************************************************
310
311
312
313 !*********************************************************************************************************************************
314 !> \brief Convert date and time (y,m,d, h,m,s) to JD. Input and output in UT.
315 !!
316 !! \param yy The year (int)
317 !! \param mmo The month (int)
318 !! \param dd The day (int)
319 !! \param h The hour (int)
320 !! \param m The minute (int)
321 !! \param s The second (double)
322 !!
323 !! \retval ymdhms2jd The Julian day number (double)
324
325 elemental function ymdhms2jd(yy,mmo,dd, h,m,s)
326 use sufr_kinds, only: double
327
328 implicit none
329 integer, intent(in) :: yy,mmo,dd,h,m
330 real(double), intent(in) :: s
331 real(double) ymdhms2jd
332
333 integer :: y,mo
334 real(double) :: d
335
336 y = yy
337 mo = mmo
338 d = dble(dd) + dble(h)/24.d0 + dble(m)/1440.d0 + s/86400.d0
339 ymdhms2jd = cal2jd(y,mo,d)
340
341 end function ymdhms2jd
342 !*********************************************************************************************************************************
343
344
345 !*********************************************************************************************************************************
346 !> \brief Ensure date and time are consistent after manipulation (0<month<13, 0<=minute<60, etc.)
347 !!
348 !! \param year Year CE (I/O)
349 !! \param month Month of year (I/O)
350 !! \param day Day of month (I/O)
351 !!
352 !! \param hour Hour of day (I/O)
353 !! \param minute Minute (I/O)
354 !! \param second Second (I/O)
355
356 elemental subroutine consistent_date_time(year,month,day, hour,minute,second)
357 use sufr_kinds, only: double
358
359 implicit none
360 integer, intent(inout) :: year,month,day, hour,minute
361 real(double), intent(inout) :: second
362 real(double) :: jd
363
364 jd = ymdhms2jd(year,month,day, hour,minute,second)
365 call jd2ymdhms(jd, year,month,day, hour,minute,second)
366
367 end subroutine consistent_date_time
368 !*********************************************************************************************************************************
369
370
371 !*********************************************************************************************************************************
372 !> \brief Convert date and time (h) to a Julian day - input in UT
373 !!
374 !! \param yy Year (CE)
375 !! \param mo Month
376 !! \param dd Day of month
377 !! \param time Time (hours)
378 !! \retval dtm2jd Julian day
379
380 elemental function dtm2jd(yy,mo,dd,time)
381 use sufr_kinds, only: double
382
383 implicit none
384 integer, intent(in) :: yy,mo,dd
385 real(double), intent(in) :: time
386 real(double) :: d,dtm2jd
387
388 d = dble(dd) + time/24.d0
389 dtm2jd = cal2jd(yy,mo,d)
390
391 end function dtm2jd
392 !*********************************************************************************************************************************
393
394
395
396
397
398 !*********************************************************************************************************************************
399 !> \brief Convert time (h) to hours and (integer) minutes
400 !!
401 !! \param tm Time (hours)
402 !! \param h Hours (output)
403 !! \param m Minutes (integer) (output)
404
405 elemental subroutine tm2hm(tm,h,m)
406 use sufr_kinds, only: double
407 implicit none
408 real(double), intent(in) :: tm
409 integer, intent(out) :: h,m
410
411 h = floor(tm)
412 m = nint((tm-dble(h))*60)
413
414 if(m.ge.60) then
415 h = h+1
416 m = m-60
417 end if
418 if(h.ge.24) h = h-24
419
420 end subroutine tm2hm
421 !*********************************************************************************************************************************
422
423
424
425 !*********************************************************************************************************************************
426 !> \brief Convert time (h) to hours and (decimal) minutes
427 !!
428 !! \param tm Time (hours)
429 !! \param h Hours (output)
430 !! \param m Minutes (decimal) (output)
431
432 elemental subroutine tm2hmm(tm,h,m)
433 use sufr_kinds, only: double
434 implicit none
435 real(double), intent(in) :: tm
436 integer, intent(out) :: h
437 real(double), intent(out) :: m
438
439 h = floor(tm)
440 m = (tm-dble(h))*60
441
442 if(h.ge.24) h = h-24
443
444 end subroutine tm2hmm
445 !*********************************************************************************************************************************
446
447
448
449 !*********************************************************************************************************************************
450 !> \brief Convert time (h) to hours, minutes and (integer) seconds
451 !!
452 !! \param tm Time (hours)
453 !! \param h Hours (output)
454 !! \param m Minutes (output)
455 !! \param s Seconds (integer) (output)
456
457 elemental subroutine tm2hms(tm, h,m,s)
458 use sufr_kinds, only: double
459 implicit none
460 real(double), intent(in) :: tm
461 integer, intent(out) :: h,m,s
462
463 h = floor(tm)
464 m = floor((tm-dble(h))*60)
465 s = nint((tm - dble(h) - dble(m)/60.d0)*3600)
466
467 if(s.ge.60) then
468 m = m+1
469 s = s-60
470 end if
471 if(m.ge.60) then
472 h = h+1
473 m = m-60
474 end if
475 if(h.ge.24) h = h-24
476
477 end subroutine tm2hms
478 !*********************************************************************************************************************************
479
480
481
482
483 !*********************************************************************************************************************************
484 !> \brief Convert time (h) to hours, minutes and (decimal) seconds
485 !!
486 !! \param tm Time (hours)
487 !! \param h Hours (output)
488 !! \param m Minutes (output)
489 !! \param s Seconds (output)
490
491 elemental subroutine tm2hmss(tm, h,m,s)
492 use sufr_kinds, only: double
493 implicit none
494 real(double), intent(in) :: tm
495 integer, intent(out) :: h,m
496 real(double), intent(out) :: s
497
498 h = floor(tm)
499 m = floor((tm-dble(h))*60)
500 s = (tm - dble(h) - dble(m)/60.d0)*3600
501
502 if(m.ge.60) then
503 h = h+1
504 m = m-60
505 end if
506 if(h.ge.24) h = h-24
507
508 end subroutine tm2hmss
509 !*********************************************************************************************************************************
510
511
512
513
514 !*********************************************************************************************************************************
515 !> \brief Calculates day of week (0 = Sunday, ..., 6 = Saturday). Output for timezone of input - call dow_ut(jd+tz/24.d0) for local time.
516 !!
517 !! \param jd0 Julian day number (double)
518 !! \retval dow_ut The day-of-week number, 0-6 for Sun-Sat (int)
519
520 elemental function dow_ut(jd0)
521 use sufr_kinds, only: double
522
523 implicit none
524 real(double), intent(in) :: jd0
525 integer :: dow_ut
526 real(double) :: jd,x
527
528 jd = dble(nint(jd0)) - 0.5d0
529 x = (jd + 1.5d0)/7.d0
530
531 dow_ut = nint(jd + 1.5d0 - floor(x)*7.d0)
532
533 end function dow_ut
534 !*********************************************************************************************************************************
535
536
537 !*********************************************************************************************************************************
538 !> \brief Calculates ISO day of week (1 = Monday, ..., 7 = Sunday). Output for timezone of input - call dow_ut(jd+tz/24.d0) for local time.
539 !!
540 !! \param jd0 Julian day number (double)
541 !! \retval dow_iso The day-of-week number, 1-7 for Mon-Sun (int)
542
543 elemental function dow_iso(jd0)
544 use sufr_kinds, only: double
545
546 implicit none
547 real(double), intent(in) :: jd0
548 integer :: dow_iso
549
550 dow_iso = dow_ut(jd0)
551 if(dow_iso.eq.0) dow_iso = 7
552
553 end function dow_iso
554 !*********************************************************************************************************************************
555
556
557 !*********************************************************************************************************************************
558 !> \brief Calculate day of year (1-366) from JD
559 !!
560 !! \param jd0 Julian day
561 !! \retval doy The day of year (1-366)
562
563 elemental function doy(jd0)
564 use sufr_kinds, only: double
565
566 implicit none
567 real(double), intent(in) :: jd0
568 integer :: doy,yr,mon
569 real(double) :: jd1,dy
570
571 call jd2cal(jd0, yr,mon,dy)
572 jd1 = cal2jd(yr,1,0.5d0)
573 doy = nint(jd0-jd1)
574
575 end function doy
576 !*********************************************************************************************************************************
577
578
579
580 !*********************************************************************************************************************************
581 !> \brief Calculate day of year (1-366) from year,month,day
582 !!
583 !! \param yr Year (CE)
584 !! \param mon Month
585 !! \param dy Day of month
586 !! \retval ymd2doy Day of year (1-366)
587
588 elemental function ymd2doy(yr,mon,dy)
589 use sufr_kinds, only: double
590
591 implicit none
592 integer, intent(in) :: yr,mon,dy
593 real(double) :: jd0,jd1
594 integer :: ymd2doy
595
596 jd0 = cal2jd(yr,mon,dble(dy))
597 jd1 = cal2jd(yr,1,0.5d0)
598 ymd2doy = nint(jd0-jd1)
599
600 end function ymd2doy
601 !*********************************************************************************************************************************
602
603
604
605 !*********************************************************************************************************************************
606 !> \brief Calculate month and day from day of year and year
607 !!
608 !! \param doy Day of year number
609 !! \param yr Year (CE)
610 !! \param mon Month of year (output)
611 !! \param dy Day of month (output)
612 !!
613 !! \note year is input
614
615 elemental subroutine doy2md(doy,yr, mon,dy)
616 use sufr_kinds, only: double
617
618 implicit none
619 integer, intent(in) :: doy,yr
620 integer, intent(out) :: mon,dy
621 integer :: yr1
622 real(double) :: jd1,dy1
623
624 jd1 = cal2jd(yr,1,dble(doy))
625 call jd2cal(jd1,yr1,mon,dy1)
626 dy = floor(dy1)
627
628 end subroutine doy2md
629 !*********************************************************************************************************************************
630
631
632
633 !*********************************************************************************************************************************
634 !> \brief Calculate whether year is leap (1) or not (0). The number of days in February is then given by
635 !! 28 + leapyr(yr) and number of days in a year by 365 + leapyr(yr)
636 !!
637 !! \param yr Year (CE)
638 !! \retval leapyr Leap year (1) or no (0)
639
640 elemental function leapyr(yr)
641
642 implicit none
643 integer, intent(in) :: yr
644 integer :: leapyr
645
646 leapyr = nint( cal2jd(yr,3,1.d0) - cal2jd(yr,2,29.d0) )
647
648 end function leapyr
649 !*********************************************************************************************************************************
650
651
652
653 !*********************************************************************************************************************************
654 !> \brief Return JD as date and time in ISO_8601 format (e.g. 2014-03-24T20:48:01+00:00)
655 !!
656 !! \param jd Julian day (UT)
657 !! \param tz Time zone (optional - default: 0 = UT)
658 !! \retval jd2iso8601 Date string in ISO 8601 format.
659
660 elemental function jd2iso8601(jd, tz)
661 use sufr_kinds, only: double
662
663 implicit none
664 real(double), intent(in) :: jd
665 real(double), intent(in), optional :: tz
666 character :: jd2iso8601*(30), tzsign ! Need 25 for -999 <= year <= 9999
667 integer :: dy,yr,mon, hr,mn,se, tzhr,tzmn
668 real(double) :: day, time, ltz
669
670 ltz = 0.d0
671 if(present(tz)) ltz = tz
672
673 call jd2cal(jd + ltz/24.d0, yr,mon,day) ! UT -> LT
674 dy = floor(day)
675 time = (day - dble(dy)) * 24.d0
676 call tm2hms(time, hr,mn,se)
677 call tm2hm(abs(ltz), tzhr,tzmn)
678
679 tzsign = '+'
680 if(ltz.lt.0.d0) tzsign = '-'
681
682 write(jd2iso8601,'(I0, 7(A1,I2.2) )') yr,'-',mon,'-',dy,'T',hr,':',mn,':',se, tzsign,tzhr,':',tzmn
683
684 end function jd2iso8601
685 !*********************************************************************************************************************************
686
687
688
689 !*********************************************************************************************************************************
690 !> \brief Return JD as date and time in RFC-822 format (e.g. Sat, 07 Sep 2002 23:12:01 +0100)
691 !!
692 !! \param jd Julian day (UT)
693 !! \param tz Time zone (optional - default: 0 = UT)
694 !! \retval jd2rfc822 Date string in RFC-822 format
695
696 elemental function jd2rfc822(jd, tz)
697 use sufr_kinds, only: double
698
699 implicit none
700 real(double), intent(in) :: jd
701 real(double), intent(in), optional :: tz
702 character :: jd2rfc822*(35), tzsign ! Need 31 for -999 <= year <= 9999
703 integer :: dy,yr,mon, hr,mn,se, tzhr,tzmn
704 real(double) :: day, time, ltz
705
706 ! Cannot use these from constants, because of circular dependencies:
707 character, parameter :: endys(0:6)*(3) = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
708 character, parameter :: enmntsb(12)*(3) = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
709
710 ltz = 0.d0
711 if(present(tz)) ltz = tz
712
713 call jd2cal(jd + ltz/24.d0, yr,mon,day) ! UT -> LT
714 dy = floor(day)
715 time = (day - dble(dy)) * 24.d0
716 call tm2hms(time, hr,mn,se)
717 call tm2hm(abs(ltz), tzhr,tzmn)
718
719 tzsign = '+'
720 if(ltz.lt.0.d0) tzsign = '-'
721
722 write(jd2rfc822,'(A,I2.2, A,I5, I3.2,2(A1,I2.2), 1x,A1,2I2.2)') trim(endys(dow_ut(jd+tz/24.d0)))//', ',dy, ' '//enmntsb(mon), yr, &
723 hr,':',mn,':',se, tzsign,tzhr,tzmn
724
725 end function jd2rfc822
726 !*********************************************************************************************************************************
727
728
729
730 !*********************************************************************************************************************************
731 !> \brief Convert a Julian day (UT) to a GPS time (seconds since 1980-01-06 - 2000-01-01 = 630720013.0)
732 !!
733 !! \param jd Julian day (UT)
734 !!
735 !! \todo Check: leap seconds taken into account until 2022.
736 !! \retval jd2gps GPS time
737
738 function jd2gps(jd)
739 use sufr_kinds, only: double
740
741 implicit none
742 real(double), intent(in) :: jd
743 real(double) :: jd1980, jd2gps
744 integer :: nleap
745
746 jd1980 = cal2jd(1980,1,6.d0)
747 jd2gps = (jd - jd1980)*86400.d0 ! GPS time w/o leap seconds
748
749 if(jd.lt.jd1980) &
750 write(0,*) 'Warning: Leap seconds are not taken into account when computing GPS time before 1980-01-06.'
751
752 nleap = 0
753 if(jd.ge.cal2jd(1981,7,1.d0)) nleap = nleap + 1 ! Leap second on 1981-07-01
754 if(jd.ge.cal2jd(1982,7,1.d0)) nleap = nleap + 1 ! Leap second on 1982-07-01
755 if(jd.ge.cal2jd(1983,7,1.d0)) nleap = nleap + 1 ! Leap second on 1983-07-01
756 if(jd.ge.cal2jd(1985,7,1.d0)) nleap = nleap + 1 ! Leap second on 1985-07-01
757 if(jd.ge.cal2jd(1988,1,1.d0)) nleap = nleap + 1 ! Leap second on 1988-01-01
758 if(jd.ge.cal2jd(1990,1,1.d0)) nleap = nleap + 1 ! Leap second on 1990-01-01
759 if(jd.ge.cal2jd(1991,1,1.d0)) nleap = nleap + 1 ! Leap second on 1991-01-01
760 if(jd.ge.cal2jd(1992,7,1.d0)) nleap = nleap + 1 ! Leap second on 1992-07-01
761 if(jd.ge.cal2jd(1993,7,1.d0)) nleap = nleap + 1 ! Leap second on 1993-07-01
762 if(jd.ge.cal2jd(1994,7,1.d0)) nleap = nleap + 1 ! Leap second on 1994-07-01
763 if(jd.ge.cal2jd(1996,1,1.d0)) nleap = nleap + 1 ! Leap second on 1996-01-01
764 if(jd.ge.cal2jd(1997,7,1.d0)) nleap = nleap + 1 ! Leap second on 1997-07-01
765 if(jd.ge.cal2jd(1999,1,1.d0)) nleap = nleap + 1 ! Leap second on 1999-01-01
766 if(jd.ge.cal2jd(2006,1,1.d0)) nleap = nleap + 1 ! Leap second on 2006-01-01
767 if(jd.ge.cal2jd(2009,1,1.d0)) nleap = nleap + 1 ! Leap second on 2009-01-01
768 if(jd.ge.cal2jd(2012,7,1.d0)) nleap = nleap + 1 ! Leap second on 2012-07-01
769 if(jd.ge.cal2jd(2015,7,1.d0)) nleap = nleap + 1 ! Leap second on 2015-07-01
770 if(jd.ge.cal2jd(2017,1,1.d0)) nleap = nleap + 1 ! Leap second on 2017-01-01
771
772 jd2gps = jd2gps + dble(nleap)
773
774 end function jd2gps
775 !*********************************************************************************************************************************
776
777
778 !*********************************************************************************************************************************
779 !> \brief Convert a GPS time to Julian day (UT)
780 !!
781 !! \param GPStime GPS time: seconds since 1980-01-06
782 !! \retval gps2jd Julian day
783 !!
784 !! \todo Check leap seconds since 2009
785 !!
786 !! \note GPS time: seconds since 1980-01-06 - 2000-01-01 = 630720013.0
787
788 function gps2jd(GPStime)
789 use sufr_kinds, only: double
790 implicit none
791 real(double), intent(in) :: gpstime
792 integer :: nleap
793 real(double) :: jd1980, gps2jd
794
795 jd1980 = cal2jd(1980,1,6.d0) ! Start of GPS time
796 gps2jd = gpstime/86400.d0 + jd1980 ! GPS time, w/o leap seconds
797
798 if(gps2jd.lt.jd1980) write(0,*) 'Warning: Leap seconds are not taken into account when computing GPS time before 1980-01-06.'
799
800 nleap = 0
801 if(gps2jd.ge.cal2jd(1981,7,1.d0)) nleap = nleap + 1 ! Leap second on 1981-07-01
802 if(gps2jd.ge.cal2jd(1982,7,1.d0)) nleap = nleap + 1 ! Leap second on 1982-07-01
803 if(gps2jd.ge.cal2jd(1983,7,1.d0)) nleap = nleap + 1 ! Leap second on 1983-07-01
804 if(gps2jd.ge.cal2jd(1985,7,1.d0)) nleap = nleap + 1 ! Leap second on 1985-07-01
805 if(gps2jd.ge.cal2jd(1988,1,1.d0)) nleap = nleap + 1 ! Leap second on 1988-01-01
806 if(gps2jd.ge.cal2jd(1990,1,1.d0)) nleap = nleap + 1 ! Leap second on 1990-01-01
807 if(gps2jd.ge.cal2jd(1991,1,1.d0)) nleap = nleap + 1 ! Leap second on 1991-01-01
808 if(gps2jd.ge.cal2jd(1992,7,1.d0)) nleap = nleap + 1 ! Leap second on 1992-07-01
809 if(gps2jd.ge.cal2jd(1993,7,1.d0)) nleap = nleap + 1 ! Leap second on 1993-07-01
810 if(gps2jd.ge.cal2jd(1994,7,1.d0)) nleap = nleap + 1 ! Leap second on 1994-07-01
811 if(gps2jd.ge.cal2jd(1996,1,1.d0)) nleap = nleap + 1 ! Leap second on 1996-01-01
812 if(gps2jd.ge.cal2jd(1997,7,1.d0)) nleap = nleap + 1 ! Leap second on 1997-07-01
813 if(gps2jd.ge.cal2jd(1999,1,1.d0)) nleap = nleap + 1 ! Leap second on 1999-01-01
814 if(gps2jd.ge.cal2jd(2006,1,1.d0)) nleap = nleap + 1 ! Leap second on 2006-01-01
815 if(gps2jd.ge.cal2jd(2009,1,1.d0)) nleap = nleap + 1 ! Leap second on 2009-01-01
816 if(gps2jd.ge.cal2jd(2012,7,1.d0)) nleap = nleap + 1 ! Leap second on 2012-07-01
817 if(gps2jd.ge.cal2jd(2015,7,1.d0)) nleap = nleap + 1 ! Leap second on 2015-07-01
818 if(gps2jd.ge.cal2jd(2017,1,1.d0)) nleap = nleap + 1 ! Leap second on 2017-01-01
819
820 gps2jd = gps2jd - dble(nleap)/86400.d0 ! Leap s -> days
821
822 end function gps2jd
823 !*********************************************************************************************************************************
824
825
826
827 !*********************************************************************************************************************************
828 !> \brief Convert a Julian day (UT) to Unix time (seconds since 1970-01-01)
829 !!
830 !! \param jd Julian day (UT)
831 !! \retval jd2unix UNIX time
832
833 elemental function jd2unix(jd)
834 use sufr_kinds, only: double
835
836 implicit none
837 real(double), intent(in) :: jd
838 real(double) :: jd2unix
839
840 jd2unix = (jd - 2440587.5d0)*86400 ! jd since 1970-01-01, converted to seconds
841
842 end function jd2unix
843 !*********************************************************************************************************************************
844
845
846
847 !*********************************************************************************************************************************
848 !> \brief Convert UNIX time stamp to Julian day
849 !!
850 !! \param unixTime Unix time: 0 = JD 2440587.5 = 1970-01-01
851 !! \retval unix2jd Julian day
852
853 elemental function unix2jd(unixTime)
854 use sufr_kinds, only: double
855 implicit none
856 real(double), intent(in) :: unixtime
857 real(double) :: unix2jd
858
859 unix2jd = unixtime/86400.d0 + 2440587.5d0
860
861 end function unix2jd
862 !*********************************************************************************************************************************
863
864
865 !*********************************************************************************************************************************
866 !> \brief Return system-clock date and time in (year, month, ..., minute, second and tz)
867 !!
868 !! \param year Year CE (output)
869 !! \param month Month of year (output)
870 !! \param day Day of month (output)
871 !!
872 !! \param hour Hour of day (output)
873 !! \param minute Minute (output)
874 !! \param second Second (output)
875 !! \param ms Millisecond (output)
876 !!
877 !! \param tz Time zone w.r.t. Greenwich in hours - >0 = east (output)
878 !!
879 !! \note If second is present and ms is not, the milliseconds are added as a fraction to the seconds.
880
881 subroutine system_clock_2_ymdhms(year,month,day, hour,minute,second, ms, tz)
882 use sufr_kinds, only: double
883 use sufr_dummy, only: dumstr99
884
885 implicit none
886 integer, intent(out), optional :: year,month,day, hour,minute, ms
887 real(double), intent(out), optional :: second, tz
888 integer :: dt(8)
889
890 call date_and_time(dumstr99,dumstr99,dumstr99, dt)
891
892 if(present(year)) year = dt(1)
893 if(present(month)) month = dt(2)
894 if(present(day)) day = dt(3)
895
896 if(present(hour)) hour = dt(5)
897 if(present(minute)) minute = dt(6)
898
899 if(present(ms)) then
900 if(present(second)) second = dble(dt(7))
901 ms = dt(8)
902 else
903 if(present(second)) second = dble(dt(7)) + dble(dt(8))*1.d-3
904 end if
905
906 if(present(tz)) tz = dble(dt(4))/60.d0
907
908 end subroutine system_clock_2_ymdhms
909 !*********************************************************************************************************************************
910
911
912
913end module sufr_date_and_time
914!***********************************************************************************************************************************
915
Procedures for manipulation of date and time.
elemental real(double) function ymdhms2jd(yy, mmo, dd, h, m, s)
Convert date and time (y,m,d, h,m,s) to JD. Input and output in UT.
elemental integer function dow_iso(jd0)
Calculates ISO day of week (1 = Monday, ..., 7 = Sunday). Output for timezone of input - call dow_ut(...
elemental character function, dimension(30) jd2iso8601(jd, tz)
Return JD as date and time in ISO_8601 format (e.g. 2014-03-24T20:48:01+00:00)
elemental subroutine jd2datetime(jd, year, month, day, time)
Convert a Julian day to a date (y,m,d) and time (UT, h)
elemental real(double) function dtm2jd(yy, mo, dd, time)
Convert date and time (h) to a Julian day - input in UT.
elemental integer function ymd2doy(yr, mon, dy)
Calculate day of year (1-366) from year,month,day.
elemental real(double) function jd2year(jd)
Convert a Julian day to decimal year (e.g. 2000.0)
elemental integer function leapyr(yr)
Calculate whether year is leap (1) or not (0). The number of days in February is then given by 28 + l...
real(double) function gps2jd(gpstime)
Convert a GPS time to Julian day (UT)
elemental subroutine tm2hmss(tm, h, m, s)
Convert time (h) to hours, minutes and (decimal) seconds.
elemental character function, dimension(15) jd2datestr(jd)
Convert a Julian day to a date string (yyyy-mm-dd)
elemental subroutine jd2cal(jd, yy, mm, dd)
Convert a Julian day to a calendar date (fractional day) - in UT.
subroutine system_clock_2_ymdhms(year, month, day, hour, minute, second, ms, tz)
Return system-clock date and time in (year, month, ..., minute, second and tz)
elemental integer function doy(jd0)
Calculate day of year (1-366) from JD.
elemental character function, dimension(35) jd2rfc822(jd, tz)
Return JD as date and time in RFC-822 format (e.g. Sat, 07 Sep 2002 23:12:01 +0100)
elemental subroutine consistent_date_time(year, month, day, hour, minute, second)
Ensure date and time are consistent after manipulation (0<month<13, 0<=minute<60, etc....
elemental real(double) function jd2time(jd)
Convert a Julian day to time (UT, h)
elemental real(double) function jd2unix(jd)
Convert a Julian day (UT) to Unix time (seconds since 1970-01-01)
elemental subroutine tm2hms(tm, h, m, s)
Convert time (h) to hours, minutes and (integer) seconds.
elemental real(double) function unix2jd(unixtime)
Convert UNIX time stamp to Julian day.
elemental subroutine tm2hm(tm, h, m)
Convert time (h) to hours and (integer) minutes.
elemental real(double) function year2jd(year)
Convert a year (with decimals) to a JD. Input and output in UT.
elemental subroutine tm2hmm(tm, h, m)
Convert time (h) to hours and (decimal) minutes.
elemental subroutine doy2md(doy, yr, mon, dy)
Calculate month and day from day of year and year.
elemental integer function dow_ut(jd0)
Calculates day of week (0 = Sunday, ..., 6 = Saturday). Output for timezone of input - call dow_ut(jd...
real(double) function jd2gps(jd)
Convert a Julian day (UT) to a GPS time (seconds since 1980-01-06 - 2000-01-01 = 630720013....
elemental subroutine jd2ymdhms(jd, yy, mm, d, h, m, s)
Convert a Julian day to date and time (h,m,s, UT)
elemental real(double) function cal2jd(yy, mm, dd)
Convert a calendar date to JD. Input and output in UT.
Module containing dummy variables for all kinds.
character, dimension(99) dumstr99
Dummy string of length 99.
Provides kinds and related constants/routines.
Definition kinds.f90:26
integer, parameter double
Double-precision float. Precision = 15, range = 307.
Definition kinds.f90:35
integer, parameter dbl
Double-precision float. Precision = 15, range = 307.
Definition kinds.f90:36
integer, parameter long
Long integer.
Definition kinds.f90:31