Class: IncompleteDate
- Inherits:
-
Object
- Object
- IncompleteDate
- Defined in:
- lib/incomplete_date.rb,
lib/incomplete_date/version.rb,
lib/incomplete_date/active_record.rb
Defined Under Namespace
Modules: IncompleteDateAttr
Constant Summary collapse
- VALID_DATE_PARTS =
[:year, :month, :day, :circa]
- VERSION =
'0.1.2'
Instance Attribute Summary collapse
-
#circa ⇒ Object
Returns the value of attribute circa.
-
#day ⇒ Object
(also: #mday)
Returns the value of attribute day.
-
#month ⇒ Object
Returns the value of attribute month.
-
#year ⇒ Object
Returns the value of attribute year.
Class Method Summary collapse
-
.leap_year?(year) ⇒ Boolean
Returns
true
if the given year is a leap year,false
otherwise. - .max_month_days(month = nil, year = nil) ⇒ Object
Instance Method Summary collapse
- #[](part_name) ⇒ Object
- #[]=(part_name, value) ⇒ Object
- #circa? ⇒ Boolean
- #complete? ⇒ Boolean
- #defined_parts ⇒ Object
- #defines_birthday? ⇒ Boolean
- #empty? ⇒ Boolean
- #exact? ⇒ Boolean
- #has?(*parts) ⇒ Boolean
- #has_day? ⇒ Boolean
- #has_month? ⇒ Boolean
- #has_year? ⇒ Boolean
-
#highest ⇒ Object
(also: #max, #last)
Returns the highest possible date that matches this incomplete date.
-
#include?(date) ⇒ Boolean
Returns
true
if the given date is included in the possible set of complete dates that match this incomplete date. -
#incomplete? ⇒ Boolean
– Testing completeness ++.
-
#initialize(value) ⇒ IncompleteDate
constructor
A new instance of IncompleteDate.
-
#lowest ⇒ Object
(also: #min, #first)
Returns the lowest possible date that matches this incomplete date.
-
#to_birthday ⇒ Object
Returns an incomplete date which only has the birthday parts (month and day) taken from this incomplete date.
-
#to_date(opts = {}) ⇒ Object
Converts this incomplete date to a standard date value.
- #to_hash ⇒ Object
-
#to_i ⇒ Object
Converts this incomplete date to its equivalent integer representation suitable for the database layer.
- #to_incomplete_date ⇒ Object
-
#to_range ⇒ Object
Returns the range of dates that are included or match with this incomplete date.
- #to_s ⇒ Object
- #valid_day?(day, month = nil, year = nil) ⇒ Boolean
- #valid_month?(month) ⇒ Boolean
- #valid_year?(year, month = nil, day = nil) ⇒ Boolean
Constructor Details
#initialize(value) ⇒ IncompleteDate
Returns a new instance of IncompleteDate.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/incomplete_date.rb', line 10 def initialize(value) @circa = false case value when Integer @circa = (value < 0) num = value.abs num, @day = num.divmod(100) @year, @month = num.divmod(100) when Hash @day, @month, @year = value[:day], value[:month], value[:year] @circa = value.fetch(:circa, false) when Date @day, @month, @year = value.mday, value.month, value.year when IncompleteDate @day, @month, @year, @circa = value.day, value.month, value.year, value.circa when nil #invaluable for existing databases! @day, @month, @year, @circa = 0, 0, 0, false else raise ArgumentError, "Invalid #{self.class.name} specification" end @day = nil if @day == 0 @month = nil if @month == 0 @year = nil if @year == 0 end |
Instance Attribute Details
#circa ⇒ Object
Returns the value of attribute circa.
7 8 9 |
# File 'lib/incomplete_date.rb', line 7 def circa @circa end |
#day ⇒ Object Also known as: mday
Returns the value of attribute day.
6 7 8 |
# File 'lib/incomplete_date.rb', line 6 def day @day end |
#month ⇒ Object
Returns the value of attribute month.
6 7 8 |
# File 'lib/incomplete_date.rb', line 6 def month @month end |
#year ⇒ Object
Returns the value of attribute year.
6 7 8 |
# File 'lib/incomplete_date.rb', line 6 def year @year end |
Class Method Details
.leap_year?(year) ⇒ Boolean
Returns true
if the given year is a leap year, false
otherwise.
44 45 46 47 |
# File 'lib/incomplete_date.rb', line 44 def self.leap_year?(year) raise ArgumentError, "year cannot be null or zero" if year.nil? or year.zero? (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0) end |
.max_month_days(month = nil, year = nil) ⇒ Object
49 50 51 52 53 54 55 56 57 |
# File 'lib/incomplete_date.rb', line 49 def self.max_month_days(month = nil, year = nil) year ||= 2000 # Assume a leap year if year is not known case month when nil,1,3,5,7,8,10,12 then 31 when 4,6,9,11 then 30 when 2 then leap_year?(year) ? 29 : 28 else raise ArgumentError, "invalid month" end end |
Instance Method Details
#[](part_name) ⇒ Object
101 102 103 104 |
# File 'lib/incomplete_date.rb', line 101 def [](part_name) raise ArgumentError, "Invalid date part #{part_name}" unless VALID_DATE_PARTS.include?(part_name) self.send(part_name) end |
#[]=(part_name, value) ⇒ Object
106 107 108 109 |
# File 'lib/incomplete_date.rb', line 106 def []=(part_name, value) raise ArgumentError, "Invalid date part #{part_name}" unless VALID_DATE_PARTS.include?(part_name) self.send("#{part_name}=", value) end |
#circa? ⇒ Boolean
95 96 97 |
# File 'lib/incomplete_date.rb', line 95 def circa? @circa end |
#complete? ⇒ Boolean
119 120 121 |
# File 'lib/incomplete_date.rb', line 119 def complete? !incomplete? end |
#defined_parts ⇒ Object
152 153 154 |
# File 'lib/incomplete_date.rb', line 152 def defined_parts VALID_DATE_PARTS.reject { |part| (part == :circa) || self[part].nil? } end |
#defines_birthday? ⇒ Boolean
148 149 150 |
# File 'lib/incomplete_date.rb', line 148 def defines_birthday? has_day? && has_month? end |
#empty? ⇒ Boolean
127 128 129 |
# File 'lib/incomplete_date.rb', line 127 def empty? @day.nil? && @month.nil? && @year.nil? end |
#exact? ⇒ Boolean
123 124 125 |
# File 'lib/incomplete_date.rb', line 123 def exact? complete? && !circa? end |
#has?(*parts) ⇒ Boolean
131 132 133 134 |
# File 'lib/incomplete_date.rb', line 131 def has?(*parts) parts.collect!(&:to_sym) parts.inject(true) { |total,part| total && !self.send(part).nil? } end |
#has_day? ⇒ Boolean
136 137 138 |
# File 'lib/incomplete_date.rb', line 136 def has_day? !@day.nil? end |
#has_month? ⇒ Boolean
140 141 142 |
# File 'lib/incomplete_date.rb', line 140 def has_month? !@month.nil? end |
#has_year? ⇒ Boolean
144 145 146 |
# File 'lib/incomplete_date.rb', line 144 def has_year? !@year.nil? end |
#highest ⇒ Object Also known as: max, last
Returns the highest possible date that matches this incomplete date.
Only defined if this incomplete date has the year part defined. Otherwise it returns nil
.
see #lowest
198 199 200 201 202 203 |
# File 'lib/incomplete_date.rb', line 198 def highest return nil unless has_year? max_month = self.month || 12 max_day = self.day || IncompleteDate.max_month_days(max_month, self.year) Date.civil(self.year, max_month, max_day) end |
#include?(date) ⇒ Boolean
Returns true
if the given date is included in the possible set of complete dates that match this incomplete date.
For instance 2003-xx-xx includes 2003-12-24 (or any date within the year 2003) but it does not include 1999-12-14, for instance.
The argument can be either a Date instance or an IncompleteDate instance.
169 170 171 172 173 |
# File 'lib/incomplete_date.rb', line 169 def include?(date) (self.year.nil? || (date.year == self.year)) && (self.month.nil? || (date.month == self.month)) && (self.day.nil? || (date.mday == self.mday)) end |
#incomplete? ⇒ Boolean
– Testing completeness ++
115 116 117 |
# File 'lib/incomplete_date.rb', line 115 def incomplete? @day.nil? || @month.nil? || @year.nil? end |
#lowest ⇒ Object Also known as: min, first
Returns the lowest possible date that matches this incomplete date.
Only defined if this incomplete date has the year part defined. Otherwise it returns nil
.
see #highest
183 184 185 186 |
# File 'lib/incomplete_date.rb', line 183 def lowest return nil unless has_year? Date.civil(self.year, self.month || 1, self.day || 1) end |
#to_birthday ⇒ Object
Returns an incomplete date which only has the birthday parts (month and day) taken from this incomplete date. If the needed date parts are not defined, it returns nil
.
216 217 218 219 |
# File 'lib/incomplete_date.rb', line 216 def to_birthday return nil unless defines_birthday? IncompleteDate.new(:month => month, :day => day) end |
#to_date(opts = {}) ⇒ Object
Converts this incomplete date to a standard date value. Any missing date parts can be provided by the hash argument, or else are taken from today’s date, or a reference date that be given as an optional argument with key :ref
. In the case of the day missing and not explicitely provided, it defaults to 1, and not to the reference date.
228 229 230 231 232 233 234 |
# File 'lib/incomplete_date.rb', line 228 def to_date(opts = {}) ref = opts.fetch(:ref, Date.today) Date.civil( (self.year || opts[:year] || ref.year).to_i, (self.month || opts[:month] || ref.month).to_i, (self.day || opts[:day] || 1).to_i) end |
#to_hash ⇒ Object
290 291 292 293 294 |
# File 'lib/incomplete_date.rb', line 290 def to_hash result = {} VALID_DATE_PARTS.each { |part| result[part] = self.send(part) } result end |
#to_i ⇒ Object
Converts this incomplete date to its equivalent integer representation suitable for the database layer.
The two less significant digits in the decimal representation of the number are the day of the month. The next two less significant digits represent the month (numbered from 01 to 12) and the rest of the digits represent the year. In any case a value of zero means that that particular part of the date is not known. Finally, the sign of the number represents wether the date is considered to be uncertain (negative) or certain (positive).
This representation relies on the fact there was no year 0 in the Gregorian or Julian calendars (see en.wikipedia.org/wiki/Year_zero).
The integer value zero represents a date that is completely unknown, so it is somehow equivalent to nil
in terms of meaning, and it is questionable that we allow instances of this class with such a configuration.
258 259 260 261 |
# File 'lib/incomplete_date.rb', line 258 def to_i y,m,d = [year,month,day].collect(&:to_i) # converts +nil+ values to zero (circa ? -1 : 1) * (d + m*100 + y*10000) end |
#to_incomplete_date ⇒ Object
236 237 238 |
# File 'lib/incomplete_date.rb', line 236 def to_incomplete_date self end |
#to_range ⇒ Object
Returns the range of dates that are included or match with this incomplete date.
Uses #lowest and #highest to determine the extremes of the range. Returns nil
if the year is not defined.
286 287 288 |
# File 'lib/incomplete_date.rb', line 286 def to_range has_year? ? (min..max) : nil end |
#to_s ⇒ Object
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/incomplete_date.rb', line 263 def to_s dt = to_date ord = has_day? ? dt.day.ordinalize : nil result = case defined_parts when [:year, :month, :day] then dt.strftime("%B #{ord}, %Y") when [:year, :month] then dt.strftime("%B %Y") when [:month, :day] then dt.strftime("%B #{ord}") when [:year, :day] then dt.strftime("#{ord} of the month, %Y") when [:year] then dt.strftime("%Y") when [:month] then dt.strftime("%B") when [:day] then "#{ord} of the month" else return "unknown" end circa ? "c. #{result}" : result end |
#valid_day?(day, month = nil, year = nil) ⇒ Boolean
59 60 61 62 63 |
# File 'lib/incomplete_date.rb', line 59 def valid_day?(day, month = nil, year = nil) return true if day.nil? || day.zero? max = IncompleteDate.max_month_days(month || self.month, year || self.year) (1..max).include?(day) end |
#valid_month?(month) ⇒ Boolean
65 66 67 68 |
# File 'lib/incomplete_date.rb', line 65 def valid_month?(month) return true if month.nil? || month.zero? (1..12).include?(month) && valid_day?(self.day, month) end |
#valid_year?(year, month = nil, day = nil) ⇒ Boolean
70 71 72 73 74 75 |
# File 'lib/incomplete_date.rb', line 70 def valid_year?(year, month = nil, day = nil) return true if year.nil? || year.zero? day ||= self.day month ||= self.month !(!IncompleteDate.leap_year?(year) && (day == 29) && (month == 2)) end |