## 4.3 Time span

• 时期（Durations）：以秒为单位表示一段精确的时间
• 阶段(Periods)： 用人类单位定义的时间间隔，如几周或几个月
• 区间(Intervals)：由起点和终点定义的一段时间

### 4.3.1 时期 Durations

my_age <- today() - ymd(19981112)
my_age
#> Time difference of 7839 days

difftime 对象的单位可以是秒、分钟、小时、日或周。这种模棱两可的对象处理起来非常困难，，所以 lubridate提供了总是以秒为单位的另一种时间间隔：时期

as.duration(my_age)
#> [1] "677289600s (~21.46 years)"

dseconds(15)
#> [1] "15s"
dminutes(10)
#> [1] "600s (~10 minutes)"
dhours(c(12,24))
#> [1] "43200s (~12 hours)" "86400s (~1 days)"

ddays(0:5)
#> [1] "0s"                "86400s (~1 days)"  "172800s (~2 days)"
#> [4] "259200s (~3 days)" "345600s (~4 days)" "432000s (~5 days)"
dweeks(3)  ## 没有dmonths()
#> [1] "1814400s (~3 weeks)"
dyears(1)
#> [1] "31557600s (~1 years)"

2 * ddays(2)
#> [1] "345600s (~4 days)"

dyears(1) + dweeks(12) + ddays(10)
#> [1] "39679200s (~1.26 years)"

(tomorrow <- today() + ddays(1))
#> [1] "2020-04-30"

(last_year <- now() - dyears(1))
#> [1] "2019-04-30 09:15:23 CST"

one_pm <- ymd_hms("2016-03-12 13:00:00", tz = "America/New_York")

one_pm
#> [1] "2016-03-12 13:00:00 EST"
one_pm + ddays(1)
#> [1] "2016-03-13 14:00:00 EDT"

### 4.3.2 阶段 Periods

one_pm
#> [1] "2016-03-12 13:00:00 EST"
one_pm + days(1)  ## 阶段对象
#> [1] "2016-03-13 13:00:00 EDT"

one_pm + days(1)告诉 R，加上一天，而不是加上多少秒。

seconds(15)
#> [1] "15S"
minutes(10)
#> [1] "10M 0S"
hours(c(12,24))
#> [1] "12H 0M 0S" "24H 0M 0S"

days(7)
#> [1] "7d 0H 0M 0S"
months(1:6)
#> [1] "1m 0d 0H 0M 0S" "2m 0d 0H 0M 0S" "3m 0d 0H 0M 0S" "4m 0d 0H 0M 0S"
#> [5] "5m 0d 0H 0M 0S" "6m 0d 0H 0M 0S"
weeks(3)
#> [1] "21d 0H 0M 0S"
years(1)
#> [1] "1y 0m 0d 0H 0M 0S"

10 * (months(6) + days(10))
#> [1] "60m 100d 0H 0M 0S"
days(50) + hours(25) + minutes(2)
#> [1] "50d 25H 2M 0S"

## 闰年
ymd("2016-01-01") + dyears(1)
#> [1] "2016-12-31 06:00:00 UTC"
ymd("2016-01-01") + years(1)
#> [1] "2017-01-01"

## 夏时制
one_pm + ddays(1)
#> [1] "2016-03-13 14:00:00 EDT"
one_pm + days(1)
#> [1] "2016-03-13 13:00:00 EDT"

There is still one specific problem worth mentioning. That is adding months. Adding months frustrates basic arithmetic because consecutive months have different lengths. With other elements, it is helpful for arithmetic to perform automatic roll over. For example, 12:00:00 + 61 seconds becomes 12:01:01. However, people often prefer that this behavior NOT occur with months. For example, we sometimes want January 31 + 1 month = February 28 and not March 3. %m+% performs this type of arithmetic. Date %m+% months(n) always returns a date in the nth month after Date. If you want minus, %m-% does the job.

jan <- ymd("2010-01-31")

jan + months(1:3) # Feb 31 and April 31 returned as NA, because there is no such date
#> [1] NA           "2010-03-31" NA
jan %m+% months(1:3)
#> [1] "2010-02-28" "2010-03-31" "2010-04-30"
jan %m-% months(1:3)
#> [1] "2009-12-31" "2009-11-30" "2009-10-31"

%m+% can be also applied to other time span. For example, it is useful when performing arithmetic around a leap year:

leap <- ymd(20200229)
# test if it is a leap year
leap_year(leap)
#> [1] TRUE

leap + years(c(-1, 1))
#> [1] NA NA
leap %m+% years(c(-1, 1))
#> [1] "2019-02-28" "2021-02-28"

flights_dt %>%
filter(arr_time < dep_time) %>%
select(arr_time, dep_time)
#> # A tibble: 10,633 x 2
#>   arr_time            dep_time
#>   <dttm>              <dttm>
#> 1 2013-01-01 00:03:00 2013-01-01 19:29:00
#> 2 2013-01-01 00:29:00 2013-01-01 19:39:00
#> 3 2013-01-01 00:08:00 2013-01-01 20:58:00
#> 4 2013-01-01 01:46:00 2013-01-01 21:02:00
#> 5 2013-01-01 00:25:00 2013-01-01 21:08:00
#> 6 2013-01-01 00:16:00 2013-01-01 21:20:00
#> # ... with 10,627 more rows

flights_dt <- flights_dt %>%
mutate(overnight = arr_time < dep_time,
arr_time = arr_time + days(overnight * 1))

## 这样一来，航班数据就符合常理了
flights_dt %>% filter(overnight, arr_time < dep_time)
#> # A tibble: 0 x 10
#> # ... with 10 variables: origin <chr>, dest <chr>, dep_delay <dbl>,
#> #   arr_delay <dbl>, dep_time <dttm>, sched_dep_time <dttm>, arr_time <dttm>,
#> #   sched_arr_time <dttm>, air_time <dbl>, overnight <lgl>

### 4.3.3 区间 Intervals

years(1) / days(1)
#> [1] 365

interval(ymd(20090201), ymd(20090101))
#> [1] 2009-02-01 UTC--2009-01-01 UTC

next_year <- today() + years(1)
today() %--% next_year
#> [1] 2020-04-29 UTC--2021-04-29 UTC

## 闰年
(ymd(20160101) %--% ymd(20170101)) / days(1)
#> [1] 366
## 平年
(ymd(20170101) %--% ymd(20180101)) / days(1)
#> [1] 365

### 4.3.5 Exercises

Exercise 4.3 创建一个日期向量来给出 2015 年每个月的第一天
ymd(20150101) + months(0:11)
#>  [1] "2015-01-01" "2015-02-01" "2015-03-01" "2015-04-01" "2015-05-01"
#>  [6] "2015-06-01" "2015-07-01" "2015-08-01" "2015-09-01" "2015-10-01"
#> [11] "2015-11-01" "2015-12-01"

## To get the vector of the first day of the month for this year, we first need to figure out what this year is, and get January 1st of it
floor_date(today(), "year") + months(0:11)
#>  [1] "2020-01-01" "2020-02-01" "2020-03-01" "2020-04-01" "2020-05-01"
#>  [6] "2020-06-01" "2020-07-01" "2020-08-01" "2020-09-01" "2020-10-01"
#> [11] "2020-11-01" "2020-12-01"
Exercise 4.4 编写一个函数，输入你的生日（日期型），返回你的年龄（以年为单位）：
age <- function(birth) {
birth <- ymd(birth)
(birth %--% today()) %/% years(1)
}

age("19981112")
#> [1] 21