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
Alternate Geom_Text Position with Hjust
Have Lubridate Subtraction Return Only a Numeric Value
Adding Regression Line Equation and R2 on Separate Lines Graph
Porting Set Operations from R's Data Frames to Data Tables: How to Identify Duplicated Rows
With the R Package Xlsx, How to Set Na.Strings When Reading an Excel File
Scale_Y_Log10() and Coord_Trans(Ytrans = 'Log10') Lead to Different Results
R: Data.Table Count !Na Per Row
Use Href Infobox as Actionbutton
Plotting a 95% Confidence Interval for a Lm Object
R Data.Table Join on Conditionals
Reshape Long Structured Data.Table into a Wide Structure Using Data.Table Functionality
How to Flip Rows and Columns in R
R: Save Multiple Plots from a File List into a Single File (Png or PDF or Other Format)
Convert Lat/Lon to Zipcode/Neighborhood Name
Error in Unserialize(Socklist[[N]]):Error Reading from Connection on Unix
How to Convert .Rdata Format into Text File Format