Created
April 13, 2011 15:44
-
-
Save mark/917784 to your computer and use it in GitHub Desktop.
This was the date class I wrote like 5 years ago
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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