【问题标题】:Assigning Dates to Fiscal Year为会计年度分配日期
【发布时间】:2016-02-25 22:52:29
【问题描述】:

我正在尝试编写一些代码来查看日期,然后将其分配给会计年度。我完全被困住了。

我有一个包含 POSIXct 格式日期的变量:

df$Date
#2015-05-01 CST
#2015-04-30 CST
#2014-09-01 CST

我需要做的是获取这些日期并返回从 5 月 1 日到 4 月 30 日的财政年度。例如,2016 财政年度从 2015 年 5 月 1 日到 2016 年 4 月 30 日。结果看起来像这样:

df$Date                df$FiscalYear
#2015-05-01 CST        #FY2016
#2015-04-30 CST        #FY2015
#2014-09-01 CST        #FY2015

有什么简单的方法吗?

【问题讨论】:

标签: r dplyr lubridate


【解决方案1】:

这里有一些替代方案。它们都返回数字年份,但如果您真的需要一个以 FY 开头的字符串,请使用paste0("FY", result),其中result 是以下任何结果。它们都支持向量输入,即输入dates可以是向量。

1) zoo::as.yearmon zoo 包有一个 "yearmon" 类,表示年/月为年 + 分数,其中分数 = 0 表示 1 月,1/12 表示 2 月,2 /12 三月等。

使用这个单线就可以了。它减去 4/12(因为 4 月是年末)并加 1(即加一年)。然后获取年份取整数部分:

library(zoo)

as.integer(as.yearmon(dates) - 4/12 + 1)
## [1] 2016 2015 2015

2) POSIXlt 这是一个不使用任何包的解决方案。将日期转换为 POSIXlt 类。 mo 组件表示 Jan 为 0,Feb 为 1 等,所以如果我们是 5 月或更晚(mo 为 4 或更多),则会计年度为下一个日历年,否则为当前日历年。 POSIXlt 对象的year 组件是自 1900 年以来的年数,因此如果我们在 5 月或更晚,则将年份添加到 1900 加 1:

lt <- as.POSIXlt(dates)
lt$year + (lt$mo >= 4) + 1900
## [1] 2016 2015 2015

3) 格式 如果月份大于或等于 5,则将年份加到 1(否则加到零)。这也没有使用任何包:

as.numeric(format(dates, "%Y")) + (format(dates, "%m") >= "05")
## [1] 2016 2015 2015

4) substr。我们可以使用substr提取年份,如果提取的月份(也使用substr提取)为“05”或更大,则转换为数字并加1。同样没有使用任何包。

as.numeric(substr(dates, 1, 4)) + (substr(dates, 6, 7) >= "05")
## [1] 2016 2015 2015

5) read.table 这也不使用任何包。

with(read.table(text = format(dates), sep = "-"), V1 + (V2 >= 5))
## [1] 2016 2015 2015

注意:我们使用这个作为输入dates

dates <- as.Date(c("2015-05-01", "2015-04-30", "2014-09-01"))

【讨论】:

  • 添加了 (2)、(3) 和 (4)
  • 谢谢 GG。我认为英国相当于as.numeric(format(dates, "%Y")) - (format(dates, "%m") &lt;= "03")
  • 太棒了,和 3 一起去了,干得好。应该是答案,更具可读性。
【解决方案2】:

加上 G. Grothendieck 的精彩回应。与lubridate

year(dates) + (month(dates) >= 5)

【讨论】:

    【解决方案3】:

    尝试修改这个:

    Federal.FY <- function(x,firstMonth=10,  # I've altered this line to follow the federal fiscal year, October
                           fy.prefix='FY',
                           quarter.prefix='Q',
                           sep='-',
                           level.range=c(min(x), max(x)) ) {if(level.range[1] > min(x) | level.range[2] < max(x)) {
    warning(paste0('The range of x is greater than level.range. Values ',
                   'outside level.range will be returned as NA.'))}
    quarterString <- function(d) {
    year <- as.integer(format(d, format='%Y'))
    month <- as.integer(format(d, format='%m'))
    y <- ifelse(firstMonth > 1 & month >= firstMonth, year+1, year)
    q <- cut( (month - firstMonth) %% 12, breaks=c(-Inf,2,5,8,Inf),
              labels=paste0(quarter.prefix, 1:4))
    return(paste0(fy.prefix, y, sep, q))}
    vals <- quarterString(x)
    levels <- unique(quarterString(seq(
    as.Date(format(level.range[1], '%Y-%m-01')),
    as.Date(format(level.range[2], '%Y-%m-28')), by='month')))
    return(factor(vals, levels=levels, ordered=TRUE))}
    
    d <- as.Date("2016-10-02")
    Federal.FY(d)
    ##[1] FY2017-Q1
    ##Levels: FY2017-Q1
    

    【讨论】:

      【解决方案4】:

      您可以将seq 与 POSIXct 对象一起使用,以生成跨越数据年份的“截点”或财政年度的第一天的列表,然后使用 findInterval 计算特定日期属于哪个区间进入:

      > dates <- as.POSIXct( c('2015-05-01','2015-04-30','2014-09-01'))
      > fy.tmp <- seq( as.POSIXct('2000-05-01'), length=25, by='year')
      > fiscalYear <- (2001:2025)[ findInterval(dates,fy.tmp) ]
      > fiscalYear
      [1] 2016 2015 2015
      

      如果您想要一个因子作为结果,您也可以使用cut 函数而不是findInterval

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多