ncdf_times.R 4.41 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
`ncdf_times` <-
function(nc, as.Rdate=TRUE, force=TRUE, tz="CET") {
    # this function converts netcdf times to the 
    # R date-time format or to the udunits dates
    # you can choose to switch to uduints format
    # for gregorian calendars by setting as.Rdate
    # to FALSE
    # non-gregorian calendar dates are output using 
    # udunits date format
    
    # you can force to get back an R date format, even
    # if the calendar used is not gregorian using
    # force=T (may return udunits dates if conversion
    # is not successful)
    
    # WARNING: time zones are not fully supported yet
    
    # check whether udunits is available
    .udunitsInclude     <- FALSE
    if (any(.packages() == "udunits") & class(try(utInit(), silent=T)) != "try-error"){
        .udunitsInclude <- TRUE
    }
    
    timei   <- which(names(nc$dim) %in% c("time", "TIME", "tim", "TIM"))
    units   <- nc$dim[[timei]]$units
    vals    <- nc$dim[[timei]]$vals
    tmp     <- ncatt_get(nc, names(nc$dim)[timei], "calendar")
    if (tmp$hasatt) {
        calendar <- tmp$value
    } else {
        calendar <- "standard"
        print(paste("Warning: Calendar is missing in", nc$filename))
    }    
    if (calendar == "proleptic_gregorian") calendar <- "standard"
    
    if (as.Rdate & calendar == "standard"){

        if (charmatch("hours since", units, nomatch=0) | 
            charmatch("minutes since", units, nomatch=0) |
            charmatch("seconds since", units, nomatch=0)) {

            mul <- 1
            ref.txt     <- substr(units, 15,33)
            if (charmatch("minutes", units, nomatch=0)) mul     <- 60
            if (charmatch("hours", units, nomatch=0)) {
                mul     <- 3600
                ref.txt <- substr(units, 13,31)
            }

            times       <- vals * mul
            if (nchar(ref.txt) == 19){
                ref         <- as.POSIXct(ref.txt, tz)
            } else {
                ref         <- as.POSIXct(paste(ref.txt, "00", sep=":"), tz)
            }   
            time        <- as.Date(ref + times)

        }  
        if (charmatch("days since", units, nomatch=0)){
            time        <- as.Date(substr(units, 12,21), "%Y-%m-%d") + vals
        }
        if (charmatch("months since", units, nomatch=0)) {
            ref.yr      <- as.numeric(substr(units, 14,17))
            ref.month   <- as.numeric(substr(units, 19,20))
            ref.day     <- as.numeric(substr(units, 22,23))
            if (is.null(ref.day)) ref.day <- 1

            month       <- floor((vals+ref.yr*12 + ref.month-1) %% 12) + 1
            year        <- floor((vals+ref.yr*12 + ref.month-1)/12) 
            
            time        <- as.Date(ISOdate(year, month, ref.day))
        } 
        if (charmatch("years since", units, nomatch=0)) {
            unit.tmp    <- paste(strsplit(units, " ")[[1]][3:4], collapse=" ")
            #ref.yr      <- substr(units, 13,16)
            #ref.month   <- as.numeric(substr(units, 18,19))
            ref.yr      <- as.numeric(format(as.Date(unit.tmp), "%Y"))
            ref.month   <- as.numeric(format(as.Date(unit.tmp), "%m"))
            if (is.null(ref.month)) ref.month <- 1
            #ref.day     <- as.numeric(substr(units, 21,22))
            ref.day     <- as.numeric(format(as.Date(unit.tmp), "%d"))
            if (is.null(ref.day)) ref.day <- 1

            year        <- floor(vals)
            month       <- floor((vals*12)%%12)

            time        <- as.Date(ISOdate(ref.yr + year, ref.month + month, ref.day))
        }  
        if (charmatch("day as", units, nomatch=0)) {
            date        <- floor(vals)
            day         <- as.numeric(substr(date, nchar(date)-1, nchar(date)))
            if (all(day > 28)) date <- as.character(as.numeric(date) - max(day, na.rm=T) + 28)
            date        <- paste("000",date, sep="")
            date        <- substr(date, nchar(date)-7, nchar(date))
            time        <- as.Date(date, "%Y%m%d")
        }

    } else {
        if (.udunitsInclude){
            time <- utCalendar(vals, units, calendar=calendar, style="array")  
            if (force){
                tmp  <- try(ISOdatetime(time$year, time$month, time$day, time$hour, 
                    time$minute, time$second, tz), silent=T)
                if (class(tmp)[1] != "try-error") time <- tmp
            }
        } else {
            stop("Package udunits cannot be loaded or initialized via utInit()")
        }
    }


    time
        
}