How to convert a string into a date-time object - r

The data is character and I want it to be date-time. I have the cheat sheet with me but there isn't any format that I can use that satisfies the weird date format. Any suggestions?
x <- 'Fri Dec 11 12:10:51 PST 2020'

You can use the anytime package
> library(anytime)
> anytime("Fri Dec 11 12:10:51 PST 2020")
[1] "2020-12-11 12:10:51 CST"
>
> class(anytime("Fri Dec 11 12:10:51 PST 2020"))
[1] "POSIXct" "POSIXt"
>
It has three key advantages:
it can guess the format (as here)
it converts all sorts of input format (incl character, factor, ...)
it is pretty fast (as the parser is C++ from Boost)
It is pretty standard for most methods to ignore the timezone attribute. So the PST became my local time, i.e. Central.

In base R, you could do :
x <- 'Fri Dec 11 12:10:51 PST 2020'
as.POSIXct(x, format = '%a %b %d %T PST %Y')
See ?strptime for detailed format specifications.

Related

How to convert a character timestamp into a date-time object in R

There is a timestamp variable (i.e. UTC) in my data frame which is a character / string and the date-time format is as follows:-
Fri Aug 10 04:42:47 +0000 2012
How to convert it into a date-time object in R? I tried using the following but it is giving me NAs.
data1$datetime <- as.POSIXct(as.numeric(data1$UTC),origin="1970-01-01",tz="GMT")
This works for your example. See ?strptime for the format codes.
as.POSIXct("Fri Aug 10 04:42:47 +0000 2012",format="%a %b %d %H:%M:%S %z %Y",tz="GMT")
[1] "2012-08-10 04:42:47 GMT"
You can also use parse_date_time from lubridate, which saves you the typing of spaces and % signs:
date_string = "Fri Aug 10 04:42:47 +0000 2012"
library(lubridate)
parse_date_time(date_string, "abdHMSzY", tz = "GMT")
# [1] "2012-08-10 04:42:47 GMT"

Character string with timezone convert to date

I am trying to convert a vector of dates that I read from a csv file using read.table. These were read as a vector of character strings. I am trying to convert it to a date vector using as_date.
The date vector has elements of the below type
dateString
"Wed Dec 11 00:00:00 ICT 2013"
On trying to convert using the below command,
as.Date(dateString,"%a %b %e %H:%M:%S %Z %Y")
Error in strptime(x, format, tz = "GMT") :
use of %Z for input is not supported
What would be the right format to use in strptime? or in as.Date?
Just use the anytime() function from the anytime package:
R> anytime::anytime("Wed Dec 11 00:00:00 ICT 2013")
[1] "2013-12-11 CST"
R>
There is also an utctime() variant to not impose your local time, and much. By now we also had a number of questions here so just search.
And if you want a date, it works the same way:
R> anytime::anydate("Wed Dec 11 00:00:00 ICT 2013")
[1] "2013-12-11"
R>

Dealing with date-time string that has day of the week

I have a date-time string that has day of the week and some meta-data in the string.
d <- "Fri, 14 Jul 2000 06:59:00 -0700 (PDT)"
I need to convert it into a date-time object (e.g. I have a column of these in a data.table) for further analysis. I have dealt with this using regexes to strip off meta-data from the string. Is there a better approach?
What I have is:
m <- regexpr("^\\w+,\\s+", d, perl=TRUE)
regmatches(d, m)
m <- regexpr("\\s-?\\d+\\s\\(\\w+\\)$", d, perl=TRUE)
regmatches(d, m)
ds <- sub("^\\w+,\\s+", "", d)
ds <- sub("\\s-?\\d+\\s\\(\\w+\\)$", "", ds)
Now I can convert this to date-time objects of class Date, Posixlt or Posixct for use in analysis.
dd <- strptime(ds, format="%d %b %Y %H:%M:%S")
dd <- as.Date(ds, format="%d %b %Y %H:%M:%S")
dd <- as.POSIXct(ds, format="%d %b %Y %H:%M:%S")
I wrote the anytime package to help with (among other things) these silly format strings -- so it heuristically just tries a number of them (and focuses on sane ones).
The input you have here qualifies (and is in fact a pretty common form):
R> anytime("Fri, 14 Jul 2000 06:59:00 -0700 (PDT)")
[1] "2000-07-14 06:59:00 CDT"
R>
We do not currently try to capture the timezone offset information at the end, so you have to deal with that after the fact. The display is in CDT which is my local timezone.
There is some more information about anytime on its webpage.
assuming the format of string is going to be constant across your data :
time = trimws(unlist(strsplit(d, "[,-]"))[2])
#[1] "14 Jul 2000 06:59:00"
tz = unlist(strsplit(d, "[,-]"))[3]
tz = gsub("[^A-Z]", "", tz)
#[1] "PDT"
> as.Date(time, format = "%d %b %Y")
[1] "2000-07-14"
> as.POSIXct(time, format = "%d %b %Y %H:%M:%S") #specify th etimezone with tz
[1] "2000-07-14 06:59:00 IST"

