SURFEX v8.1
General documentation of Surfex
mode_dates_netcdf.F90
Go to the documentation of this file.
1 !SFX_LIC Copyright 1994-2014 CNRS, Meteo-France and Universite Paul Sabatier
2 !SFX_LIC This is part of the SURFEX software governed by the CeCILL-C licence
3 !SFX_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
4 !SFX_LIC for details. version 1.
6 
7 ! Module to read correctly time in a netcdf file
8 
9 ! Author : Matthieu Lafaysse
10 ! Creation : 2012-11-12
11 
12 ! Modifications
13 
15 
16 USE yomhook ,ONLY : lhook, dr_hook
17 USE parkind1 ,ONLY : jprb
18 
19 IMPLICIT NONE
20 
21 INTEGER,PARAMETER::jp_gregoire=1582 !Année où le pape Grégoire XIII décida de passer du calendrier julien au calendrier grégorien
22 !Avant cette date tous les années multiples de 4 sont des années bissextiles
23 !Au-delà de cette date les années multiples de 100 ne sont pas bissextiles sauf les années multiples de 400 qui le sont
24 !De plus les journées du 5 au 14 octobre 1582 ont été supprimées pour compenser le retard accumulé
25 
26 
27 CONTAINS
28 
29 !----------------------------------------------------------------------------------------------------------------
30 
31 
32 SUBROUTINE netcdf2date(PTIME,HUNITS,PDATETIME)
33 !
34 ! Conversion de la date au format netcdf vers le format année mois jour heure selon dimension de itv_date
35 REAL,DIMENSION(:),INTENT(IN) :: PTIME
36  CHARACTER(*),INTENT(IN) :: HUNITS
37 type(date_time),DIMENSION(:),INTENT(OUT) :: pdatetime
38 !
39 INTEGER,DIMENSION(SIZE(PTIME)) :: ITIMEHOURS
40 REAL,DIMENSION(SIZE(PTIME)) :: ZREST
41 INTEGER :: IYEARUNITS,IMONTHUNITS,IDAYUNITS,IHOURUNITS
42 !
43  CHARACTER(LEN=14) :: YHEADER
44  CHARACTER(LEN=100) :: YFMT
45  CHARACTER :: YC1,YC2,YC3
46 !
47 LOGICAL :: GHEADER
48 !
49 INTEGER,DIMENSION(4),PARAMETER :: ITV_DATEREF = (/1900,1,1,0/)
50 INTEGER,DIMENSION(4),PARAMETER :: ITV_DATEREFBIS = (/1850,1,1,0/)
51 !
52 INTEGER,DIMENSION(4) :: ITV_DATETEMPO
53 INTEGER :: ICARACUNITS,ICARACHOUR,ICARACDAY,ICARACMONTH,ICARACYEAR
54 INTEGER :: IERROR
55 INTEGER :: JTIME
56 INTEGER :: IV_DIFFREF
57 !
58 REAL(KIND=JPRB) :: ZHOOK_HANDLE
59 !
60 IF (lhook) CALL dr_hook('MODE_DATES_NETCDF:NETCDF2DATE',0,zhook_handle)
61 !
62 SELECT CASE (hunits(1:4))
63  CASE ("days")
64  icaracunits = 11
65  itimehours = int(ptime*24.)
66  zrest = ptime*24.-itimehours
67  CASE ("hour")
68  icaracunits = 12
69  itimehours = int(ptime)
70  zrest = ptime-itimehours
71  CASE ("minu")
72  icaracunits = 14
73  itimehours = int(ptime/60.)
74  zrest = (ptime/60.)-itimehours
75  CASE ("seco")
76  icaracunits = 14
77  itimehours = int(ptime/3600.)
78  zrest = (ptime/3600.)-itimehours
79  CASE DEFAULT
80  print*, "ERROR date_netcdf.F90 : Can't read time units :"
81  print*,trim(hunits)
82  stop "Error units time"
83 END SELECT
84 
85 SELECT CASE (hunits(1:4))
86  !CASE ("days")
87  ! !Read reference date
88  ! boucles_days:DO ICARACDAY=1,2 !Day written by 1 or 2 char
89  ! DO ICARACMONTH=1,2 !Month written by 1 or 2 char
90  ! DO ICARACYEAR=1,4 !Year written by 1 to 4 char
91  ! WRITE(YFMT,FMT='("(A",I2,",",2("I",I1,",A1,"),"I",I1,",X,I",I1,",A1)")')&
92  ! ICARACUNITS,ICARACYEAR,ICARACMONTH,ICARACDAY,ICARACHOUR
93  ! READ(HUNITS,FMT=YFMT,IOSTAT=IERROR)YHEADER,IYEARUNITS,YC1,IMONTHUNITS,YC2,IDAYUNITS,IHOURUNITS,YC3
94  ! IHOURUNITS=0
95  ! IF (IERROR==0) THEN
96  ! IF ((TRIM(YHEADER)=='days since').AND.(YC1=='-').AND.(YC2=='-').AND.(YC3==':')) THEN
97  ! ! PRINT*,"DATE DE REFERENCE LUE :"
98  ! ! PRINT*,itv_oldref
99  ! EXIT boucles_days
100  ! END IF
101  ! END IF
102  ! END DO
103  ! END DO
104  ! END DO boucles_days
105  CASE ("days","hour","minu","seco")
106  !Read reference date
107  boucles_hours:DO icarachour=1,2 !Hour written by 1 or 2 char
108  DO icaracday=1,2 !Day written by 1 or 2 char
109  DO icaracmonth=1,2 !Month written by 1 or 2 char
110  DO icaracyear=1,4 !Year written by 1 to 4 char
111  WRITE(yfmt,fmt='("(A",I2,",",2("I",I1,",A1,"),"I",I1,",X,I",I1,",A1)")')&
112  icaracunits,icaracyear,icaracmonth,icaracday,icarachour
113  READ(hunits,fmt=yfmt,iostat=ierror)yheader,iyearunits,&
114  yc1,imonthunits,yc2,idayunits,ihourunits,yc3
115  IF (ierror==0) THEN
116  gheader=(trim(yheader)=='hours since') .OR. (trim(yheader)=='minutes since') .OR. &
117  (trim(yheader)=='seconds since') .OR. (trim(yheader)=='days since')
118  IF (gheader.AND.(yc1=='-').AND.(yc2=='-').AND.(yc3==':')) THEN
119  ! PRINT*,"DATE DE REFERENCE LUE :"
120  ! PRINT*,itv_oldref
121  EXIT boucles_hours
122  END IF
123  END IF
124  END DO
125  END DO
126  END DO
127  END DO boucles_hours
128  CASE DEFAULT
129  stop "Error units time"
130 END SELECT
131 
132 
133 
134 !Check successful reading
135 IF (ierror>0) THEN
136  print*, "ERROR date_netcdf.F90 : Can't read time units :"
137  print*,trim(hunits)
138  stop "Error units time"
139 END IF
140 
141 DO jtime=1,SIZE(ptime)
142  !Initialiaze the date to the reference date
143  pdatetime(jtime)%TDATE%YEAR = iyearunits
144  pdatetime(jtime)%TDATE%MONTH = imonthunits
145  pdatetime(jtime)%TDATE%DAY = idayunits
146  pdatetime(jtime)%TIME = ihourunits+zrest(jtime)
147  CALL addhours(pdatetime(jtime),itimehours(jtime))
148 END DO
149 
150 IF (lhook) CALL dr_hook('MODE_DATES_NETCDF:NETCDF2DATE',1,zhook_handle)
151 
152 END SUBROUTINE netcdf2date
153 !----------------------------------------------------------------------------------------------------------------
154 
155 !--------------------------------------------------------------------------------------------------------------
156 LOGICAL FUNCTION leapyear (PYEAR)
157 INTEGER, INTENT(IN) :: PYEAR ! Is the year a leap year ?
158 REAL(KIND=JPRB) :: ZHOOK_HANDLE
159 
160 IF (lhook) CALL dr_hook('MODE_DATES_NETCDF:LEAPYEAR',0,zhook_handle)
161 
162 IF (pyear>jp_gregoire) THEN
163  leapyear = (((mod(pyear,4)==0).AND.(mod(pyear,100)/=0)).OR.(mod(pyear,400)==0))
164 ELSE
165  leapyear = (mod(pyear,4)==0)
166 ENDIF
167 
168 IF (lhook) CALL dr_hook('MODE_DATES_NETCDF:LEAPYEAR',1,zhook_handle)
169 
170 END FUNCTION leapyear
171 !--------------------------------------------------------------------------------------------------------------
172 
173 !--------------------------------------------------------------------------------------------------------------
174 SUBROUTINE addhours (TPTIME,KNHOURS)
175 !Add the number of hours to a date
176 TYPE(date_time),INTENT(INOUT)::TPTIME
177 INTEGER,INTENT(IN)::KNHOURS ! number of hours
178 INTEGER,DIMENSION(12)::INBDM !Number of days per months
179 INTEGER::IREMAININGDAYS !Number of remaining days to add
180 REAL(KIND=JPRB) :: ZHOOK_HANDLE
181 
182 IF (lhook) CALL dr_hook('MODE_DATES_NETCDF:ADDHOURS',0,zhook_handle)
183 
184 !special case of 1582
185 IF (tptime%TDATE%YEAR==jp_gregoire) THEN
186  inbdm=(/31,28,31,30,31,30,31,31,30,21,30,31/)
187 ELSE
188  IF (leapyear(tptime%TDATE%YEAR)) THEN
189  inbdm=(/31,29,31,30,31,30,31,31,30,31,30,31/)
190  ELSE
191  inbdm=(/31,28,31,30,31,30,31,31,30,31,30,31/)
192  ENDIF
193 ENDIF
194 
195 IF (knhours>=0) THEN
196  !Increase hour
197  IF ((int(tptime%TIME)+knhours)<=23) THEN
198  tptime%TIME=tptime%TIME+knhours
199  ELSE
200  iremainingdays=(int(tptime%TIME)+knhours)/24 !Number of remaining days
201  tptime%TIME=mod(int(tptime%TIME)+knhours,24)+tptime%TIME-int(tptime%TIME) ! new hour (+minutes)
202  !Increase days
203  DO
204  IF ((tptime%TDATE%DAY+iremainingdays)<=inbdm(tptime%TDATE%MONTH)) THEN
205  tptime%TDATE%DAY=tptime%TDATE%DAY+iremainingdays
206  EXIT
207  ELSE
208  iremainingdays=iremainingdays-(inbdm(tptime%TDATE%MONTH)-tptime%TDATE%DAY+1)
209  IF (tptime%TDATE%MONTH<12) THEN
210  tptime%TDATE%MONTH=tptime%TDATE%MONTH+1 !Month change
211  tptime%TDATE%DAY=1
212  ELSE
213  !Year change
214  tptime%TDATE%YEAR=tptime%TDATE%YEAR+1
215  tptime%TDATE%MONTH=1
216  tptime%TDATE%DAY=1
217  !Update february number of days
218  IF (leapyear(tptime%TDATE%YEAR)) inbdm(2)=29
219  IF (leapyear(tptime%TDATE%YEAR-1)) inbdm(2)=28
220  !Update october month for 1582 and 1583
221  IF (tptime%TDATE%YEAR==jp_gregoire) inbdm(10)=21
222  IF (tptime%TDATE%YEAR==jp_gregoire+1) inbdm(10)=31
223  ENDIF
224  ENDIF
225  ENDDO
226  ENDIF
227 ELSE
228  IF ((int(tptime%TIME)+knhours)>=0) THEN
229  tptime%TIME=tptime%TIME+knhours
230  ELSE
231  iremainingdays=(int(tptime%TIME)-knhours)/24+1
232  tptime%TIME=mod(int(tptime%TIME)-knhours,24)+tptime%TIME-int(tptime%TIME) ! new hour
233  ! decrease days
234  DO
235  IF ((tptime%TDATE%DAY-iremainingdays)>=1) THEN
236  tptime%TDATE%DAY=tptime%TDATE%DAY-iremainingdays
237  EXIT
238  ELSE
239  iremainingdays=iremainingdays-tptime%TDATE%DAY
240  IF (tptime%TDATE%MONTH>=1) THEN
241  tptime%TDATE%MONTH=tptime%TDATE%MONTH-1 !Month change
242  tptime%TDATE%DAY=inbdm(tptime%TDATE%MONTH)
243  ELSE
244  !Year change
245  tptime%TDATE%YEAR=tptime%TDATE%YEAR-1
246  tptime%TDATE%MONTH=12
247  tptime%TDATE%DAY=inbdm(tptime%TDATE%MONTH)
248  !Update february number of days
249  IF (leapyear(tptime%TDATE%YEAR)) inbdm(2)=29
250  IF (leapyear(tptime%TDATE%YEAR+1)) inbdm(2)=28
251  !Update october month for 1582 and 1583
252  IF (tptime%TDATE%YEAR==jp_gregoire) inbdm(10)=21
253  IF (tptime%TDATE%YEAR==jp_gregoire-1) inbdm(10)=31
254  END IF
255  END IF
256  END DO
257  END IF
258 END IF
259 
260 IF (lhook) CALL dr_hook('MODE_DATES_NETCDF:ADDHOURS',1,zhook_handle)
261 
262 END SUBROUTINE addhours
263 !--------------------------------------------------------------------------------------------------------------
264 
265 END MODULE mode_dates_netcdf
subroutine netcdf2date(PTIME, HUNITS, PDATETIME)
integer, parameter jp_gregoire
logical function leapyear(PYEAR)
integer, parameter jprb
Definition: parkind1.F90:32
logical lhook
Definition: yomhook.F90:15
subroutine addhours(TPTIME, KNHOURS)