Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate date in R

Tags:

r

I have a date in the format dd-mm-yyyy HH:mm:ss What is the best and easiest way to validate this date?

I tried

d <- format.Date(date, format="%d-%m-%Y %H:%M:%S")

But how can I catch the error when an illegal date is passed?

like image 996
user1790894 Avatar asked Nov 19 '12 08:11

user1790894


3 Answers

Simple way:

d <- try(as.Date(date, format="%d-%m-%Y %H:%M:%S"))
if("try-error" %in% class(d) || is.na(d)) {
  print("That wasn't correct!")
}

Explanation: format.Date uses as.Date internally to convert date into an object of the Date class. However, it does not use a format option, so as.Date uses the default format, which is %Y-%m-%dand then %Y/%m/%d.

The format option from format.Date is used only for the output, not for the parsing. Quoting from the as.Date man page:

The ‘as.Date’ methods accept character strings, factors, logical ‘NA’ and objects of classes ‘"POSIXlt"’ and ‘"POSIXct"’. (The last is converted to days by ignoring the time after midnight in the representation of the time in specified timezone, default UTC.) Also objects of class ‘"date"’ (from package ‘date’) and ‘"dates"’ (from package ‘chron’). Character strings are processed as far as necessary for the format specified: any trailing characters are ignored.

However, when you directly call as.Date with a format specification, nothing else will be allowed than what fits your format.

See also: ?as.Date

like image 182
January Avatar answered Oct 19 '22 17:10

January


You may want to look at the gsubfn package. This has functions (gsubfn specifically) that work like other regular expression functions to match pieces to a string, but then it calls a user supplied function and passes the matching pieces to this function. So you would write your own function that looks at the year, moth, and day and makes sure that they are in the correct ranges (and the range for day can depend on the passed month and year.

like image 1
Greg Snow Avatar answered Oct 19 '22 17:10

Greg Snow


This might be helpful if flexibility is desired in a date-time entry.

I have a function where I want to allow either a date-only entry or a date-time entry, then set a flag - for use inside the function only. I'm calling this flag data_type. The flag will be used later in the larger function to select units for getting a difference in two dates with difftime. (In most cases, the function will be perfectly fine with date only, but in some cases a user might need a shorter time frame. I don't want to inconvenience users with the shorter time frame if they don't need it.)

I am posting this for two reasons: 1) to help anyone trying to allow flexibility in date arguments and 2) to welcome sanity checks in case there's a problem with the method, since this is going into a function in an R package.

dat_time_check_fn <- function(dat_time) {
  if (!anyNA(as.Date(dat_time, format= "%Y-%m-%d %H:%M:%S"))) date_type <- 1
else if (!anyNA(as.Date(dat_time, format= "%Y-%m-%d"))) date_type <- 2
else stop("Error: dates must either be in format '1999-12-31' or '1999-12-31 23:59:59' ")
date_type
}

Date-time case

date5 <- "1999-12-31 23:59:59"

date_type <- dat_time_check_fn(date5)
date_type
[1] 1

Date only case:

date6 <- "1999-12-31"

date_type <- dat_time_check_fn(date6)
date_type
[1] 2

Note that if the order above in the function is reversed, the longer date-time can be inadvertently coerced to the shorter version and both types result in date_type = 1.

My larger function has more than one date, but I need them to be compatible. Below, I'm checking the two dates checked above, where one was type 1 and one was type 2. Combining types gives the result with date only (type 2):

date_type <- dat_time_check_fn(c(date5, date6))
date_type
[1] 2

Here's a non-compliant version:

date7 <- "1/31/2011"

date_type <- dat_time_check_fn(date7)

Error in dat_time_check_fn(date7) : 
  Error: dates must either be in format '1999-12-31' or '1999-12-31 23:59:59'
like image 1
markhogue Avatar answered Oct 19 '22 18:10

markhogue