Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
Implemented support for negative number of days as constructor argume…
Browse files Browse the repository at this point in the history
…nts.

For example, Date.civil(2008, 7, -1) will construct "2008-7-31" date.
  • Loading branch information
Alexander Dymo authored and rtomayko committed Jul 12, 2008
1 parent 4872381 commit 8203c32
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 10 deletions.
40 changes: 30 additions & 10 deletions ext/date_performance.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <math.h>
#include <ruby.h>
#include <time.h>

#define FLOOR(a) lrintf(floorf(a))
#define FLOAT(a) (float)a
Expand Down Expand Up @@ -187,18 +188,37 @@ rb_date_new(int argc, VALUE * argv, VALUE self) {
m = (argc > 1 ? NUM2INT(argv[1]) : 1),
d = (argc > 2 ? NUM2INT(argv[2]) : 1);
VALUE sg = (argc > 3 ? argv[3] : ITALY);
int jd = civil_to_jd(y, m, d, sg);
int jd = -1;
struct mini_tm t;
jd_to_civil(jd, sg, &t);
if ( t.y != y || t.m != m || t.d != d ) {
rb_raise(rb_eArgError, "Invalid date: (%d, %d, %d)", y, m, d);
return Qnil;
}else{
VALUE ajd = jd_to_ajd(jd, INT2FIX(0), INT2FIX(0));
VALUE date = rb_funcall(self, id_new_bang, 3, ajd, INT2FIX(0), sg);
rb_ivar_set(date, id_ivar_civil, rb_ary_new3(3, INT2FIX(t.y), INT2FIX(t.m), INT2FIX(t.d)));
return date;
if (d < 0) {
int ny = (y * 12 + m) / 12;
int nm = (y * 12 + m) % 12;
nm = (nm + 1) / 1;
jd = civil_to_jd(ny, nm, d+1, sg);

VALUE ns = jd < 2299161 ? JULIAN : GREGORIAN;
jd_to_civil(jd-d, ns, &t);
if ( t.y != ny || t.m != nm || t.d != 1 ) {
rb_raise(rb_eArgError, "Invalid date: (%d, %d, %d)", y, m, d);
return Qnil;
}
jd_to_civil(jd, sg, &t);
if ( t.y != y || t.m != m ) {
rb_raise(rb_eArgError, "Invalid date: (%d, %d, %d)", y, m, d);
return Qnil;
}
} else {
jd = civil_to_jd(y, m, d, sg);
jd_to_civil(jd, sg, &t);
if ( t.y != y || t.m != m || t.d != d ) {
rb_raise(rb_eArgError, "Invalid date: (%d, %d, %d)", y, m, d);
return Qnil;
}
}
VALUE ajd = jd_to_ajd(jd, INT2FIX(0), INT2FIX(0));
VALUE date = rb_funcall(self, id_new_bang, 3, ajd, INT2FIX(0), sg);
rb_ivar_set(date, id_ivar_civil, rb_ary_new3(3, INT2FIX(t.y), INT2FIX(t.m), INT2FIX(t.d)));
return date;
}


Expand Down
21 changes: 21 additions & 0 deletions test/extension_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,25 @@ def test_strftime_with_datetime
assert_equal "2007-01-01T04:20:00+00:00", dt.strftime("%FT%T%:z")
end

def test_constructor_with_negative_days
#leap year
month_ends = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
(1..12).each do |m|
d = Date.new(2008, m, -1)
assert_equal d.day, month_ends[m-1]
end
#normal year
month_ends = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
(1..12).each do |m|
d = Date.new(2009, m, -1)
assert_equal d.day, month_ends[m-1]
end
#before calendar reform for Italy
month_ends = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
(1..12).each do |m|
d = Date.new(1581, m, -1)
assert_equal d.day, month_ends[m-1]
end
end

end

0 comments on commit 8203c32

Please sign in to comment.