How do I specify POSIX (time) format for 3 letter tz in R, in order to ignore it?

For output, the specification is %Z (see ?strptime). But for input, how does that work?
To clarify, it'd be great for the time zone abbreviation to be parsed into useful information by as.POSIXct(), but more core to be question is how to get the function to at least ignore the time zone.
Here is my best workaround, but is there a particular format code to pass to as.POSIXct() that will work for all time zones?
times <- c("Fri Jul 03 00:15:00 EDT 2015", "Fri Jul 03 00:15:00 GMT 2015")
as.POSIXct(times, format="%a %b %d %H:%M:%S %Z %Y") # nope! strptime can't handle %Z in input
formats <- paste("%a %b %d %H:%M:%S", gsub(".+ ([A-Z]{3}) [0-9]{4}$", "\\1", times),"%Y")
as.POSIXct(times, format=formats) # works
Edit: Here is the output from the last line, as well as its class (from a separate call); the output is as expected. From the console:
> as.POSIXct(times, format=formats)
[1] "2015-07-03 00:15:00 EDT" "2015-07-03 00:15:00 EDT"
> attributes(as.POSIXct(times, format=formats))
$class
[1] "POSIXct" "POSIXt"
$tzone
[1] ""
The short answer is, "no, you can't." Those are abbreviations and they are not guaranteed to uniquely identify a specific timezone.
For example, is "EST" Eastern Standard Time in the US or Australia? Is "CST" Central Standard Time in the US or Australia, or is it China Standard Time, or is it Cuba Standard Time?
I just noticed that you're not trying to parse the timezone abbreviation, you are simply trying to avoid it. I don't know of a way to tell strptime to ignore arbitrary characters. I do know that it will ignore anything in the character representation of the time after the end of the format string. For example:
R> # The year is not parsed, so the current year is used
R> as.POSIXct(times, format="%a %b %d %H:%M:%S")
[1] "2015-07-03 00:15:00 UTC" "2015-07-03 00:15:00 UTC"
Other than that, a regular expression is the only thing I can think of that solves this problem. Unlike your example, I would use the regex on the input character vector to remove all 3-5 character timezone abbreviations.
R> times_no_tz <- gsub(" [[:upper:]]{3,5} ", " ", times)
R> as.POSIXct(times_no_tz, format="%a %b %d %H:%M:%S %Y")
[1] "2015-07-03 00:15:00 UTC" "2015-07-03 00:15:00 UTC"

Extract date from a long string

