八块腹肌的数据线 · 机场到北工大-北京工业大学国际学院· 3 月前 · |
深情的烈酒 · 第1视点|习近平:携手实现中印两大文明伟大复 ...· 4 月前 · |
坚强的烤地瓜 · 首届北京大学临床学科评估发布· 4 月前 · |
开心的滑板 · 国家金融监督管理总局· 4 月前 · |
谦逊的苦瓜 · 关于与崔永元老师的辩论_手机新浪网· 11 月前 · |
时间计算 cst中国 date函数 utc |
https://www.math.pku.edu.cn/teachers/lidf/docs/Rbook/html/_Rbook/prog-type-date.html |
一身肌肉的泡面
1 年前 |
evalCpp()
转换单一计算表达式
cppFunction()
转换简单的C++函数—Fibnacci例子
sourceCpp()
转换C++程序—正负交替迭代例子
sourceCpp()
转换C++源文件中的程序—正负交替迭代例子
sourceCpp()
转换C++源程序文件—卷积例子
wrap()
把C++变量返回到R中
as()
函数把R变量转换为C++类型
as()
和
wrap()
的隐含调用
//[[Rcpp::export]]
sourceCpp()
函数中直接包含C++源程序字符串
cppFunction()
函数中直接包含C++函数源程序字符串
evalCpp()
函数中直接包含C++源程序表达式字符串
depends
指定要链接的库
invisible
要求函数结果不自动显示
clone
函数
is_na
seq_along
seq_len
pmin
和
pmax
ifelse
sapply
和
lapply
sign
diff
kable()
函数制作表格
R中用一种叫做POSIXct和POSIXlt的特殊数据类型保存日期和时间, 可以仅包含日期部分,也可以同时有日期和时间。 技术上,POSIXct把日期时间保存为从1970年1月1日零时到该日期时间的时间间隔秒数, 所以数据框中需要保存日期时用POSIXct比较合适, 需要显示时再转换成字符串形式; POSIXlt把日期时间保存为一个包含年、月、日、星期、时、分、秒等成分的列表, 所以求这些成分可以从POSIXlt格式日期的列表变量中获得。 日期时间会涉及到所在时区、夏时制等问题, 比较复杂。
为了获得专用的时间类型, 可以使用hms扩展包。
基础的R用
as.Date()
、
as.POSIXct()
等函数生成日期型和日期时间型,
R扩展包lubridate提供了多个方便函数,
可以更容易地生成、转换、管理日期型和日期时间型数据。
函数
lubridate::today()
返回当前日期:
函数
lubridate::now()
返回当前日期时间:
结果显示中出现的
CST
是时区,
这里使用了操作系统提供的当前时区。
CST不是一个含义清晰的时区,
在不同国家对应不同的时区,
在中国代表中国标准时间(北京时间)。
用
lubridate::ymd()
,
lubridate::mdy()
,
lubridate::dmy()
将字符型向量转换为日期型向量,如:
ymd(c("1998-3-10", "2018-01-17", "18-1-17")) ## [1] "1998-03-10" "2018-01-17" "2018-01-17" mdy(c("3-10-1998", "01-17-2018")) ## [1] "1998-03-10" "2018-01-17" dmy(c("10-3-1998", "17-01-2018")) ## [1] "1998-03-10" "2018-01-17"
在年号只有两位数字时,默认对应到1969-2068范围。
lubridate包的
ymd
、
mdy
、
dmy
等函数添加
hms
、
hm
、
h
等后缀,
可以用于将字符串转换成日期时间。
上面例子结果显示中UTC是时区,
UTC是协调世界时(Universal Time Coordinated)英文缩写,
是由国际无线电咨询委员会规定和推荐,
并由国际时间局(BIH)负责保持的以秒为基础的时间标度。
UTC相当于本初子午线(即经度0度)上的平均太阳时,
过去曾用格林威治平均时(GMT)来表示。
北京时间比UTC时间早8小时,
以1999年1月1日0000UTC为例,
UTC时间是零点,
北京时间为1999年1月1日早上8点整。
日期时间字符串中日期部分和时间部分以空格分隔,
也可以用字母
T
分隔。
在
Date()
、
as.DateTime()
、
ymd()
等函数中,
可以用
tz=
指定时区,
比如北京时间可指定为
tz="Etc/GMT-8"
或
tz="Asia/Shanghai"
。
为了将某个时间转换到指定的时区,
而不改变真正的时间,
用
with_tz()
函数,如:
## [1] "1998-03-16 05:15:45 UTC" "2023-03-14 02:11:12 UTC"
为了保持表面的时间(时钟显示的日期时间)不变,
但将真正的时间修改到另外的时区,
用
force_tz()
或
force_tzs()
,
其中
force_tzs()
可以将每个时间单独应用不同的时区。
## [1] "1998-03-16 13:15:45 UTC" "2023-03-14 10:11:12 UTC"
上例的结果显示中,仅时区改变了,
显示的日期、时间都没有变,
但这样就改变了真实的时间。
输入的日期中的时区
"Asia/Shanghai"
不起作用,
仅该时区的钟面时间起作用。
force_tzs(ymd_hms(c("1998-03-16 13:15:45", "2023-03-14 10:11:12"), tz="Asia/Shanghai"), tzones=c("Etc/GMT-6", "Etc/GMT-10"))
## [1] "1998-03-16 07:15:45 UTC" "2023-03-14 00:11:12 UTC"
这将北京时间
"1998-03-16 13:15:45"
改成了东6区时间,
对应到UTC就是钟面时间减6,
所以13点变成7点,
将北京时间
"2023-03-14 10:11:12"
改成了东10区时间,
对应到UTC就是钟面时间减10,所以10点变成0点。
输入的日期中的时区
"Asia/Shanghai"
不起作用,
仅该时区的钟面时间起作用。
lubridate::make_date(year, month, day)
可以从三个数值构成日期向量。
lubridate::make_datetime(year, month, day, hour, min, sec)
可以从最多六个数值组成日期时间,
其中时分秒缺省值都是0。
在
make_date()
和
make_datetime()
都可以用
tz
选项指定时区,
但仅支持单个时区。
如果多个时间的时区也不同,
应该使用
force_tzs()
函数。
用
lubridate::as_date()
可以将日期时间型转换为日期型,如
用
lubridate::as_datetime()
可以将日期型数据转换为日期时间型,如
用
as.character()
函数把日期型数据转换为字符型, 如
在
as.character()
中可以用
format
选项指定显示格式,如
格式中“
%Y
”代表四位的公元年号,
“
%m
”代表两位的月份数字,
“
%d
”代表两位的月内日期号。
这些格式缩写也被用在从字符串转换在日期时,
比如
readr::read_csv
在指定某一列为
col_date()
时,
可以指定格式如
format="%m/%d/%Y"
。
"15Mar98"
这样的日期在英文环境中比较常见,
但是在R中的处理比较复杂。
在下面的例子中,R日期被转换成了类似
"Mar98"
这样的格式,
在
format
选项中用了“
%b
”代表三英文字母月份缩写,
但是因为月份缩写依赖于操作系统默认语言环境,
需要用
Sys.setlocale()
函数设置语言环境为
"C"
。示例程序如下
x <- as.POSIXct(c('1998-03-16', '2015-11-22')) old.lctime <- Sys.getlocale('LC_TIME') Sys.setlocale('LC_TIME', 'C') ## [1] "C" as.character(x, format='%b%y') ## [1] "Mar98" "Nov15" Sys.setlocale('LC_TIME', old.lctime) ## [1] "Chinese (Simplified)_China.utf8"
format
选项中的“
%y
”表示两位数的年份,
应尽量避免使用两位数年份以避免混淆。
包含时间的转换如
x <- as.POSIXct('1998-03-16 13:15:45') as.character(x) ## [1] "1998-03-16 13:15:45" as.character(x, format='%H:%M:%S') ## [1] "13:15:45"
这里“
%H
”代表小时(按24小时制),
“
%M
”代表两位的分钟数字,
“
%S
”代表两位的秒数。
lubridate包的如下函数可以取出日期型或日期时间型数据中的组成部分:
year()
取出年
month()
取出月份数值
mday()
取出日数值
yday()
取出日期在一年中的序号,元旦为1
wday()
取出日期在一个星期内的序号,
但是一个星期从星期天开始,
星期天为1,星期一为2,星期六为7。
hour()
取出小时
minute()
取出分钟
second()
取出秒
比如, 2018-1-17是星期三,
month(as.POSIXct("2018-1-17 13:15:40")) ## [1] 1 mday(as.POSIXct("2018-1-17 13:15:40")) ## [1] 17 wday(as.POSIXct("2018-1-17 13:15:40")) ## [1] 4
lubridate的这些成分函数还允许被赋值, 结果就修改了相应元素的值,如
x <- as.POSIXct("2018-1-17 13:15:40") year(x) <- 2000 month(x) <- 1 mday(x) <- 1 ## [1] "2000-01-01 13:15:40 CST"
update()
可以对一个日期或一个日期型向量统一修改其组成部分的值,
update()
函数中可以用
year
,
month
,
mday
,
hour
,
minute
,
second
等参数修改日期的组成部分。
用lubridate包的功能计算周岁如下:
age.int <- function(birth, now){ age <- year(now) - year(birth) sele <- (month(now) * 100 + mday(now) < month(birth) * 100 + mday(birth)) ## sele 是那些没有到生日的人 age[sele] <- age[sele] - 1
9.8 日期舍入计算
lubridate包提供了
floor_date()
,round_date()
,ceiling_date()
等函数, 对日期可以用unit=
指定一个时间单位进行舍入。 时间单位为字符串, 如seconds
,5 seconds
,minutes
,2 minutes
,hours
,days
,weeks
,months
,years
等。比如,以
10 minutes
为单位,floor_date()
将时间向前归一化到10分钟的整数倍,ceiling_date()
将时间向后归一化到10分钟的整数倍,round_date()
将时间归一化到最近的10分钟的整数倍, 时间恰好是5分钟倍数时按照类似四舍五入的原则向上取整。x <- ymd_hms("2018-01-11 08:32:44") floor_date(x, unit="10 minutes") ## [1] "2018-01-11 08:30:00 UTC" ceiling_date(x, unit="10 minutes") ## [1] "2018-01-11 08:40:00 UTC" round_date(x, unit="10 minutes") ## [1] "2018-01-11 08:30:00 UTC"
如果单位是星期, 会涉及到一个星期周期的开始是星期日还是星期一的问题。 用参数
week_start=7
指定开始是星期日,week_start=1
指定开始是星期一。9.9 日期计算
在lubridate的支持下日期可以相减, 可以进行加法、除法。 lubridate包提供了如下的三种与时间长短有关的数据类型:
时间长度(duration),按整秒计算; 时间周期(period),如日、周; 时间区间(interval),包括一个开始时间和一个结束时间。 9.9.1 时间长度
R的POSIXct日期时间之间可以相减,如
d1 <- ymd_hms("2000-01-01 0:0:0") d2 <- ymd_hms("2000-01-02 12:0:5") di <- d2 - d1; di ## Time difference of 1.500058 days
结果显示与日期之间差别大小有关系, 结果是类型是difftime。 为了转换成数值,比如秒数, 可以用
as.double()
和units="secs"
,as.double(di, units="days") ## [1] 1.500058 as.double(di, units="hours") ## [1] 36.00139 as.double(di, units="mins") ## [1] 2160.083 as.double(di, units="secs") ## [1] 129605
lubridate包提供了duration类型, 固定以秒作为基本单位, 所以处理更方便:
lubridate的
dseconds()
,dminutes()
,dhours()
,ddays()
,dweeks()
,dyears()
函数可以直接生成时间长度类型的数据,如## [1] "3600s (~1 hours)"
lubridate的时间长度类型总是以秒作为单位, 可以在时间长度之间相加, 也可以对时间长度乘以无量纲数,如
可以给一个日期加或者减去一个时间长度, 结果严格按推移的秒数计算,
d2 <- ymd_hms("2000-01-02 12:0:5") d2 - dhours(5) ## [1] "2000-01-02 07:00:05 UTC" d2 + ddays(10) ## [1] "2000-01-12 12:00:05 UTC"
时间的前后推移在涉及到夏时制时有可能出现难以预料到的情况。
9.9.2 时间周期
时间长度的固定单位是秒, 但是像月、年这样的单位, 因为可能有不同的天数, 所以日历中的时间单位往往没有固定的时长。
lubridate包的
seconds()
,minutes()
,hours()
,days()
,weeks()
,years()
函数可以生成以日历中正常的周期为单位的时间长度, 不需要与秒数相联系, 可以用于时间的前后推移。 这些时间周期的结果可以相加、乘以无量纲整数:lubridate的月度周期因为与已有函数名冲突, 所以没有提供, 需要使用
lubridate::period(num, units="month")
的格式, 其中num
是几个月的数值。为了按照日历进行日期的前后平移, 而不是按照秒数进行日期的前后平移, 应该使用这些时间周期。
例如,因为2016年是闰年, 按秒数给2016-01-01加一年,得到的并不是2017-01-01:
使用时间周期函数则得到预期结果:
9.9.3 时间区间
lubridate提供了
%--%
运算符构造一个时间期间(time interval)。 时间区间可以求交集、并集等。d1 <- ymd_hms("2000-01-01 0:0:0") d2 <- ymd_hms("2000-01-02 12:0:5") din <- (d1 %--% d2); din ## [1] 2000-01-01 UTC--2000-01-02 12:00:05 UTC
对一个时间区间可以用除法计算其时间长度,如
生成时间区间, 也可以用
lubridate::interval(start, end)
函数,如interval(ymd_hms("2000-01-01 0:0:0"), ymd_hms("2000-01-02 12:0:5")) ## [1] 2000-01-01 UTC--2000-01-02 12:00:05 UTC
可以指定时间长度和开始日期生成时间区间,
d1 <- ymd("2018-01-15") din <- as.interval(dweeks(1), start=d1); din ## [1] 2018-01-15 UTC--2018-01-22 UTC
注意这个时间区间表面上涉及到8个日期, 但是实际长度还是只有7天, 因为每一天的具体时间都是按零时计算, 所以区间末尾的那一天实际不含在内。
用
lubridate::int_start()
和lubridate::int_end()
函数访问时间区间的端点,如:可以用
as.duration()
将一个时间区间转换成时间长度, 用as.period()
将一个时间区间转换为可变时长的时间周期个数。用
lubridate::int_shift()
平移一个时间区间,如用
lubridate::int_overlaps()
判断两个时间区间是否有共同部分,如时间区间允许开始时间比结束时间晚, 用
lubridate::int_standardize()
可以将时间区间标准化成开始时间小于等于结束时间。lubridate()
现在没有提供求交集的功能, 一个自定义求交集的函数如下:int_intersect <- function(int1, int2){ n <- length(int1) int1 <- lubridate::int_standardize(int1) int2 <- lubridate::int_standardize(int2) sele <- lubridate::int_overlaps(int1, int2) inter <- rep(lubridate::interval(NA, NA), n) if(any(sele)){ inter[sele] <- lubridate::interval(pmax(lubridate::int_start(int1[sele]), lubridate::int_start(int2[sele])), pmin(lubridate::int_end(int1[sele]), lubridate::int_end(int2[sele]))) inter
d1 <- ymd(c("2018-01-15", "2018-01-18", "2018-01-25")) d2 <- ymd(c("2018-01-21", "2018-01-23", "2018-01-30")) din <- interval(d1, d2); din ## [1] 2018-01-15 UTC--2018-01-21 UTC 2018-01-18 UTC--2018-01-23 UTC ## [3] 2018-01-25 UTC--2018-01-30 UTC int_intersect(rep(din[1], 2), din[2:3]) ## [1] 2018-01-18 UTC--2018-01-21 UTC NA--NA
此自定义函数还可以进一步改成允许两个自变量长度不等的情形。
9.10 基本R软件的日期功能
9.10.1 生成日期和日期时间型数据
Sys.date()
返回Date类型的当前日期。Sys.time()
返回POSIXct类型的当前日期时间。对
yyyy-mm-dd
或yyyy/mm/dd
格式的数据, 可以直接用as.Date()
转换为Date类型,如:
as.Date()
可以将多个日期字符串转换成Date类型,如对于非标准的格式,在
as.Date()
中可以增加一个format
选项, 其中用%Y
表示四位数字的年,%m
表示月份数字,%d
表示日数字。如用
as.POSIXct()
函数把年月日格式的日期转换为R的标准日期, 没有时间部分就认为时间在午夜。如as.POSIXct(c('1998-03-16')) ## [1] "1998-03-16 CST" as.POSIXct(c('1998/03/16')) ## [1] "1998-03-16 CST"
年月日中间的分隔符可以用减号也可以用正斜杠, 但不能同时有减号又有斜杠。
待转换的日期时间字符串,可以是年月日之后隔一个空格以“时:分:秒”格式带有时间。如
用
as.POSIXct()
可以同时转换多项日期时间,如## [1] "1998-03-16 13:15:45 CST" "2015-11-22 09:45:03 CST"
转换后的日期变量有class属性,取值为POSIXct与POSIXt, 并带有一个tzone(时区)属性。
x <- as.POSIXct(c('1998-03-16 13:15:45', '2015-11-22 9:45:3')) attributes(x) ## $class ## [1] "POSIXct" "POSIXt" ## $tzone ## [1] ""
在
as.POSIXct()
函数中用format
参数指定一个日期格式。如如果日期仅有年和月,必须添加日(添加01为日即可)才能读入。 比如用’1991-12’表示1991年12月,则如下程序将其读入为’1991-12-01’:
old.lctime <- Sys.getlocale('LC_TIME') Sys.setlocale('LC_TIME', 'C') ## [1] "C" as.POSIXct(paste('01', 'DEC91', sep=''), format='%d%b%y') ## [1] "1991-12-01 CST" Sys.setlocale('LC_TIME', old.lctime) ## [1] "Chinese (Simplified)_China.utf8"
把
'DEC91'
转换成了’1991-12-01’。如果明确地知道时区, 在
as.POSIXct()
和as.POSIXlt()
中可以加选项tz=
字符串。 选项tz
的缺省值为空字符串, 这一般对应于当前操作系统的默认时区。 但是,有些操作系统和R版本不能使用默认值, 这时可以为tz指定时区, 比如北京时间可指定为tz='Etc/GMT+8'
。如9.10.2 取出日期时间的组成值
把一个R日期时间值用
as.POSIXlt()
转换为POSIXlt类型, 就可以用列表元素方法取出其组成的年、月、日、时、分、秒等数值。x <- as.POSIXct('1998-03-16 13:15:45') y <- as.POSIXlt(x) cat(1900+y$year, y$mon+1, y$mday, y$hour, y$min, y$sec, '\n') ## 1998 3 16 13 15 45
注意year要加1900,mon要加1。 另外,列表元素
wday
取值1-6时表示星期一到星期六, 取值0时表示星期天。对多个日期,
as.POSIXlt()
会把它们转换成一个列表(列表类型稍后讲述), 这时可以用列表元素year
,mon
,mday
等取出日期成分。如9.10.3 日期计算
因为Date类型是用数值保存的,所以可以给日期加减一个整数,如:
所有的比较运算都适用于日期类型。
可以给一个日期加减一定的秒数,如
as.POSIXct(c('1998-03-16 13:15:45')) - 30 ## [1] "1998-03-16 13:15:15 CST" as.POSIXct(c('1998-03-16 13:15:45')) + 10 ## [1] "1998-03-16 13:15:55 CST"
但是两个日期不能相加。
给一个日期加减一定天数, 可以通过加减秒数实现,如
这个例子把日期推后了两天。
用
difftime(time1, time2, units='days')
计算time1减去time2的天数,x <- as.POSIXct(c('1998-03-16', '2015-11-22')) c(difftime(x[2], x[1], units='days')) ## Time difference of 6460 days
函数结果用
c()
包裹以转换为数值, 否则会带有单位。调用
difftime()
时如果前两个自变量中含有时间部分, 则间隔天数也会带有小数部分。如x <- as.POSIXct(c('1998-03-16 13:15:45', '2015-11-22 9:45:3')) c(difftime(x[2], x[1], units='days')) ## Time difference of 6459.854 days
difftime()
中units
选项还可以取为'secs'
,'mins'
,'hours'
等。9.11 练习
"出生日期","发病日期" "1941/3/8","2007/1/1" "1972/1/24","2007/1/1" "1932/6/1","2007/1/1" "1947/5/17","2007/1/1" "1943/3/10","2007/1/1" "1940/1/8","2007/1/1" "1947/8/5","2007/1/1" "2005/4/14","2007/1/1" "1961/6/23","2007/1/2" "1949/1/10","2007/1/2"
把这个文件读入为R数据框dates.tab, 运行如下程序定义
date1
和date2
变量:把date1、date2转换为R的POSIXct日期型。
求date1中的各个出生年。
计算发病时的年龄,以周岁论(过生日才算)。
把date2中发病年月转换为’monyy’格式,这里mon是如FEB这样英文三字母缩写, yy是两数字的年份。
对诸如’FEB91’, ’OCT15’这样的年月数据, 假设00—20表示21世纪年份,21—99表示20实际年份。 编写R函数,输入这样的字符型向量, 返回相应的POSIXct格式日期, 具体日期都取为相应月份的1号。 这个习题和后两个习题可以预习函数部分来做。
对R的POSIXct日期,写函数转换成’FEB91’, ’OCT15’这样的年月表示, 假设00—20表示21世纪年份,21—99表示20实际年份。
给定两个POSIXct日期向量birth和work, birth为生日,work是入职日期, 编写R函数, 返回相应的入职周岁整数值(不到生日时周岁值要减一)。
八块腹肌的数据线 · 机场到北工大-北京工业大学国际学院 3 月前 |
深情的烈酒 · 第1视点|习近平:携手实现中印两大文明伟大复兴-新华网 4 月前 |
坚强的烤地瓜 · 首届北京大学临床学科评估发布 4 月前 |
开心的滑板 · 国家金融监督管理总局 4 月前 |
谦逊的苦瓜 · 关于与崔永元老师的辩论_手机新浪网 11 月前 |