module FatCore::Date
Constants
- BOT
Constant for Beginning of Time (
BOT
) outside the range of what we would ever want to find in commercial situations.- EOT
Constant for End of Time (
EOT
) outside the range of what we would ever want to find in commercial situations.- FED_DECREED_HOLIDAYS
Holidays decreed by Presidential proclamation
- PRESIDENTIAL_FUNERALS
Presidential funeral since JFK
Public Class Methods
# File lib/fat_core/date.rb, line 1809 def self.included(base) base.extend(ClassMethods) end
Public Instance Methods
Return the date that is n NYSE trading days after or before (if n < 0) this date.
@param num [Integer] number of NYSE trading days to add to this date @return [::Date]
# File lib/fat_core/date.rb, line 1128 def add_nyse_workdays(num) d = dup return d if num.zero? incr = num.negative? ? -1 : 1 num = num.abs while num.positive? d += incr num -= 1 if d.nyse_workday? end d end
Return the date that is the beginning of the chunk
in which this date falls.
@param chunk [Symbol] one of :year
, :half
, :quarter
, :bimonth
,
+:month+, +:semimonth+, +:biweek+, +:week+, or +:day+.
@return [::Date] the first date in the chunk-sized period in which this date
falls
# File lib/fat_core/date.rb, line 754 def beginning_of_chunk(chunk) case chunk when :year beginning_of_year when :half beginning_of_half when :quarter beginning_of_quarter when :bimonth beginning_of_bimonth when :month beginning_of_month when :semimonth beginning_of_semimonth when :biweek beginning_of_biweek when :week beginning_of_week when :day self else raise ArgumentError, "unknown chunk sym: '#{chunk}'" end end
Return whether the date that is the beginning of the chunk
@param chunk [Symbol] one of :year
, :half
, :quarter
, :bimonth
,
+:month+, +:semimonth+, +:biweek+, +:week+, or +:day+.
@return [::Boolean] whether this date begins a chunk
# File lib/fat_core/date.rb, line 816 def beginning_of_chunk?(chunk) self == beginning_of_chunk(chunk) end
The date that is the first day of the half-year in which self falls. @return [::Date]
# File lib/fat_core/date.rb, line 400 def beginning_of_half if month > 9 (beginning_of_quarter - 15).beginning_of_quarter elsif month > 6 beginning_of_quarter else beginning_of_year end end
Self's calendar bimonth: 1, 2, 3, 4, 5, or 6 depending on which calendar bimonth the date falls in. @return [Integer]
# File lib/fat_core/date.rb, line 153 def bimonth case month when (1..2) 1 when (3..4) 2 when (5..6) 3 when (7..8) 4 when (9..10) 5 when (11..12) 6 end end
Self's calendar biweek: 1, through 24 depending on which calendar semimonth the date falls in. @return [Integer]
# File lib/fat_core/date.rb, line 180 def biweek if cweek.odd? (cweek + 1) / 2 else cweek / 2 end end
Return whether this date is Easter Sunday for the year in which it falls according to the Western Church. A few holidays key off this date as “moveable feasts.”
@return [Boolean]
# File lib/fat_core/date.rb, line 368 def easter? # Am I Easter? self == easter_this_year end
Return the date for Easter in the Western Church for the year in which this date falls.
@return [::Date]
# File lib/fat_core/date.rb, line 849 def easter_this_year # Return the date of Easter in self's year ::Date.easter(year) end
Return the date that is the end of the chunk
in which this date falls.
@param chunk [Symbol] one of :year
, :half
, :quarter
, :bimonth
,
+:month+, +:semimonth+, +:biweek+, +:week+, or +:day+.
@return [::Date] the first date in the chunk-sized period in which this date
falls
# File lib/fat_core/date.rb, line 786 def end_of_chunk(chunk) case chunk when :year end_of_year when :half end_of_half when :quarter end_of_quarter when :bimonth end_of_bimonth when :month end_of_month when :semimonth end_of_semimonth when :biweek end_of_biweek when :week end_of_week when :day self else raise ArgumentError, "unknown chunk: '#{chunk}'" end end
Return whether the date that is the end of the chunk
@param chunk [Symbol] one of :year
, :half
, :quarter
, :bimonth
,
+:month+, +:semimonth+, +:biweek+, +:week+, or +:day+.
@return [::Boolean] whether this date ends a chunk
# File lib/fat_core/date.rb, line 825 def end_of_chunk?(chunk) self == end_of_chunk(chunk) end
Return whether this date is a United States federal holiday.
Calculations for Federal holidays are based on 5 USC 6103, include all weekends, Presidential funerals, and holidays decreed executive orders.
@return [Boolean]
# File lib/fat_core/date.rb, line 892 def fed_holiday? # All Saturdays and Sundays are "holidays" return true if weekend? # Some days are holidays by executive decree return true if FED_DECREED_HOLIDAYS.include?(self) # Presidential funerals return true if PRESIDENTIAL_FUNERALS.include?(self) # Is self a fixed holiday return true if fed_fixed_holiday? || fed_moveable_feast? if friday? && month == 12 && day == 26 # If Christmas falls on a Thursday, apparently, the Friday after is # treated as a holiday as well. See 2003, 2008, for example. true elsif friday? # A Friday is a holiday if a fixed-date holiday # would fall on the following Saturday (self + 1).fed_fixed_holiday? || (self + 1).fed_moveable_feast? elsif monday? # A Monday is a holiday if a fixed-date holiday # would fall on the preceding Sunday (self - 1).fed_fixed_holiday? || (self - 1).fed_moveable_feast? elsif (year % 4 == 1) && year > 1965 && mon == 1 && mday == 20 # Inauguration Day after 1965 is a federal holiday, but if it falls on a # Sunday, the following Monday is observed, but if it falls on a # Saturday, the prior Friday is /not/ observed. So, we can't just count # this as a regular fixed holiday. true elsif monday? && (year % 4 == 1) && year > 1965 && mon == 1 && mday == 21 # Inauguration Day after 1965 is a federal holiday, but if it falls on a # Sunday, the following Monday is observed, but if it falls on a # Saturday, the prior Friday is /not/ observed. true else false end end
Return whether this date is a date on which the US federal government is open for business. It is the opposite of fed_holiday?
@return [Boolean]
# File lib/fat_core/date.rb, line 937 def fed_workday? !fed_holiday? end
Return the date that is n
calendar bimonths after this date, where a calendar bimonth is a period of 2 months.
@param num [Integer] number of bimonths to advance, can be negative @return [::Date] new date n bimonths after this date
# File lib/fat_core/date.rb, line 565 def next_bimonth(num = 1) num = num.floor return self if num.zero? next_month(num * 2) end
Return the date that is n
biweeks after this date where each biweek is 14 days.
@param num [Integer] number of biweeks to advance, can be negative @return [::Date] new date n biweeks after this date
# File lib/fat_core/date.rb, line 664 def next_biweek(num = 1) num = num.floor return self if num.zero? self + (14 * num) end
Return the next federal workday after this date. The date returned is always a date at least one day after this date, never this date.
@return [::Date]
# File lib/fat_core/date.rb, line 965 def next_fed_workday add_fed_workdays(1) end
Return the date that is n
calendar halves after this date, where a calendar half is a period of 6 months.
@param num [Integer] number of halves to advance, can be negative @return [::Date] new date n halves after this date
# File lib/fat_core/date.rb, line 523 def next_half(num = 1) num = num.floor return self if num.zero? next_month(num * 6) end
Return the next NYSE trading day after this date. The date returned is always a date at least one day after this date, never this date.
@return [::Date]
# File lib/fat_core/date.rb, line 1146 def next_nyse_workday add_nyse_workdays(1) end
Return the date that is n
calendar quarters after this date, where a calendar quarter is a period of 3 months.
@param num [Integer] number of quarters to advance, can be negative @return [::Date] new date n quarters after this date
# File lib/fat_core/date.rb, line 544 def next_quarter(num = 1) num = num.floor return self if num.zero? next_month(num * 3) end
Return the date that is n
semimonths after this date. Each semimonth begins on the 1st or 16th of the month, and advancing one semimonth from the first half of a month means to go as far past the 16th as the current date is past the 1st; advancing one semimonth from the second half of a month means to go as far into the next month past the 1st as the current date is past the 16th, but never past the 15th of the next month.
@param num [Integer] number of semimonths to advance, can be negative @return [::Date] new date n semimonths after this date
# File lib/fat_core/date.rb, line 590 def next_semimonth(num = 1) num = num.floor return self if num.zero? factor = num.negative? ? -1 : 1 num = num.abs if num.even? next_month(num / 2) else # Advance or retreat one semimonth next_sm = if day == 1 if factor.positive? beginning_of_month + 16.days else prior_month.beginning_of_month + 16.days end elsif day == 16 if factor.positive? next_month.beginning_of_month else beginning_of_month end elsif day < 16 # In the first half of the month (the 2nd to the 15th), go as far past # the 16th as the date is past the 1st. Thus, as many as 14 days past # the 16th, so at most to the 30th of the month unless there are less # than 30 days in the month, then go to the end of the month. if factor.positive? [beginning_of_month + 16.days + (day - 1).days, end_of_month].min else [prior_month.beginning_of_month + 16.days + (day - 1).days, prior_month.end_of_month].min end elsif factor.positive? # In the second half of the month (17th to the 31st), go as many # days into the next month as we are past the 16th. Thus, as many as # 15 days. But we don't want to go past the first half of the next # month, so we only go so far as the 15th of the next month. # ::Date.parse('2015-02-18').next_semimonth should be the 3rd of the # following month. next_month.beginning_of_month + [(day - 16), 15].min else beginning_of_month + [(day - 16), 15].min end num -= 1 # Now that n is even, advance (or retreat) n / 2 months unless we're done. if num >= 2 next_sm.next_month(factor * num / 2) else next_sm end end end
Return this date if its a federal workday, otherwise skip forward to the first later federal workday.
@return [::Date]
# File lib/fat_core/date.rb, line 981 def next_until_fed_workday date = dup date += 1 until date.fed_workday? date end
Return this date if its a trading day, otherwise skip forward to the first later trading day.
@return [::Date]
# File lib/fat_core/date.rb, line 1164 def next_until_trading_day date = dup date += 1 until date.trading_day? date end
Return the date that is n
weeks after this date where each week is 7 days. This is different from the next_week
method in active_support, which goes to the first day of the week in the next week and does not take an argument n
to go multiple weeks.
@param num [Integer] number of weeks to advance @return [::Date] new date n weeks after this date
# File lib/fat_core/date.rb, line 687 def next_week(num = 1) num = num.floor return self if num.zero? self + (7 * num) end
Return whether this date is the `n`th weekday `wday` of the given `month` in this date's year.
@param nth [Integer] number of wday in month, if negative count from end of
the month
@param wday [Integer] day of week, 0 is Sunday, 1 Monday, etc. @param month [Integer] the month number, 1 is January, 2 is February, etc. @return [Boolean]
# File lib/fat_core/date.rb, line 381 def nth_wday_in_month?(nth, wday, month) # Is self the nth weekday in the given month of its year? # If nth is negative, count from last day of month self == ::Date.nth_wday_in_year_month(nth, wday, year, month) end
Return whether this date is a fixed holiday for the NYSE, that is, a holiday that falls on the same date each year.
@return [Boolean]
# File lib/fat_core/date.rb, line 1184 def nyse_fixed_holiday? # Fixed-date holidays if mon == 1 && mday == 1 # New Years (January 1), true elsif mon == 7 && mday == 4 # Independence Day (July 4), true elsif mon == 12 && mday == 25 # Christmas (December 25), and true else false end end
Return whether the NYSE is open for trading on this date.
@return [Boolean]
# File lib/fat_core/date.rb, line 1118 def nyse_workday? !nyse_holiday? end
Return the date that is n
calendar bimonths before this date, where a calendar bimonth is a period of 2 months.
@param num [Integer] number of bimonths to retreat, can be negative @return [::Date] new date n bimonths before this date
# File lib/fat_core/date.rb, line 577 def prior_bimonth(num = 1) next_bimonth(-num) end
Return the date that is n
biweeks before this date where each biweek is 14 days.
@param num [Integer] number of biweeks to retreat, can be negative @return [::Date] new date n biweeks before this date
# File lib/fat_core/date.rb, line 676 def prior_biweek(num = 1) next_biweek(-num) end
Return the date that is n
weeks before this date where each week is 7 days.
@param num [Integer] number of days to retreat @return [::Date] new date n days before this date
# File lib/fat_core/date.rb, line 710 def prior_day(num) next_day(-num) end
Return the last federal workday before this date. The date returned is always a date at least one day before this date, never this date.
@return [::Date]
# File lib/fat_core/date.rb, line 973 def prior_fed_workday add_fed_workdays(-1) end
Return the date that is n
calendar halves before this date, where a calendar half is a period of 6 months.
@param num [Integer] number of halves to retreat, can be negative @return [::Date] new date n halves before this date
# File lib/fat_core/date.rb, line 535 def prior_half(num = 1) next_half(-num) end
Return the last NYSE trading day before this date. The date returned is always a date at least one day before this date, never this date.
@return [::Date]
# File lib/fat_core/date.rb, line 1155 def prior_nyse_workday add_nyse_workdays(-1) end
Return the date that is n
calendar quarters before this date, where a calendar quarter is a period of 3 months.
@param num [Integer] number of quarters to retreat, can be negative @return [::Date] new date n quarters after this date
# File lib/fat_core/date.rb, line 556 def prior_quarter(num = 1) next_quarter(-num) end
Return the date that is n
semimonths before this date. Each semimonth begins on the 1st or 15th of the month, and retreating one semimonth from the first half of a month means to go as far past the 15th of the prior month as the current date is past the 1st; retreating one semimonth from the second half of a month means to go as far past the 1st of the current month as the current date is past the 15th, but never past the 14th of the the current month.
@param num [Integer] number of semimonths to retreat, can be negative @return [::Date] new date n semimonths before this date
# File lib/fat_core/date.rb, line 655 def prior_semimonth(num = 1) next_semimonth(-num) end
Return this if its a federal workday, otherwise skip back to the first prior federal workday.
# File lib/fat_core/date.rb, line 989 def prior_until_fed_workday date = dup date -= 1 until date.fed_workday? date end
Return this date if its a trading day, otherwise skip back to the first prior trading day.
@return [::Date]
# File lib/fat_core/date.rb, line 1174 def prior_until_trading_day date = dup date -= 1 until date.trading_day? date end
Return the date that is n
weeks before this date where each week is 7 days.
@param num [Integer] number of weeks to retreat @return [::Date] new date n weeks from this date
# File lib/fat_core/date.rb, line 699 def prior_week(num) next_week(-num) end
Self's calendar semimonth: 1, through 24 depending on which calendar semimonth the date falls in. @return [Integer]
# File lib/fat_core/date.rb, line 173 def semimonth (month - 1) * 2 + (day <= 15 ? 1 : 2) end
Self's calendar week: just calls cweek. @return [Integer]
# File lib/fat_core/date.rb, line 190 def week cweek end
Does self fall on a weekend? @return [Boolean]
# File lib/fat_core/date.rb, line 833 def weekend? saturday? || sunday? end
Return whether this date falls within a period of less than six months from the date `d` using the *Stella v. Graham Page Motors* convention that “less” than six months is true only if this date falls within the range of dates 2 days after date six months before and 2 days before the date six months after the date `d`.
@param from_date [::Date] the middle of the six-month range @return [Boolean]
# File lib/fat_core/date.rb, line 356 def within_6mos_of?(from_date) # ::Date 6 calendar months before self start_date = self - 6.months + 2.days end_date = self + 6.months - 2.days (start_date..end_date).cover?(from_date) end
Protected Instance Methods
# File lib/fat_core/date.rb, line 997 def fed_fixed_holiday? # Fixed-date holidays on weekdays if mon == 1 && mday == 1 # New Years (January 1), true elsif mon == 7 && mday == 4 # Independence Day (July 4), true elsif mon == 11 && mday == 11 # Veterans Day (November 11), true elsif mon == 12 && mday == 25 # Christmas (December 25), and true else false end end
# File lib/fat_core/date.rb, line 1016 def fed_moveable_feast? # See if today is a "movable feast," all of which are # rigged to fall on Monday except Thanksgiving # No moveable feasts in certain months if [3, 4, 6, 7, 8, 12].include?(month) false elsif monday? moveable_mondays = [] # MLK's Birthday (Third Monday in Jan) moveable_mondays << nth_wday_in_month?(3, 1, 1) # Washington's Birthday (Third Monday in Feb) moveable_mondays << nth_wday_in_month?(3, 1, 2) # Memorial Day (Last Monday in May) moveable_mondays << nth_wday_in_month?(-1, 1, 5) # Labor Day (First Monday in Sep) moveable_mondays << nth_wday_in_month?(1, 1, 9) # Columbus Day (Second Monday in Oct) moveable_mondays << nth_wday_in_month?(2, 1, 10) # Other Mondays moveable_mondays.any? elsif thursday? # Thanksgiving Day (Fourth Thur in Nov) nth_wday_in_month?(4, 4, 11) else false end end
Formatting
↑ topPublic Instance Methods
Format date in `MM/DD/YYYY` form, as typical for the short American form. @return [String]
# File lib/fat_core/date.rb, line 110 def american strftime('%-m/%-d/%Y') end
Format as an English string, like `'January 12, 2016'` @return [String]
# File lib/fat_core/date.rb, line 101 def eng strftime('%B %-d, %Y') end
Format as an ISO string of the form `YYYY-MM-DD`. @return [String]
# File lib/fat_core/date.rb, line 64 def iso strftime('%Y-%m-%d') end
Format as an all-numeric string of the form `YYYYMMDD` @return [String]
# File lib/fat_core/date.rb, line 80 def num strftime('%Y%m%d') end
Format as an inactive Org date timestamp of the form `[YYYY-MM-DD <dow>]` (see Emacs org-mode) @return [String]
# File lib/fat_core/date.rb, line 89 def org(active = false) if active strftime('<%Y-%m-%d %a>') else strftime('[%Y-%m-%d %a]') end end
Format date to TeX documents as ISO strings but with en-dashes @return [String]
# File lib/fat_core/date.rb, line 72 def tex_quote strftime('%Y--%m--%d') end
Queries
↑ topPublic Instance Methods
Return the date that is n federal workdays after or before (if n < 0) this date.
@param num [Integer] number of federal workdays to add to this date @return [::Date]
# File lib/fat_core/date.rb, line 948 def add_fed_workdays(num) d = dup return d if num.zero? incr = num.negative? ? -1 : 1 num = num.abs while num.positive? d += incr num -= 1 if d.fed_workday? end d end
Return whether the date falls on the first day of a calendar bi-monthly period, i.e., the beginning of an odd-numbered month. @return [Boolean]
# File lib/fat_core/date.rb, line 247 def beginning_of_bimonth? month.odd? && beginning_of_month == self end
Return whether the date falls on the first day of a commercial bi-week, i.e., on /Monday/ in a commercial week that is an odd-numbered week. From ::Date: “The calendar week is a seven day period within a calendar year, starting on a Monday and identified by its ordinal number within the year; the first calendar week of the year is the one that includes the first Thursday of that year. In the Gregorian calendar, this is equivalent to the week which includes January 4.” @return [Boolean]
# File lib/fat_core/date.rb, line 304 def beginning_of_biweek? beginning_of_biweek == self end
Return whether the date falls on the first day of a half-year. @return [Boolean]
# File lib/fat_core/date.rb, line 214 def beginning_of_half? beginning_of_half == self end
Return whether the date falls on the first day of a calendar month. @return [Boolean]
# File lib/fat_core/date.rb, line 264 def beginning_of_month? beginning_of_month == self end
Return whether the date falls on the first day of a calendar quarter. @return [Boolean]
# File lib/fat_core/date.rb, line 230 def beginning_of_quarter? beginning_of_quarter == self end
Return whether the date falls on the first day of a calendar semi-monthly period, i.e., on the 1st or 15th of a month. @return [Boolean]
# File lib/fat_core/date.rb, line 281 def beginning_of_semimonth? beginning_of_semimonth == self end
Return whether the date falls on the first day of a commercial week, i.e., on /Monday/ in a commercial week. From ::Date: “The calendar week is a seven day period within a calendar year, starting on a Monday and identified by its ordinal number within the year; the first calendar week of the year is the one that includes the first Thursday of that year. In the Gregorian calendar, this is equivalent to the week which includes January 4.” @return [Boolean]
# File lib/fat_core/date.rb, line 331 def beginning_of_week? beginning_of_week == self end
Return whether the date falls on the first day of a year. @return [Boolean]
# File lib/fat_core/date.rb, line 198 def beginning_of_year? beginning_of_year == self end
Return whether the date falls on the last day of a calendar bi-monthly period, i.e., the end of an even-numbered month. @return [Boolean]
# File lib/fat_core/date.rb, line 256 def end_of_bimonth? month.even? && end_of_month == self end
Return whether the date falls on the last day of a commercial bi-week, i.e., on /Sunday/ in a commercial week that is an even-numbered week. From ::Date: “The calendar week is a seven day period within a calendar year, starting on a Monday and identified by its ordinal number within the year; the first calendar week of the year is the one that includes the first Thursday of that year. In the Gregorian calendar, this is equivalent to the week which includes January 4.” @return [Boolean]
# File lib/fat_core/date.rb, line 318 def end_of_biweek? end_of_biweek == self end
Return whether the date falls on the last day of a half-year. @return [Boolean]
# File lib/fat_core/date.rb, line 222 def end_of_half? end_of_half == self end
Return whether the date falls on the last day of a calendar month. @return [Boolean]
# File lib/fat_core/date.rb, line 272 def end_of_month? end_of_month == self end
Return whether the date falls on the last day of a calendar quarter. @return [Boolean]
# File lib/fat_core/date.rb, line 238 def end_of_quarter? end_of_quarter == self end
Return whether the date falls on the last day of a calendar semi-monthly period, i.e., on the 14th or the last day of a month. @return [Boolean]
# File lib/fat_core/date.rb, line 290 def end_of_semimonth? end_of_semimonth == self end
Return whether the date falls on the first day of a commercial week, i.e., on /Sunday/ in a commercial week. From ::Date: “The calendar week is a seven day period within a calendar year, starting on a Monday and identified by its ordinal number within the year; the first calendar week of the year is the one that includes the first Thursday of that year. In the Gregorian calendar, this is equivalent to the week which includes January 4.” @return [Boolean]
# File lib/fat_core/date.rb, line 344 def end_of_week? end_of_week == self end
Return whether the date falls on the last day of a year. @return [Boolean]
# File lib/fat_core/date.rb, line 206 def end_of_year? end_of_year == self end
Self's calendar “half” by analogy to calendar quarters: 1 or 2, depending on whether the date falls in the first or second half of the calendar year. @return [Integer]
# File lib/fat_core/date.rb, line 123 def half case month when (1..6) 1 when (7..12) 2 end end
Returns whether this date is one on which the NYSE was or is expected to be closed for business.
Calculations for NYSE holidays are from Rule 51 and supplementary materials for the Rules of the New York Stock Exchange, Inc.
-
General Rule 1: if a regular holiday falls on Saturday, observe it on the preceding Friday.
-
General Rule 2: if a regular holiday falls on Sunday, observe it on the following Monday.
These are the regular holidays:
-
New Year's Day, January 1.
-
Birthday of Martin Luther King, Jr., the third Monday in January.
-
Washington's Birthday, the third Monday in February.
-
Good Friday Friday before Easter Sunday. NOTE: this is not a fed holiday
-
Memorial Day, the last Monday in May.
-
Independence Day, July 4.
-
Labor Day, the first Monday in September.
-
Thanksgiving Day, the fourth Thursday in November.
-
Christmas Day, December 25.
Columbus and Veterans days not observed.
In addition, there have been several days on which the exchange has been closed for special events such as Presidential funerals, the 9-11 attacks, the paper-work crisis in the 1960's, hurricanes, etc. All of these are considered holidays for purposes of this method.
In addition, every weekend is considered a holiday.
@return [Boolean]
# File lib/fat_core/date.rb, line 1084 def nyse_holiday? # All Saturdays and Sundays are "holidays" return true if weekend? # Presidential funerals, observed by NYSE as well. return true if PRESIDENTIAL_FUNERALS.include?(self) # Is self a fixed holiday return true if nyse_fixed_holiday? || nyse_moveable_feast? return true if nyse_special_holiday? if friday? && (self >= ::Date.parse('1959-07-03')) # A Friday is a holiday if a holiday would fall on the following # Saturday. The rule does not apply if the Friday "ends a monthly or # yearly accounting period." Adopted July 3, 1959. E.g, December 31, # 2010, fell on a Friday, so New Years was on Saturday, but the NYSE # opened because it ended a yearly accounting period. I believe 12/31 # is the only date to which the exception can apply since only New # Year's can fall on the first of the month. !end_of_quarter? && ((self + 1).nyse_fixed_holiday? || (self + 1).nyse_moveable_feast?) elsif monday? # A Monday is a holiday if a holiday would fall on the # preceding Sunday. This has apparently always been the rule. (self - 1).nyse_fixed_holiday? || (self - 1).nyse_moveable_feast? else false end end
Return whether this date is a non-fixed holiday for the NYSE, that is, a holiday that can fall on different dates each year, a so-called “moveable feast”.
@return [Boolean]
# File lib/fat_core/date.rb, line 1206 def nyse_moveable_feast? # See if today is a "movable feast," all of which are # rigged to fall on Monday except Thanksgiving # No moveable feasts in certain months return false if [6, 7, 8, 10, 12].include?(month) case month when 1 # MLK's Birthday (Third Monday in Jan) since 1998 year >= 1998 && nth_wday_in_month?(3, 1, 1) when 2 # Washington's Birthday was celebrated on February 22 until 1970. In # 1971 and later, it was moved to the third Monday in February. Note: # Lincoln's birthday is not an official holiday, but is sometimes # included with Washington's and called "Presidents' Day." if year <= 1970 month == 2 && day == 22 else nth_wday_in_month?(3, 1, 2) end when 3, 4 # Good Friday if !friday? false elsif [1898, 1906, 1907].include?(year) # Good Friday, the Friday before Easter, except certain years false else (self + 2).easter? end when 5 # Memorial Day (Last Monday in May) year <= 1970 ? (month == 5 && day == 30) : nth_wday_in_month?(-1, 1, 5) when 9 # Labor Day (First Monday in Sep) nth_wday_in_month?(1, 1, 9) when 10 # Columbus Day (Oct 12) 1909--1953 year >= 1909 && year <= 1953 && day == 12 when 11 if tuesday? # Election Day. Until 1968 all Election Days. From 1972 to 1980 # Election Day in presidential years only. Election Day is the first # Tuesday after the first Monday in November. first_tuesday = ::Date.nth_wday_in_year_month(1, 1, year, 11) + 1 is_election_day = (self == first_tuesday) if year <= 1968 is_election_day elsif year <= 1980 is_election_day && (year % 4).zero? else false end elsif thursday? # Historically Thanksgiving (NYSE closed all day) had been declared to # be the last Thursday in November until 1938; the next-to-last # Thursday in November from 1939 to 1941 (therefore the 3rd Thursday # in 1940 and 1941); the last Thursday in November in 1942; the fourth # Thursday in November since 1943; if year < 1938 nth_wday_in_month?(-1, 4, 11) elsif year <= 1941 nth_wday_in_month?(3, 4, 11) elsif year == 1942 nth_wday_in_month?(-1, 4, 11) else nth_wday_in_month?(4, 4, 11) end elsif day == 11 # Armistice or Veterans Day. 1918--1921; 1934--1953. (year >= 1918 && year <= 1921) || (year >= 1934 && year <= 1953) else false end else false end end
They NYSE has closed on several occasions outside its normal holiday rules. This detects those dates beginning in 1960. Closing for part of a day is not counted. See www1.nyse.com/pdfs/closings.pdf. Return whether this date is one of those special closings.
@return [Boolean]
# File lib/fat_core/date.rb, line 1294 def nyse_special_holiday? return false unless self > ::Date.parse('1960-01-01') return true if PRESIDENTIAL_FUNERALS.include?(self) case self when ::Date.parse('1961-05-29') # Day before Decoaration Day true when ::Date.parse('1963-11-25') # President Kennedy's funeral true when ::Date.parse('1965-12-24') # Christmas eve unscheduled for normal holiday true when ::Date.parse('1968-02-12') # Lincoln birthday true when ::Date.parse('1968-04-09') # Mourning MLK true when ::Date.parse('1968-07-05') # Day after Independence Day true when (::Date.parse('1968-06-12')..::Date.parse('1968-12-31')) # Paperwork crisis (closed on Wednesdays if no other holiday in week) wednesday? && (self - 2).nyse_workday? && (self - 1).nyse_workday? && (self + 1).nyse_workday? && (self + 2).nyse_workday? when ::Date.parse('1969-02-10') # Heavy snow true when ::Date.parse('1969-07-21') # Moon landing true when ::Date.parse('1977-07-14') # Electrical blackout NYC true when ::Date.parse('1985-09-27') # Hurricane Gloria true when (::Date.parse('2001-09-11')..::Date.parse('2001-09-14')) # 9-11 Attacks true when ::Date.parse('2007-01-02') # Observance death of President Ford true when ::Date.parse('2012-10-29'), ::Date.parse('2012-10-30') # Hurricane Sandy true else false end end
Self's calendar quarter: 1, 2, 3, or 4, depending on which calendar quarter the date falls in. @return [Integer]
# File lib/fat_core/date.rb, line 137 def quarter case month when (1..3) 1 when (4..6) 2 when (7..9) 3 when (10..12) 4 end end
Does self fall on a weekday? @return [Boolean]
# File lib/fat_core/date.rb, line 841 def weekday? !weekend? end
Relative ::Dates
↑ topPublic Instance Methods
Return the date that is n chunks later than self.
@param chunk [Symbol] one of :year
, :half
, :quarter
, :bimonth
,
+:month+, +:semimonth+, +:biweek+, +:week+, or +:day+.
@param num [Integer] the number of chunks to add, can be negative @return [::Date] the date n chunks from this date
# File lib/fat_core/date.rb, line 722 def add_chunk(chunk, num = 1) case chunk when :year next_year(num) when :half next_month(6 * num) when :quarter next_month(3 * num) when :bimonth next_month(2 * num) when :month next_month(num) when :semimonth next_semimonth(num) when :biweek next_biweek(num) when :week next_week(num) when :day next_day(num) else raise ArgumentError, "add_chunk unknown chunk: '#{chunk}'" end end
The date that is the first day of the bimonth in which self falls. A 'bimonth' is a two-month calendar period beginning on the first day of the odd-numbered months. E.g., 2014-01-01 to 2014-02-28 is the first bimonth of 2014. @return [::Date]
# File lib/fat_core/date.rb, line 431 def beginning_of_bimonth if month.odd? beginning_of_month else (self - 1.month).beginning_of_month end end
Return the date that is the first day of the commercial biweek in which self falls. A biweek is a period of two commercial weeks starting with an odd-numbered week and with each week starting in Monday and ending on Sunday. @return [::Date]
# File lib/fat_core/date.rb, line 491 def beginning_of_biweek if cweek.odd? beginning_of_week(:monday) else (self - 1.week).beginning_of_week(:monday) end end
The date that is the first day of the semimonth in which self falls. A semimonth is a calendar period beginning on the 1st or 16th of each month and ending on the 15th or last day of the month respectively. So each year has exactly 24 semimonths. @return [::Date]
# File lib/fat_core/date.rb, line 461 def beginning_of_semimonth if day >= 16 ::Date.new(year, month, 16) else beginning_of_month end end
The date that is the last day of the bimonth in which self falls. A 'bimonth' is a two-month calendar period beginning on the first day of the odd-numbered months. E.g., 2014-01-01 to 2014-02-28 is the first bimonth of 2014. @return [::Date]
# File lib/fat_core/date.rb, line 446 def end_of_bimonth if month.odd? (self + 1.month).end_of_month else end_of_month end end
Return the date that is the last day of the commercial biweek in which self falls. A biweek is a period of two commercial weeks starting with an odd-numbered week and with each week starting in Monday and ending on Sunday. So this will always return a Sunday in an even-numbered week. In the last week of the year (if it is not part of next year's first week) the end of the biweek will not extend beyond self's week, so that week 1 of the following year will start a new biweek. @return [::Date]
# File lib/fat_core/date.rb, line 508 def end_of_biweek if cweek >= 52 && end_of_week(:monday).year > year end_of_week(:monday) elsif cweek.odd? (self + 1.week).end_of_week(:monday) else end_of_week(:monday) end end
The date that is the last day of the half-year in which self falls. @return [::Date]
# File lib/fat_core/date.rb, line 414 def end_of_half if month < 4 (end_of_quarter + 15).end_of_quarter elsif month < 7 end_of_quarter else end_of_year end end
The date that is the last day of the semimonth in which self falls. A semimonth is a calendar period beginning on the 1st or 16th of each month and ending on the 15th or last day of the month respectively. So each year has exactly 24 semimonths. @return [::Date]
# File lib/fat_core/date.rb, line 476 def end_of_semimonth if day <= 15 ::Date.new(year, month, 15) else end_of_month end end
Predecessor of self, opposite of `#succ`. @return [::Date]
# File lib/fat_core/date.rb, line 392 def pred self - 1.day end