convert a netcdf time variable to an R date object

前端 未结 3 1261
孤街浪徒
孤街浪徒 2021-01-01 00:55

I have a netcdf file with a timeseries and the time variable has the following typical metadata:

    double time(time) ;
            time:standard_name = \"t         


        
3条回答
  •  孤独总比滥情好
    2021-01-01 01:43

    I couldn't get @AF7's function to work with my files so I wrote my own. The function below creates a POSIXct vector of dates, for which the start date, time interval, unit and length are read from the nc file. It works with nc files of many (but probably not every...) shapes or forms.

     ncdate <- function(nc) {
        ncdims <- names(nc$dim) #Extract dimension names
        timevar <- ncdims[which(ncdims %in% c("time", "Time", "datetime", "Datetime",
                                              "date", "Date"))[1]] # Pick the time dimension
        ntstep <-nc$dim[[timevar]]$len
        tm <- ncvar_get(nc, timevar) # Extract the timestep count
        tunits <- ncatt_get(nc, timevar, "units") # Extract the long name of units
        tspace <- tm[2] - tm[1] # Calculate time period between two timesteps, for the "by" argument 
        tstr <- strsplit(tunits$value, " ") # Extract string components of the time unit
        a<-unlist(tstr[1]) # Isolate the unit .i.e. seconds, hours, days etc.
        uname <- a[which(a %in% c("seconds","hours","days"))[1]] # Check unit
        startd <- as.POSIXct(gsub(paste(uname,'since '),'',tunits$value),format="%Y-%m-%d %H:%M:%S") ## Extract the start / origin date
        tmulti <- 3600 # Declare hourly multiplier for date
        if (uname == "days") tmulti =86400 # Declare daily multiplier for date
        ## Rename "seconds" to "secs" for "by" argument and change the multiplier.
        if (uname == "seconds") {
            uname <- "secs"
            tmulti <- 1 }
        byt <- paste(tspace,uname) # Define the "by" argument
        if (byt == "0.0416666679084301 days") { ## If the unit is "days" but the "by" interval is in hours
        byt= "1 hour"                       ## R won't understand "by < 1" so change by and unit to hour.
        uname = "hours"}
        datev <- seq(from=as.POSIXct(startd+tm[1]*tmulti),by= byt, units=uname,length=ntstep)
    }
    

    Edit

    To address the flaw highlighted by @AF7's comment that the above code would only work for regularly spaced files, datev could be calculated as

     datev <- as.POSIXct(tm*tmulti,origin=startd)
    

提交回复
热议问题