Class: ThirdBase::Date
- Inherits:
-
Object
- Object
- ThirdBase::Date
- Includes:
- Comparable
- Defined in:
- lib/third_base/date.rb
Overview
ThirdBase’s date class, a simple class which, unlike the standard Date class, does not include any time information.
This class is significantly faster than the standard Date class for two reasons. First, it does not depend on the Rational class (which is slow). Second, it doesn’t convert all dates to julian dates unless it is necessary.
Direct Known Subclasses
Constant Summary collapse
- MONTHNAMES =
[nil] + %w(January February March April May June July August September October November December)
- ABBR_MONTHNAMES =
[nil] + %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
- MONTH_NUM_MAP =
{}
- DAYNAMES =
%w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
- ABBR_DAYNAMES =
%w(Sun Mon Tue Wed Thu Fri Sat)
- DAY_NUM_MAP =
{}
- CUMMULATIVE_MONTH_DAYS =
{1=>0, 2=>31, 3=>59, 4=>90, 5=>120, 6=>151, 7=>181, 8=>212, 9=>243, 10=>273, 11=>304, 12=>334}
- LEAP_CUMMULATIVE_MONTH_DAYS =
{1=>0, 2=>31, 3=>60, 4=>91, 5=>121, 6=>152, 7=>182, 8=>213, 9=>244, 10=>274, 11=>305, 12=>335}
- DAYS_IN_MONTH =
{1=>31, 2=>28, 3=>31, 4=>30, 5=>31, 6=>30, 7=>31, 8=>31, 9=>30, 10=>31, 11=>30, 12=>31}
- LEAP_DAYS_IN_MONTH =
{1=>31, 2=>29, 3=>31, 4=>30, 5=>31, 6=>30, 7=>31, 8=>31, 9=>30, 10=>31, 11=>30, 12=>31}
- MONTHNAME_RE_PATTERN =
"(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december)"
- FULL_MONTHNAME_RE_PATTERN =
"(january|february|march|april|may|june|july|august|september|october|november|december)"
- ABBR_MONTHNAME_RE_PATTERN =
"(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)"
- FULL_DAYNAME_RE_PATTERN =
"(sunday|monday|tuesday|wednesday|thursday|friday|saturday)"
- ABBR_DAYNAME_RE_PATTERN =
"(sun|mon|tue|wed|thu|fri|sat)"
- PARSER_LIST =
[]
- DEFAULT_PARSER_LIST =
[:iso, :us, :num]
- PARSERS =
{}
- DEFAULT_PARSERS =
{}
- STRFTIME_RE =
/%./o
- STRPTIME_PROC_A =
proc{|h,x| h[:cwday] = DAY_NUM_MAP[x.downcase]}
- STRPTIME_PROC_B =
proc{|h,x| h[:month] = MONTH_NUM_MAP[x.downcase]}
- STRPTIME_PROC_C =
proc{|h,x| h[:year] ||= x.to_i*100}
- STRPTIME_PROC_d =
proc{|h,x| h[:day] = x.to_i}
- STRPTIME_PROC_G =
proc{|h,x| h[:cwyear] = x.to_i}
- STRPTIME_PROC_g =
proc{|h,x| h[:cwyear] = two_digit_year(x)}
- STRPTIME_PROC_j =
proc{|h,x| h[:yday] = x.to_i}
- STRPTIME_PROC_m =
proc{|h,x| h[:month] = x.to_i}
- STRPTIME_PROC_u =
proc{|h,x| h[:cwday] = x.to_i}
- STRPTIME_PROC_V =
proc{|h,x| h[:cweek] = x.to_i}
- STRPTIME_PROC_y =
proc{|h,x| h[:year] = two_digit_year(x)}
- STRPTIME_PROC_Y =
proc{|h,x| h[:year] = x.to_i}
- UNIXEPOCH =
2440588
Class Method Summary collapse
-
.add_parser(type, re, &block) ⇒ Object
Add a parser to the parser type.
-
.add_parser_type(type) ⇒ Object
Add a parser type to the list of parser types.
-
.civil(year, mon, day) ⇒ Object
Returns a new Date with the given year, month, and day.
-
.commercial(cwyear, cweek, cwday = 5) ⇒ Object
Returns a new Date with the given commercial week year, commercial week, and commercial week day.
-
.jd(j) ⇒ Object
Returns a new Date with the given julian date.
-
.new(*args) ⇒ Object
Calls civil with the given arguments.
- .new! ⇒ Object
-
.ordinal(year, yday) ⇒ Object
Returns a new Date with the given year and day of year.
-
.parse(str, opts = {}) ⇒ Object
Parses the given string and returns a Date.
-
.reset_parsers! ⇒ Object
Reset the parsers, parser types, and order of parsers used to the default.
-
.strptime(str, fmt = strptime_default) ⇒ Object
Parse the string using the provided format (or the default format).
-
.today ⇒ Object
Returns a date with the current year, month, and date.
-
.use_parsers(*parsers) ⇒ Object
Set the order of parser types to use to the given parser types.
Instance Method Summary collapse
-
#+(d) ⇒ Object
Returns a new date with d number of days added to this date.
-
#-(d) ⇒ Object
Returns a new date with d number of days subtracted from this date.
-
#<<(m) ⇒ Object
Returns a new date with m number of months subtracted from this date.
-
#<=>(date) ⇒ Object
Compare two dates.
-
#==(date) ⇒ Object
(also: #eql?)
Dates are equel only if their year, month, and day match.
-
#===(d) ⇒ Object
If d is a date, only true if it is equal to this date.
-
#>>(m) ⇒ Object
Returns a new date with m number of months added to this date.
-
#cwday ⇒ Object
The commercial week day for this date.
-
#cweek ⇒ Object
The commercial week for this date.
-
#cwyear ⇒ Object
The commercial week year for this date.
-
#day ⇒ Object
(also: #mday)
The day of the month for this date.
-
#downto(d, &block) ⇒ Object
Yield every date between this date and given date to the block.
-
#hash ⇒ Object
Unique value for this date, based on it’s year, month, and day of month.
-
#initialize(opts) ⇒ Date
constructor
Called by Date.new!, Takes a hash with one of the following keys:.
-
#inspect ⇒ Object
Programmer friendly readable string, much more friendly than the one in the standard date class.
-
#jd ⇒ Object
This date’s julian date.
-
#leap? ⇒ Boolean
Whether this date is in a leap year.
-
#mon ⇒ Object
(also: #month)
The month number for this date (January is 1, December is 12).
-
#step(limit, step = 1) ⇒ Object
Yield each date between this date and limit, adding step number of days in each iteration.
-
#strftime(fmt = strftime_default) ⇒ Object
Format the time using a format string, or the default format string.
-
#succ ⇒ Object
(also: #next)
Return the day after this date.
-
#to_s ⇒ Object
Alias for strftime with the default format.
-
#upto(d, &block) ⇒ Object
Yield every date between this date and the given date to the block.
-
#wday ⇒ Object
Return the day of the week for this date.
-
#yday ⇒ Object
Return the day of the year for this date.
-
#year ⇒ Object
Return the year for this date.
Constructor Details
#initialize(opts) ⇒ Date
Called by Date.new!, Takes a hash with one of the following keys:
-
:civil : should be an array with 3 elements, a year, month, and day
-
:commercial : should be an array with 3 elements, a commercial week year, commercial week, and commercial week day
-
:jd : should be an integer specifying the julian date
-
:ordinal : should be an array with 2 elements, a year and day of year.
An ArgumentError is raised if the date is invalid. All Date objects are immutable once created.
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/third_base/date.rb', line 309 def initialize(opts) if opts[:civil] @year, @mon, @day = opts[:civil] raise(ArgumentError, "invalid date") unless @year.is_a?(Integer) && @mon.is_a?(Integer) && @day.is_a?(Integer) && valid_civil? elsif opts[:ordinal] @year, @yday = opts[:ordinal] raise(ArgumentError, "invalid date") unless @year.is_a?(Integer) && @yday.is_a?(Integer) && valid_ordinal? elsif opts[:jd] @jd = opts[:jd] raise(ArgumentError, "invalid date") unless @jd.is_a?(Integer) elsif opts[:commercial] @cwyear, @cweek, @cwday = opts[:commercial] raise(ArgumentError, "invalid date") unless @cwyear.is_a?(Integer) && @cweek.is_a?(Integer) && @cwday.is_a?(Integer) && valid_commercial? else raise(ArgumentError, "invalid date format") end end |
Class Method Details
.add_parser(type, re, &block) ⇒ Object
Add a parser to the parser type. re should be a Regexp, and a block must be provided. The block should take a single MatchData argument, a return either nil specifying it could not parse the string, or a hash of values to be passed to new!.
99 100 101 |
# File 'lib/third_base/date.rb', line 99 def self.add_parser(type, re, &block) parser_hash[type].unshift([re, block]) end |
.add_parser_type(type) ⇒ Object
Add a parser type to the list of parser types. Should be used if you want to add your own parser types.
106 107 108 |
# File 'lib/third_base/date.rb', line 106 def self.add_parser_type(type) parser_hash[type] ||= [] end |
.civil(year, mon, day) ⇒ Object
Returns a new Date with the given year, month, and day.
111 112 113 |
# File 'lib/third_base/date.rb', line 111 def self.civil(year, mon, day) new!(:civil=>[year, mon, day]) end |
.commercial(cwyear, cweek, cwday = 5) ⇒ Object
Returns a new Date with the given commercial week year, commercial week, and commercial week day.
117 118 119 |
# File 'lib/third_base/date.rb', line 117 def self.commercial(cwyear, cweek, cwday=5) new!(:commercial=>[cwyear, cweek, cwday]) end |
.jd(j) ⇒ Object
Returns a new Date with the given julian date.
122 123 124 |
# File 'lib/third_base/date.rb', line 122 def self.jd(j) new!(:jd=>j) end |
.new(*args) ⇒ Object
Calls civil with the given arguments.
127 128 129 |
# File 'lib/third_base/date.rb', line 127 def self.new(*args) civil(*args) end |
.new! ⇒ Object
91 |
# File 'lib/third_base/date.rb', line 91 alias new! new |
.ordinal(year, yday) ⇒ Object
Returns a new Date with the given year and day of year.
132 133 134 |
# File 'lib/third_base/date.rb', line 132 def self.ordinal(year, yday) new!(:ordinal=>[year, yday]) end |
.parse(str, opts = {}) ⇒ Object
Parses the given string and returns a Date. Raises an ArgumentError if no parser can correctly parse the date. Takes the following options:
-
:parser_types : an array of parser types to use, overriding the default or the ones specified by use_parsers.
142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/third_base/date.rb', line 142 def self.parse(str, opts={}) s = str.strip parsers(opts[:parser_types]) do |pattern, block| if m = pattern.match(s) if res = block.call(m) return new!(res) end end end raise ArgumentError, 'invalid date' end |
.reset_parsers! ⇒ Object
Reset the parsers, parser types, and order of parsers used to the default.
155 156 157 158 159 160 161 162 163 164 |
# File 'lib/third_base/date.rb', line 155 def self.reset_parsers! parser_hash.clear default_parser_hash.each do |type, parsers| add_parser_type(type) parsers.reverse.each do |re, parser| add_parser(type, re, &parser) end end use_parsers(*default_parser_list) end |
.strptime(str, fmt = strptime_default) ⇒ Object
Parse the string using the provided format (or the default format). Raises an ArgumentError if the format does not match the string.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/third_base/date.rb', line 168 def self.strptime(str, fmt=strptime_default) blocks = [] s = str.strip date_hash = {} pattern = Regexp.escape((fmt)).gsub(STRFTIME_RE) do |x| pat, *blks = _strptime_part(x[1..1]) blocks += blks pat end if m = /#{pattern}/i.match(s) m.to_a[1..-1].zip(blocks) do |x, blk| blk.call(date_hash, x) end new_from_parts(date_hash) else raise ArgumentError, 'invalid date' end end |
.today ⇒ Object
Returns a date with the current year, month, and date.
188 189 190 191 |
# File 'lib/third_base/date.rb', line 188 def self.today t = Time.now civil(t.year, t.mon, t.day) end |
.use_parsers(*parsers) ⇒ Object
Set the order of parser types to use to the given parser types.
194 195 196 |
# File 'lib/third_base/date.rb', line 194 def self.use_parsers(*parsers) parser_list.replace(parsers) end |
Instance Method Details
#+(d) ⇒ Object
Returns a new date with d number of days added to this date.
328 329 330 331 |
# File 'lib/third_base/date.rb', line 328 def +(d) raise(TypeError, "d must be an integer") unless d.is_a?(Integer) jd_to_civil(jd + d) end |
#-(d) ⇒ Object
Returns a new date with d number of days subtracted from this date. If d is a Date, returns the number of days between the two dates.
335 336 337 338 339 340 341 342 343 |
# File 'lib/third_base/date.rb', line 335 def -(d) if d.is_a?(self.class) jd - d.jd elsif d.is_a?(Integer) self + -d else raise TypeError, "d should be #{self.class} or Integer" end end |
#<<(m) ⇒ Object
Returns a new date with m number of months subtracted from this date.
367 368 369 |
# File 'lib/third_base/date.rb', line 367 def <<(m) self >> -m end |
#<=>(date) ⇒ Object
Compare two dates. If the given date is greater than self, return -1, if it is less, return 1, and if it is equal, return 0. If given date is a number, compare this date’s julian date to it.
374 375 376 377 378 379 380 381 |
# File 'lib/third_base/date.rb', line 374 def <=>(date) if date.is_a?(Numeric) jd <=> date else ((d = (year <=> date.year)) == 0) && ((d = (mon <=> date.mon)) == 0) && ((d = (day <=> date.day)) == 0) d end end |
#==(date) ⇒ Object Also known as: eql?
Dates are equel only if their year, month, and day match.
384 385 386 387 |
# File 'lib/third_base/date.rb', line 384 def ==(date) return false unless Date === date year == date.year and mon == date.mon and day == date.day end |
#===(d) ⇒ Object
If d is a date, only true if it is equal to this date. If d is Numeric, only true if it equals this date’s julian date.
391 392 393 394 395 396 397 |
# File 'lib/third_base/date.rb', line 391 def ===(d) case d when Numeric then jd == d when Date then self == d else false end end |
#>>(m) ⇒ Object
Returns a new date with m number of months added to this date. If the day of self does not exist in the new month, set the new day to be the last day of the new month.
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/third_base/date.rb', line 348 def >>(m) raise(TypeError, "m must be an integer") unless m.is_a?(Integer) y = year n = mon + m if n > 12 or n <= 0 a, n = n.divmod(12) if n == 0 n = 12 y += a - 1 else y += a end end ndays = days_in_month(n, y) d = day > ndays ? ndays : day new_civil(y, n, d) end |
#cwday ⇒ Object
The commercial week day for this date.
400 401 402 |
# File 'lib/third_base/date.rb', line 400 def cwday @cwday || commercial[2] end |
#cweek ⇒ Object
The commercial week for this date.
405 406 407 |
# File 'lib/third_base/date.rb', line 405 def cweek @cweek || commercial[1] end |
#cwyear ⇒ Object
The commercial week year for this date.
410 411 412 |
# File 'lib/third_base/date.rb', line 410 def cwyear @cwyear || commercial[0] end |
#day ⇒ Object Also known as: mday
The day of the month for this date.
415 416 417 |
# File 'lib/third_base/date.rb', line 415 def day @day || civil[2] end |
#downto(d, &block) ⇒ Object
Yield every date between this date and given date to the block. The given date should be less than this date.
422 423 424 |
# File 'lib/third_base/date.rb', line 422 def downto(d, &block) step(d, -1, &block) end |
#hash ⇒ Object
Unique value for this date, based on it’s year, month, and day of month.
427 428 429 |
# File 'lib/third_base/date.rb', line 427 def hash civil.hash end |
#inspect ⇒ Object
Programmer friendly readable string, much more friendly than the one in the standard date class.
433 434 435 |
# File 'lib/third_base/date.rb', line 433 def inspect "#<#{self.class} #{self}>" end |
#jd ⇒ Object
This date’s julian date.
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/third_base/date.rb', line 438 def jd @jd ||= ( y = year m = mon d = day if m <= 2 y -= 1 m += 12 end a = (y / 100.0).floor jd = (365.25 * (y + 4716)).floor + (30.6001 * (m + 1)).floor + d - 1524 + (2 - a + (a / 4.0).floor) ) end |
#leap? ⇒ Boolean
Whether this date is in a leap year.
455 456 457 |
# File 'lib/third_base/date.rb', line 455 def leap? _leap?(year) end |
#mon ⇒ Object Also known as: month
The month number for this date (January is 1, December is 12).
460 461 462 |
# File 'lib/third_base/date.rb', line 460 def mon @mon || civil[1] end |
#step(limit, step = 1) ⇒ Object
Yield each date between this date and limit, adding step number of days in each iteration. Returns current date.
467 468 469 470 471 472 473 474 475 |
# File 'lib/third_base/date.rb', line 467 def step(limit, step=1) da = self op = %w(== <= >=)[step <=> 0] while da.__send__(op, limit) yield da da += step end self end |
#strftime(fmt = strftime_default) ⇒ Object
Format the time using a format string, or the default format string.
478 479 480 |
# File 'lib/third_base/date.rb', line 478 def strftime(fmt=strftime_default) fmt.gsub(STRFTIME_RE){|x| _strftime(x[1..1])} end |
#succ ⇒ Object Also known as: next
Return the day after this date.
483 484 485 |
# File 'lib/third_base/date.rb', line 483 def succ self + 1 end |
#to_s ⇒ Object
Alias for strftime with the default format
489 490 491 |
# File 'lib/third_base/date.rb', line 489 def to_s strftime end |
#upto(d, &block) ⇒ Object
Yield every date between this date and the given date to the block. The given date should be greater than this date.
495 496 497 |
# File 'lib/third_base/date.rb', line 495 def upto(d, &block) step(d, &block) end |
#wday ⇒ Object
Return the day of the week for this date. Sunday is 0, Saturday is 6.
500 501 502 |
# File 'lib/third_base/date.rb', line 500 def wday (jd + 1) % 7 end |
#yday ⇒ Object
Return the day of the year for this date. January 1 is 1.
505 506 507 508 |
# File 'lib/third_base/date.rb', line 505 def yday h = leap? ? LEAP_CUMMULATIVE_MONTH_DAYS : CUMMULATIVE_MONTH_DAYS @yday ||= h[mon] + day end |
#year ⇒ Object
Return the year for this date.
511 512 513 |
# File 'lib/third_base/date.rb', line 511 def year @year || civil[0] end |