I have a data frame where the date format is as follows:
1:9:Tue Aug 12 2014 19:25:24 GMT+0530 (IST)
I want to extract three variables day, date and time in three different columns and add it to the data frame
Day as Tue
Date as 12/08/2014
Time as 7:25:24PM
The first two numbers do not mean anything.
The dataframe consists of over 700,000 rows and I want to the new columns to replace the existing ones.
You should be careful about adding the datetime to your data.frame as 3 separate columns, because your 3 columns do not uniquely identify a specific datetime because you do not account for timezone. This shouldn't be a problem if all your datetimes are in the same timezone though.
s <- '1:9:Tue Aug 12 2014 19:25:24 GMT+0530 (IST)'
# If the first two numbers do not mean anything and are always separated by a
# colon, then we can remove them with the following gsub command:
s <- gsub("^[[:digit:]:]+","",s)
# Now we can convert the string to a POSIXlt object, assuming they all follow
# the format of including "GMT" before the signed timezone offset
p <- strptime(s, "%a %b %d %Y %H:%M:%S GMT%z")
The above will work even if your datetimes have different timezone offsets. For example:
# these times are the same, just in a different timezone (the second is made up)
s <- c('1:9:Tue Aug 12 2014 19:25:24 GMT+0530 (IST)',
'9:1:Tue Aug 12 2014 19:55:24 GMT+0600 (WAT)')
s <- gsub("^[[:digit:]:]+","",s)
p <- strptime(s, "%a %b %d %Y %H:%M:%S GMT%z")
# the times are the same
as.POSIXct(p, tz="UTC")
# [1] "2014-08-12 08:55:24 UTC" "2014-08-12 08:55:24 UTC"
Formatting the datetimes into the strings you want is easy; just use the format specifications in ?strptime.
data.frame(Day=format(p, "%a"), Date=format(p, "%d/%m/%Y"),
Time=format(p, "%I:%M:%S%p"), stringsAsFactors=FALSE)
This was a tough one. R doesn't have the best support for string and date/time functions. But I was able to get it to work with some hacks:
str <- '1:9:Tue Aug 12 2014 19:25:24 GMT+0530 (IST)';
fieldsBad <- strsplit(str,':')[[1]];
fields <- c(fieldsBad[1:2],paste0(fieldsBad[3:length(fieldsBad)],collapse=':'));
dt <- strptime(fields[3],'%a %b %d %Y %H:%M:%S');
df <- data.frame();
df[1,'Day'] <- strftime(dt,'%a');
df[1,'Date'] <- strftime(dt,'%d/%m/%Y');
df[1,'Time'] <- gsub('^0','',strftime(dt,'%I:%M:%S%p'));
df;
Shows:
Day Date Time
1 Tue 12/08/2014 7:25:24PM
Explanation of hacks:
Unfortunately, the strsplit() function does not allow specifying a maximum number of fields to produce, unlike (for example) http://perldoc.perl.org/functions/split.html in Perl, which has a LIMIT argument, which would be perfect here. So I had to sort of "over-split" and then paste the extra fields back together again on colon with paste0().
Also, the strptime() call ignores the time zone information, although fortunately still parses all it can from the input string. I tried passing the time zone information explicitly to the tz= argument, but it wouldn't recognize IST or GMT+0530 or anything I tried. But since you don't seem to require the time zone, we're ok.
Finally, no format specifier for strftime() seems to allow specifying the 12-hour time without a leading zero, so I had to use %I and call gsub() to strip it off, if present.
library(lubridate)
library(stringr)
d <- "1:9:Tue Aug 12 2014 19:25:24 GMT+0530 (IST)"
d <- gsub("^[[:alnum:]:]+ ", "", d)
tz <- gsub("[ +-]", "", str_extract(d, " ([[:upper:]]+)[+-]"))
strptime(d, "%b %d %Y %H:%M:%S", tz=tz)
## [1] "Aug 12 2014 19:25:24 GMT+0530 (IST)"
You'll prbly need to mapply that in a data frame context since strptime takes an atomic vector for tz. So, do something like:
dat$parsed <- mapply(as.POSIXct,
gsub("^[[:alnum:]:]+ ", "", dat$date),
format="%b %d %Y %H:%M:%S",
tz=gsub("[ +-]", "", str_extract(dat$date, " ([[:upper:]]+)[+-]")))
(that'll make dat$parsed numeric, but that's what POSIXct converts it to, so it's easy to work with)
I realy don't know how to do it in R, but if you get this string from js, you can do something like this:
var date = new Date('Tue Aug 12 2014 19:25:24 GMT+0530 (IST)');
console.log(date.getTime());
console.log(date.getTimezoneOffset());
get time method will return unix timestamp in ms, and getTimezoneOffset will return timezone offset in minutes. Then, you can parse it using date funcions in R. I hope, it is implemented there.

Resources