hadley/lubridate — pull request #123 by vitoshka (2012-08-01 11:52:05+00:00)
Title: Parser rewrite  (speedup of up to 200 times + heterogeneous formats) 

Hi,

I have rewritten the lubridate parser. It's not based on str_split anymore but on gsub, which has a massive speed improvement and comes close to the speed of `as.POSIXct`.

I am often facing heterogeneous formats in a single vector, which is due to aggregation from different sources or just bad quality data which would have dates like "2011-12-31 12:59", "2010-01-01 12", "2010-01-01" in the same vector. The new version of ymd and ydm_hms families can handle heterogeneous formats.

There is new low level function parseDateTime on which all other functions (including hms) are based. I have documented extensively all the parser functions and added examples to each of them.

Here is the brief illustration of new functionality (lubridate:: prefixes hadley/master version):

```R
> tt <- rep(as.character(Sys.time()), 10^5)
> system.time(out <- lubridate::ymd_hms(tt)) ## strsplit is not an option
Using date format %Y-%m-%d.
user system elapsed
200.500 1.356 215.434
> system.time(out <- ymd_hms(tt))
100000 parsed in %Y-%m-%d-%H-%M-%S order
user system elapsed
1.152 0.000 1.164

> tt <- rep("3:3:3", 10^5)
> system.time(out <- lubridate:::hms(tt))
user system elapsed
88.902 0.632 93.983
> system.time(out <- hms(tt))
user system elapsed
1.296 0.024 1.382

```

Comes close to as.POSIXct:

```R
> tt <- rep(as.character(Sys.time()), 10^6)
> system.time(out <- as.POSIXct(tt, tz = "UTC"))
user system elapsed
11.173 0.232 11.685
> system.time(out <- ymd_hms(tt))
1000000 parsed in %Y-%m-%d-%H-%M-%S order
user system elapsed
11.576 0.152 12.479
```

Heterogeneous formats:

```R

> x <- c(20100101120101, "2009-01-02 12-01-02", "2009.01.03 12:01:03", "2009-1-4 12-1-4",
+ "2009-1, 5 12:1, 5", "2009....1--6 - 12::1:6", "20090107 120107", "200901-08 1201-8",
+ "10-01-09 12:01:09", "10-01-10 10:01:10 AM", "10-01-11 10:01:11 PM")
> ymd_hms(x)
1 parsed in %y-%m-%d-%H-%M-%S order
5 parsed in %Y-%m-%d-%H-%M-%S order
2 parsed in %y-%m-%d-%I-%M-%S-%p order
3 parsed in %Y%m%d%H%M%S order
[1] "2010-01-01 12:01:01 UTC" "2009-01-02 12:01:02 UTC" "2009-01-03 12:01:03 UTC"
[4] "2009-01-04 12:01:04 UTC" "2009-01-05 12:01:05 UTC" "2009-01-06 12:01:06 UTC"
[7] "2009-01-07 12:01:07 UTC" "2009-01-08 12:01:08 UTC" "2010-01-09 12:01:09 UTC"
[10] "2010-01-10 10:01:10 UTC" "2010-01-11 22:01:11 UTC"
```

Truncated formats:

```R

> x <- c("2011-12-31 12:59:59", "2010-01-01 12:11", "2010-01-01 12", "2010-01-01")
> ymd_hms(x, missing = 3)
1 parsed in %Y-%m-%d-%H-%M-%S order
1 parsed in %Y-%m-%d-%H-%M order
1 parsed in %Y-%m-%d-%H order
1 parsed in %Y-%m-%d order
[1] "2011-12-31 12:59:59 UTC" "2010-01-01 12:11:00 UTC" "2010-01-01 12:00:00 UTC"
[4] "2010-01-01 00:00:00 UTC"

> x <- c("2011-12-31 12:59", "2010-01-01 12", "2010-01-01")
> ymd_hm(x, missing = 2)
1 parsed in %Y-%m-%d-%H-%M order
1 parsed in %Y-%m-%d-%H order
1 parsed in %Y-%m-%d order
[1] "2011-12-31 12:59:00 UTC" "2010-01-01 12:00:00 UTC" "2010-01-01 00:00:00 UTC"

```

Fractional seconds.

```R

> options(digits.secs = 3)
> x <- c("2011-12-31 12:59:59.23", "2010-01-01 12:11:10")
> ymd_hms(x, frac = TRUE)
2 parsed in %Y-%m-%d-%H-%M-%OS order
[1] "2011-12-31 12:59:59.23 UTC" "2010-01-01 12:11:10.00 UTC"

> library(devtools)
> install_github("lubridate", "vitoshka")
> options(digits.secs = 3)

> x <- c("2011-12-31 12:59:59.23", "2010-01-01 12:11:10")
> ymd_hms(x, frac = TRUE)
2 parsed in %Y-%m-%d-%H-%M-%OS order
[1] "2011-12-31 12:59:59.23 UTC" "2010-01-01 12:11:10.00 UTC"

> hms("3:3:3.34", frac = TRUE)
[1] 3 hours, 3 minutes and 3.34 seconds
```

New formats:

```R
> ymd_hms("10-12-01 01:01:01 AM", "10-12-01 01:01:01 PM", 101010202020)
2 parsed in %y-%m-%d-%I-%M-%S-%p order
1 parsed in %y%m%d%H%M%S order
[1] "2010-12-01 01:01:01 UTC" "2010-12-01 13:01:01 UTC" "2010-10-10 20:20:20 UTC"

```

With all these goodies come some minor limitations. See docs for `parseDateTime` and examples in `ymd_hms`. These are mainly due to the fact that parsing now is not ignoring the tail of the string, as strptime does. That is the format must match exactly.

This pull fixes #100 and #98.