0

This works for me in R:

# Setting up the first inner while-loop controller, the start of the next water year
  NextH2OYear <- as.POSIXlt(firstDate)
  NextH2OYear$year <- NextH2OYear$year + 1
  NextH2OYear<-as.Date(NextH2OYear)

But this doesn't:

# Setting up the first inner while-loop controller, the start of the next water month
  NextH2OMonth <- as.POSIXlt(firstDate)
  NextH2OMonth$mon <- NextH2OMonth$mon + 1
  NextH2OMonth <- as.Date(NextH2OMonth)

I get this error:

Error in as.Date.POSIXlt(NextH2OMonth) : zero length component in non-empty POSIXlt structure

Any ideas why? I need to systematically add one year (for one loop) and one month (for another loop) and am comparing the resulting changed variables to values with a class of Date, which is why they are being converted back using as.Date().

Thanks, Tom

Edit:

Below is the entire section of code. I am using RStudio (version 0.97.306). The code below represents a function that is passed an array of two columns (Date (CLass=Date) and Discharge Data (Class=Numeric) that are used to calculate the monthly averages. So, firstDate and lastDate are class Date and determined from the passed array. This code is adapted from successful code that calculates the yearly averages - there maybe one or two things I still need to change over, but I am prevented from error checking later parts due to the early errors I get in my use of POSIXlt. Here is the code:

MonthlyAvgDischarge<-function(values){  

  #determining the number of values - i.e. the number of rows
  dataCount <- nrow(values)

  # Determining first and last dates
  firstDate <- (values[1,1])
  lastDate <- (values[dataCount,1])

  # Setting up vectors for results
  WaterMonths <- numeric(0)
  class(WaterMonths) <- "Date"
  numDays <- numeric(0)
  MonthlyAvg <- numeric(0)

  # while loop variables
  loopDate1 <- firstDate
  loopDate2 <- firstDate

  # Setting up the first inner while-loop controller, the start of the next water month
  NextH2OMonth <- as.POSIXlt(firstDate)
  NextH2OMonth$mon <- NextH2OMonth$mon + 1
  NextH2OMonth <- as.Date(NextH2OMonth)

  # Variables used in the loops
  dayCounter <- 0
  dischargeTotal <- 0
  dischargeCounter <- 1
  resultsCounter <- 1
  loopCounter <- 0
  skipcount <- 0

  # Outer while-loop, controls the progression from one year to another
  while(loopDate1 <= lastDate)
  {
    # Inner while-loop controls adding up the discharge for each water year
    # and keeps track of day count
    while(loopDate2 < NextH2OMonth)
    {
      if(is.na(values[resultsCounter,2]))
      {
        # Skip this date
        loopDate2  <- loopDate2 + 1
        # Skip this value
        resultsCounter <- resultsCounter + 1
        #Skipped counter
        skipcount<-skipcount+1
      } else{
        # Adding up discharge
        dischargeTotal <- dischargeTotal + values[resultsCounter,2]
      }

      # Adding a day
      loopDate2  <- loopDate2 + 1
      #Keeping track of days
      dayCounter <- dayCounter + 1
      # Keeping track of Dicharge position
      resultsCounter <- resultsCounter + 1
    }

    # Adding the results/water years/number of days into the vectors
    WaterMonths <- c(WaterMonths, as.Date(loopDate2, format="%mm/%Y"))
    numDays <- c(numDays, dayCounter)
    MonthlyAvg <- c(MonthlyAvg, round((dischargeTotal/dayCounter), digits=0))

    # Resetting the left hand side variables of the while-loops 
    loopDate1 <- NextH2OMonth
    loopDate2 <- NextH2OMonth

    # Resetting the right hand side variable of the inner while-loop
    # moving it one year forward in time to the next water year
    NextH2OMonth <- as.POSIXlt(NextH2OMonth)
    NextH2OMonth$year <- NextH2OMonth$Month + 1
    NextH2OMonth<-as.Date(NextH2OMonth)

    # Resettting vraiables that need to be reset
    dayCounter <- 0 
    dischargeTotal <- 0
    loopCounter <- loopCounter + 1
  } 

  WaterMonths <- format(WaterMonthss, format="%mm/%Y")
  # Uncomment the line below and return AvgAnnualDailyAvg if you want the water years also 
  # AvgAnnDailyAvg <- data.frame(WaterYears, numDays, YearlyDailyAvg) 
  return((MonthlyAvg))
}  

Same error occurs in regular R. When doing it line by line, its not a problem, when running it as a script, it it.

traggatmot
  • 1,423
  • 5
  • 26
  • 51

3 Answers3

1

Plain R

seq(Sys.Date(), length = 2, by = "month")[2]
seq(Sys.Date(), length = 2, by = "year")[2]

Note that this works with POSIXlt too, e.g.

seq(as.POSIXlt(Sys.Date()), length = 2, by = "month")[2]

mondate.

library(mondate)
now <- mondate(Sys.Date())
now + 1  # date in one month
now + 12  # date in 12 months

Mondate is bit smarter about things like mondate("2013-01-31")+ 1 which gives last day of February whereas seq(as.Date("2013-01-31"), length = 2, by = "month")[2] gives March 3rd.

yearmon If you don't really need the day part then yearmon may be preferable:

library(zoo)
now.ym <- yearmon(Sys.Date())
now.ym + 1/12 # add one month
now.ym + 1 # add one year

ADDED comment on POSIXlt and section on yearmon.

G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
  • If I can't get POSIXlt to work, it looks linke Mondate will be my solution. – traggatmot Feb 13 '13 at 06:33
  • @traggatmot, I have added a commemt on how to use POSIXlt and also added a solution for `yearmon` which might be preferable if you don't really need the day part. – G. Grothendieck Feb 13 '13 at 12:15
0

Here is you can add 1 month to a date in R, using package lubridate:

library(lubridate)
x <- as.POSIXlt("2010-01-31 01:00:00")
month(x) <- month(x) + 1

>x
[1] "2010-03-03 01:00:00 PST"

(note that it processed the addition correctly, as 31st of Feb doesn't exist).

Victor K.
  • 4,054
  • 3
  • 25
  • 38
  • Using lubridate appears possible, but would muddle my code by having to make me control and keep track of the days in each month while also worrying about leap years, when the method I was intending to use handle those things. Or at least it should have. – traggatmot Feb 13 '13 at 06:32
0

Can you perhaps provide a reproducible example? What's in firstDate, and what version of R are you using? I do this kind of manipulation of POSIXlt dates quite often and it seems to work:

Sys.Date()
# [1] "2013-02-13"
date = as.POSIXlt(Sys.Date())
date$mon = date$mon + 1
as.Date(date)
# [1] "2013-03-13"
Charles
  • 4,389
  • 2
  • 16
  • 13
  • I posted the entire code. I am running everything within only R, and not RStudio to see if that changes anything. It's weird it works perfectly for incrementing the year and not month..... – traggatmot Feb 13 '13 at 07:39
  • Same error occurs in regular R. When doing it line by line, its not a problem, when running it as a script, it it. – traggatmot Feb 13 '13 at 07:44
  • Any chance you can pull out a subset of the input data that triggers the error? Unfortunately I can't get it to fail, so no idea why it doesn't work for you. – Charles Feb 14 '13 at 01:16