Skip to content

Instantly share code, notes, and snippets.

@mark
Created April 13, 2011 15:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mark/917784 to your computer and use it in GitHub Desktop.
Save mark/917784 to your computer and use it in GitHub Desktop.
This was the date class I wrote like 5 years ago
class MyDate
include Comparable
MyDatesInMonth = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
MonthsOfYear = [nil, :January, :February, :March, :April, :May, :June,
:July, :August, :September, :October, :November, :December]
MyDatesOfWeek = [:Sunday, :Monday, :Tuesday, :Wednesday, :Thursday, :Friday, :Saturday]
def initialize(year, month, day, fixed = true)
@year = year
@month = month
@day = day
@fixed = fixed
simplify
end
def self.from_date(date)
raise TypeException unless date.kind_of?(Date) || date.kind_of?(Time)
MyDate.new(date.year, date.month, date.day)
end
def self.today
now = Time.now
MyDate.new(now.year, now.month, now.day)
end
def self.parse( date )
MyDate.from_date(Date.parse(date))
end
# Accessors
def year
@year
end
def month
@month
end
def month_name
MonthsOfYear[month].to_s
end
def day
@day
end
def day_of_week
# This is cheating, but ok for now
Date.new(year, month, day).wday
end
def weekend?
[0, 6].include? day_of_week
end
def weekday?
[1, 2, 3, 4, 5].include? day_of_week
end
def day_of_week_name
MyDatesOfWeek[day_of_week].to_s
end
def weekend?
day_of_week == 0 || day_of_week == 6
end
def fixed?
@fixed
end
def self.years(n)
MyDate.new(n, 0, 0, false)
end
def self.months(n)
MyDate.new(0, n, 0, false)
end
def self.days(n)
MyDate.new(0, 0, n, false)
end
def days_in_month
return null if not fixed?
if month == 2 && leap_year
return 29
else
return MyDatesInMonth[month]
end
end
def leap_year
(year % 4 == 0) && (! (year % 100 == 0) || (year % 400 == 0))
end
def +(other)
if other.class == Fixnum
MyDate.new(year, month, day + other, fixed?)
elsif other.class == MyDate
raise ArgumentError, "Cannot add two fixed MyDates", caller if fixed? && other.fixed?
MyDate.new(year + other.year, month + other.month, day + other.day, fixed? || other.fixed?)
else
raise ArgumentError, "Cannot add a MyDate and a #{other.class}", caller
end
end
def -(other)
if other.kind_of? Fixnum
MyDate.new(year, month, day - other, fixed?)
elsif other.kind_of? MyDate
if self == other
MyDate.new(0, 0, 0, false)
else
MyDate.new(year - other.year, month - other.month, day - other.day, fixed? || other.fixed?)
end
else
raise TypeError, "Cannot add a MyDate and a #{other.class}", caller
end
end
def to_s
"#{month}/#{day}/#{year}"
end
def strftime(format_string)
Date.new(year, month, day).strftime(format_string)
end
# For Comparable
def <=>(other)
raise TypeError unless other.kind_of?(MyDate) || other.kind_of?(Date) || other.kind_of?(Time)
if year == other.year
if month == other.month
if day == other.day
0
else
day <=> other.day
end
else
month <=> other.month
end
else
year <=> other.year
end
end
def succ
MyDate.new(year, month, day + 1, fixed?)
end
# Start & End ofs
def start_of_week
self - day_of_week
end
def start_of_month
MyDate.new(year, month, 1)
end
def end_of_week
self + (6 - day_of_week)
end
def end_of_month
MyDate.new(year, month, days_in_month)
end
def day_of
MyDateRange.new(self, self)
end
def week_of
MyDateRange.new(start_of_week, end_of_week)
end
def month_of
MyDateRange.new(start_of_month, end_of_month)
end
def cal
puts "#{month_name} #{year}".center(20)
puts " S M Tu W Th F S"
month_of_in_weeks.each do |week|
puts week.inject('') { |so_far, day| so_far += month == day.month ? "#{day.day}".rjust(3) : " "}[1, -1]
end
nil
end
private
def resolve_months
while month > 12
@month -= 12
@year += 1
end
while month < 1
@month += 12
@year -= 1
end
end
def resolve_days
while day > days_in_month
@day -= days_in_month
@month += 1
resolve_months
end
while day < 1
@month -= 1
resolve_months
@day += days_in_month
end
end
def simplify
if fixed?
resolve_months
resolve_days
end
end
end
class MyDateRange
include Enumerable
def initialize(s_day, e_day)
@start_day = s_day
@end_day = e_day
end
def each
(start_day..end_day).each do |day|
yield(day)
end
self
end
def start_day
@start_day
end
def end_day
@end_day
end
def day_after
end_day + 1
end
def day_before
start_day - 1
end
def loop(step)
current = start_day
while current <= end_day
yield(current)
current += step
end
self
end
def each_week
week_range = MyDateRange.new(start_day.start_of_week, end_day)
week_range.loop(7) { |day| yield(MyDateRange.new(day, day + 6)) }
end
def in_weeks
weeks = []
each_week { |week| weeks << week }
weeks
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment