0

I have a series of dates in my code that are in an ifelse statement, that are returning a single numerical value instead of a date.

osa <- read.delim("C:/RMathew/RScripts/osaevents/osaevents.txt", stringsAsFactors=TRUE)
#
osa$datetime <- ymd_hms(osa$datetime)
osa$date <- as.Date(osa$datetime)
sixoclock <- 6*60*60
osa$daystart <- ymd_hms(ymd(osa$date) + sixoclock)
osa$dateplus <- osa$date + 1
osa$dateminus <- osa$date - 1
osa$dayend <- ymd_hms(ymd(osa$dateplus) + sixoclock)
osa$dateloca <- osa$datetime >= osa$daystart
osa$datelocb <- osa$datetime < osa$dayend
osa$milldate <- ifelse(osa$dateloca==TRUE & osa$datelocb==TRUE,
                       osa$date,osa$dateminus)

The place where this data originates considers the time between 6 AM on any given day to 6 AM the following day, as one day. The code above is trying to compare the date to the question of is it after 6 AM on a particular day, but before 6 AM on the following day, to assign it the earlier day's date (for whatever day it might be).

So far so good, but it returns a single number for the osa$milldate instead of the dates in the ifelse columns.

'data.frame':   897 obs. of  16 variables:
 $ datetime : POSIXct, format: "2015-08-13 15:11:53" "2015-08-13 14:53:26" "2015-08-13 14:34:58" "2015-08-13 14:16:18" ...
 $ stream   : Factor w/ 1 level "fc": 1 1 1 1 1 1 1 1 1 1 ...
 $ fe       : num  18.1 18 17.6 18.1 18.5 ...
 $ ni       : num  2.97 2.99 2.92 3.2 3.32 ...
 $ cu       : num  3.41 3.35 2.99 3.58 3.73 ...
 $ pd       : num  138 157 139 166 183 ...
 $ mg       : num  13.8 13.8 14.4 14.3 13.9 ...
 $ so       : num  9.67 9.81 9.65 10.58 11.37 ...
 $ date     : Date, format: "2015-08-13" "2015-08-13" "2015-08-13" "2015-08-13" ...
 $ daystart : POSIXct, format: "2015-08-13 06:00:00" "2015-08-13 06:00:00" "2015-08-13 06:00:00" "2015-08-13 06:00:00" ...
 $ dateplus : Date, format: "2015-08-14" "2015-08-14" "2015-08-14" "2015-08-14" ...
 $ dateminus: Date, format: "2015-08-12" "2015-08-12" "2015-08-12" "2015-08-12" ...
 $ dayend   : POSIXct, format: "2015-08-14 06:00:00" "2015-08-14 06:00:00" "2015-08-14 06:00:00" "2015-08-14 06:00:00" ...
 $ dateloca : logi  TRUE TRUE TRUE TRUE TRUE TRUE ...
 $ datelocb : logi  TRUE TRUE TRUE TRUE TRUE TRUE ...
 $ milldate : num  16660 16660 16660 16660 16660 ...

Thoughts? Also, there is likely to be a more elegant way to do this.

Reuben Mathew
  • 598
  • 4
  • 22
  • Does this answer your question? [How to prevent ifelse() from turning Date objects into numeric objects](https://stackoverflow.com/questions/6668963/how-to-prevent-ifelse-from-turning-date-objects-into-numeric-objects) – Sam Firke May 10 '22 at 18:31

2 Answers2

3

See the help file for ifelse

Warning:

The mode of the result may depend on the value of ‘test’ (see the examples), and the class attribute (see ‘oldClass’) of the result is taken from ‘test’ and may be inappropriate for the values selected from ‘yes’ and ‘no’.

Sometimes it is better to use a construction such as

  (tmp <- yes; tmp[!test] <- no[!test]; tmp)

, possibly extended to handle missing values in ‘test’.

This describes precisely what is going on in your example -- the date class attribute is lost -- and a work around -- a multi-step approach.

osa$milldate <- osa$date
ind<- osa$dateloca==TRUE & osa$datelocb==TRUE
osa$milldate[!ind] <- osa$dateminus

Another option is replace.

A. Webb
  • 26,227
  • 1
  • 63
  • 95
  • I'm such an R noob. I can't even make sense of that construction. If you can spare the time, please would you translate that into a simpler form so that I can understand it? I understand that the ifelse is stripping away the date formatting. I can't think of how to rewrite this ifelse statement. That's what I'm struggling with. – Reuben Mathew Aug 14 '15 at 15:11
  • Your example has been translated to the multi-step approach. – A. Webb Aug 14 '15 at 15:15
  • I wouldn't bother rewriting the `ifelse` statement. Just add another line after it. `osa$milldate <- as.POSIXct(osa$milldate, origin = origin)` (the `origin` object is in the `lubridate` package)....or you might need `as.Date`, depending on what your initial object was. – Benjamin Aug 14 '15 at 15:15
  • Benjamin, your comment is turning everything into the last day in 1969. I have the lubridate package loaded. Let me try A. Webb's method. I'll be right back. – Reuben Mathew Aug 14 '15 at 15:17
  • The suggestion from the helpfile is general. In other situations, you may encounter more than one class. – A. Webb Aug 14 '15 at 15:18
  • It's doing this weird thing where it works for the first instance, but then it resets to the wrong date after midnight. Let me play around with this a bit more. I understand that this is difficult without the dataset to experiment with at your end. Let me work on this a tad longer and I'll get back here. You have my many thanks for setting me on the right path. I'll come back here and give you the "tick" after I sort this out. – Reuben Mathew Aug 14 '15 at 15:25
  • You shouldn't even need those `==TRUE` parts if those vectors are already logical – Rich Scriven Aug 14 '15 at 15:45
0

A. Webb set me on the right path. The ifelse class was stripping the answer of the date format. The solution above with the index seemed to jumble the date order for some reason. As A. Webb pointed out, in the help file, the following line fixed it immediately.

class(osa$milldate) <- class(osa$date)

Reuben Mathew
  • 598
  • 4
  • 22