0

I found code on stack overflow that converts dates to government FY quarters. I was wondering if there was a way to modify it to show FY Biannuals. As in October, November, December, January, February, March would be FYB1 and April, May, June, July, August, September would be FYB2.

Here is the code that I found that converts to FY Quarters, Code was posted by Nettle on StackOverflow:

Federal.FY <- function(x,firstMonth=10,  
                       fy.prefix='FY',
                       biannual.prefix='B',
                       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(biannual.prefix, 1:2))
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)
Al. So
  • 53
  • 5

1 Answers1

0

It looks like you changed the labels argument to cut (1:2 instead of 1:4) but you also need to change the breaks argument. Try

Federal.FY <- function(x,firstMonth=10,  
                       fy.prefix='FY',
                       biannual.prefix='B',
                       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,5,Inf),
                  labels=paste0(biannual.prefix, 1:2))
        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))

Then I think you get what you are looking for:

d <- as.Date("2016-10-02")
Federal.FY(d)
[1] FY2017-B1
Levels: FY2017-B1
josephjscheidt
  • 326
  • 1
  • 6
  • Thank you Joseph, could you quickly explain why the change works? – Al. So Aug 09 '19 at 14:52
  • The cut function changes numeric variables to categorical variables. It needs to know where the numeric breaks are between categories and what to label the breaks.The number of labels for categories must be the same as the number of sections created by breaks. By the way, I mistyped 4 as the break value. It should be 5. It is now fixed. – josephjscheidt Aug 09 '19 at 16:45