Convert a Netcdf Time Variable to an R Date Object

convert a netcdf time variable to an R date object

I have just discovered (two years after posting the question!) that there is a package called ncdf.tools which has the function:

convertDateNcdf2R

which

converts a time vector from a netCDF file or a vector of Julian days
(or seconds, minutes, hours) since a specified origin into a POSIXct R
vector.

Usage:

convertDateNcdf2R(time.source, units = "days", origin = as.POSIXct("1800-01-01", 
tz = "UTC"), time.format = c("%Y-%m-%d", "%Y-%m-%d %H:%M:%S",
"%Y-%m-%d %H:%M", "%Y-%m-%d %Z %H:%M", "%Y-%m-%d %Z %H:%M:%S"))

Arguments:

time.source 

numeric vector or netCDF connection: either a number of time units since origin or a netCDF file connection, In the latter case, the time vector is extracted from the netCDF file, This file, and especially the time variable, has to follow the CF netCDF conventions.

units   

character string: units of the time source. If the source is a netCDF file, this value is ignored and is read from that file.

origin  

POSIXct object: Origin or day/hour zero of the time source. If the source is a netCDF file, this value is ignored and is read from that file.

Thus it is enough to simply pass the netcdf connection as the first argument and the function handles the rest. Caveat: This will only work if the netCDF file follows CF conventions (e.g. if your units are "years since" instead of "seconds since" or "days since" it will fail for example).

More details on the function are available here:
https://rdrr.io/cran/ncdf.tools/man/convertDateNcdf2R.html

How to effectively convert NCDF time into proper units

I had similar issues with the different types of calendars but after I discovered the package ncdf4.helpers, everything is much easier and faster now. An example:

 > library(ncdf4)
> #open the netcdf file
> ncin<- nc_open("precip_GPCP_1998.nc")

> library(ncdf4.helpers)
> #obtain time dimension in date format
> Time_in_Date_format <- nc.get.time.series(f = ncin,
time.dim.name = "time")

> nc_close(ncin)

> Time_in_Date_format
[1] "1998-01-01" "1998-02-01" "1998-03-01" "1998-04-01" "1998-05-01"
[6] "1998-06-01" "1998-07-01" "1998-08-01" "1998-09-01" "1998-10-01"
[11] "1998-11-01" "1998-12-01"

How to convert numeric numbers into a normal date?

Date

If A are hours since "1900-01-01", just divide them by 24, and pass this date into the origin parameter within the as.Date function, as in

A <- c(990552, 990558, 990564, 990570, 990576, 990582)
as.Date(A/24, origin = "1900-01-01")
## [1] "2013-01-01" "2013-01-01" "2013-01-01" "2013-01-01" "2013-01-02" "2013-01-02"

Date + time

If you want the hours too, use as.POSIXct instead and multiply by 3600 (You should probably specify your time zone too within tz parameter)

as.POSIXct(A*3600, origin = "1900-01-01")
## [1] "2013-01-01 02:00:00 IST" "2013-01-01 08:00:00 IST" "2013-01-01 14:00:00 IST" "2013-01-01 20:00:00 IST" "2013-01-02 02:00:00 IST" "2013-01-02 08:00:00 IST"

Time zone

In order to know your time zone, type

Sys.timezone()

For a full list of possible time zones, type

OlsonNames()

Adding/Removing hours

Either way, you can remove/add hours by multiplying the number of hours by 3600 and adding/removing from the results, for example

as.POSIXct(A*3600, origin = "1900-01-01") - 2*3600

Netcdf dataset conversion from seconds from starting time to utc hours

Since you extract time from the variables in time=f.variables['time'][:], it will lose it's associated unit (time is just a masked array, as the error says).
What you have to feed to num2date() is variables['time'].units, e.g.

from netCDF4 import date2num, num2date, Dataset
file = ... # your nc file

with Dataset(file) as root:
time = root.variables['time'][:]
dates = num2date(time, root.variables['time'].units)
## directly get UTC hours here:
# unit_utchours = root.variables['time'].units.replace('seconds', 'hours')
## would e.g. be 'hours since 2019-08-15 00:00:00'
# utc_hours = date2num(dates, unit_utchours)

# check:
print(dates[0].strftime('%Y%m%d%H'))
# e.g. prints 2019081516

...to get the dates as a number, you could e.g. do

num_dates = [int(d.strftime('%Y%m%d%H')) for d in dates]
# replace int with float if you need floating point numbers etc.

...to get the dates in UTC hours, see the commented section in the first code block. Since the dates array contains objects of type datetime.datetime, you could also do

utc_hours = [d.hour+(d.minute/60)+(d.second/3600) for d in dates]

R: Convert list of character dates to days since a given origin

Convert dates to Date class, subtract o and convert that to numeric:

as.numeric(as.Date(dates) - o)
## [1] 18627 18658 18686 18717 18747 18778 18808 18839 18870 18900 18931 18961

Alternately convert both to numeric:

as.numeric(as.Date(dates)) - as.numeric(o)

or use difftime

as.numeric(difftime(as.Date(dates), o, unit = "day"))


Related Topics



Leave a reply



Submit