mjwoods / RNetCDF

Read and write netcdf format in R
Other
24 stars 9 forks source link

An error occurred while using the utcal.nc function to converte the time amounts to UTC date. #144

Closed PanfengZhang closed 4 months ago

PanfengZhang commented 5 months ago

An error occurred while using the utcal.nc function to converte the time amounts to UTC date.

The example of .nc data is from NCEP (https://psl.noaa.gov/thredds/fileServer/Datasets/ncep.reanalysis/Monthlies/surface/slp.mon.ltm.1991-2020.nc)

library(RNetCDF)

diri = "C:/Rmet/data/slp.mon.ltm.1991-2020.nc"
fin <- open.nc(diri)
time <- var.get.nc(fin, variable = "time")
time_units <- att.get.nc(fin, variable = "time", attribute = "units")

utcal.nc(time_units, time, type = "c")
##  [1] "0000-12-30 UTC" "0001-01-30 UTC" "0001-02-27 UTC" "0001-03-30 UTC"
##  [5] "0001-04-29 UTC" "0001-05-30 UTC" "0001-06-29 UTC" "0001-07-30 UTC"
##  [9] "0001-08-30 UTC" "0001-09-29 UTC" "0001-10-30 UTC" "0001-11-29 UTC"

utcal.nc(time_units, time, type = "s")
##  [1] "01-01-01 00:00:00" "01-02-01 00:00:00" "01-03-01 00:00:00"
##  [4] "01-04-01 00:00:00" "01-05-01 00:00:00" "01-06-01 00:00:00"
##  [7] "01-07-01 00:00:00" "01-08-01 00:00:00" "01-09-01 00:00:00"
## [10] "01-10-01 00:00:00" "01-11-01 00:00:00" "01-12-01 00:00:00"

When the type parameter is set to n or s, the returned dates are inconsistent. According to the metadata information of the data, it is known that it is correct when setting s.

mjwoods commented 5 months ago

Hi @PanfengZhang ,

I think you should get consistent results with type="s" and type="n". The "n" option shows the numeric values of year, month, day, etc., which should match the strings from the "s" option.

With type="c", the conversion uses the udunits2 library to convert the time values to units of "seconds since 1970-01-01 00:00:00 +00:00", which is the reference date for POSIXct. Unfortunately, udunits2 and R interpret the resulting time values using different calendars, so when R displays the times as strings, the dates appear inconsistent.

This is not strictly a bug in RNetCDF or udunits2, because there is no general agreement on time conversions before the Gregorian calendar came into operation in year 1582. For more explanation, please see https://docs.unidata.ucar.edu/udunits/current/udunits2lib.html#Time (along with the R help for utcal.nc).

You can workaround the problem by converting the times using as.POSIXct as follows:

> as.POSIXct(utcal.nc(time_units, time, type = "s"))
 [1] "0001-01-01 LMT" "0001-02-01 LMT" "0001-03-01 LMT" "0001-04-01 LMT"
 [5] "0001-05-01 LMT" "0001-06-01 LMT" "0001-07-01 LMT" "0001-08-01 LMT"
 [9] "0001-09-01 LMT" "0001-10-01 LMT" "0001-11-01 LMT" "0001-12-01 LMT"

When R displays the above times as strings, they match the strings passed in. However, the numeric values of the times (in seconds since 1970) will be different from those produced by udunits2.

PanfengZhang commented 5 months ago

Thank you for your detailed answer.