Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions ext/date/date_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2561,7 +2561,12 @@ valid_nth_kday_p(VALUE y, int m, int n, int k, double sg,
}
#endif

#ifndef HAVE_RB_CATEGORY_WARN
#define rb_category_warn(category, fmt) rb_warn(fmt)
#endif

VALUE date_zone_to_diff(VALUE);
VALUE date_zone_to_diff_frac(VALUE, int *, long *);

static int
offset_to_sec(VALUE vof, int *rof)
Expand Down Expand Up @@ -2633,13 +2638,21 @@ offset_to_sec(VALUE vof, int *rof)
}
case T_STRING:
{
VALUE vs = date_zone_to_diff(vof);
long n;

if (!FIXNUM_P(vs))
return 0;
n = FIX2LONG(vs);
if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
int frac, ok = 0;
long whole, n = 0;
VALUE vs = date_zone_to_diff_frac(vof, &frac, &whole);

if (FIXNUM_P(vs)) {
n = FIX2LONG(vs);
if (n >= -DAY_IN_SECONDS && n <= DAY_IN_SECONDS)
ok = 1;
}
/* warn only where dropping the fraction would give an offset
* different from the one this returns today */
if (frac && (ok ? n : 0) != whole)
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "fraction of hour in a zone offset is deprecated"
" and will be ignored in a future version");
if (!ok)
return 0;
*rof = (int)n;
return 1;
Expand Down Expand Up @@ -4678,10 +4691,6 @@ get_limit(VALUE opt)
return 128;
}

#ifndef HAVE_RB_CATEGORY_WARN
#define rb_category_warn(category, fmt) rb_warn(fmt)
#endif

static VALUE
check_limit(VALUE str, VALUE opt)
{
Expand Down
24 changes: 23 additions & 1 deletion ext/date/date_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include "ruby/re.h"
#include <ctype.h>

#ifndef HAVE_RB_CATEGORY_WARN
#define rb_category_warn(category, fmt) rb_warn(fmt)
#endif

#undef strncasecmp
#define strncasecmp STRNCASECMP

Expand Down Expand Up @@ -413,12 +417,15 @@ shrink_space(char *d, const char *s, long l)
}

VALUE
date_zone_to_diff(VALUE str)
date_zone_to_diff_frac(VALUE str, int *fracp, long *whole)
{
VALUE offset = Qnil;
long l = RSTRING_LEN(str);
const char *s = RSTRING_PTR(str);

*fracp = 0;
*whole = 0;

{
int dst = 0;
int w;
Expand Down Expand Up @@ -533,6 +540,8 @@ date_zone_to_diff(VALUE str)
offset = rb_rational_num(offset);
}
}
*fracp = 1;
*whole = hour * 3600;
goto ok;
}
else if (l > 2) {
Expand All @@ -558,6 +567,19 @@ date_zone_to_diff(VALUE str)
return offset;
}

VALUE
date_zone_to_diff(VALUE str)
{
int frac;
long whole;
VALUE offset = date_zone_to_diff_frac(str, &frac, &whole);

if (frac)
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "fraction of hour in a zone offset is deprecated"
" and will be ignored in a future version");
return offset;
}

static int
day_num(VALUE s)
{
Expand Down
35 changes: 35 additions & 0 deletions test/date/test_date_new.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,41 @@ def test_civil__offset
assert_equal(0, d.offset)
end

def test_civil__fractional_zone_offset_deprecated
with_deprecation_warnings do
# A fraction that makes the offset non-integral is already dropped whole,
# so ignoring the fraction will not change these.
['+00.123', '-00.123'].each do |z|
assert_warning(/\A(?!.*fraction of hour).*invalid offset is ignored/m) do
assert_equal(0, DateTime.civil(2001,2,3, 0,0,0, z).offset)
end
end

# Here the fraction reaches the result, or dropping it would give an
# offset different from the 0 returned today.
assert_warning(/fraction of hour/) do
assert_equal(Rational(1800, 86400), DateTime.civil(2001,2,3, 0,0,0, '+00.5').offset)
end
assert_warning(/fraction of hour/) do
assert_equal(0, DateTime.civil(2001,2,3, 0,0,0, '+01.123').offset)
end

# A zero fraction and the colon forms change nothing.
assert_warning('') do
assert_equal(Rational(3600, 86400), DateTime.civil(2001,2,3, 0,0,0, '+01.0').offset)
assert_equal(Rational(1800, 86400), DateTime.civil(2001,2,3, 0,0,0, '+00:30').offset)
end
end
end

def with_deprecation_warnings
deprecated = Warning[:deprecated] if Warning.respond_to?(:[])
Warning[:deprecated] = true if Warning.respond_to?(:[]=)
yield
ensure
Warning[:deprecated] = deprecated if Warning.respond_to?(:[]=)
end

def test_civil__reform
d = Date.jd(Date::ENGLAND, Date::ENGLAND)
dt = DateTime.jd(Date::ENGLAND, 0,0,0,0, Date::ENGLAND)
Expand Down
78 changes: 72 additions & 6 deletions test/date/test_date_parse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,78 @@

class TestDateParse < Test::Unit::TestCase

def test__parse_fractional_zone_offset_deprecated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be tests added for Date._strptime, which should have appropriate warnings

with_deprecation_warnings do
# The fractional hour is honoured today and will be ignored, which
# changes :offset, or at least :zone for a zero fraction.
assert_warning(/fraction of hour/) do
assert_equal(Rational(2214, 5), Date._parse('2001-02-03T00:00:00+00.123')[:offset])
end
assert_warning(/fraction of hour/) do
assert_equal(1800, Date._parse('2001-02-03T00:00:00+00,5')[:offset])
end
assert_warning(/fraction of hour/) do
h = Date._parse('2001-02-03T00:00:00+01.0')
assert_equal(['+01.0', 3600], h.values_at(:zone, :offset))
end
[
['19990523235521.123[-9.50]', [1999,5,23,23,55,21,'-9.50',-(9*3600+30*60)]],
['19990523235521.123[+9.50]', [1999,5,23,23,55,21,'+9.50',+(9*3600+30*60)]],
['2000-01-31 13:20:00-5.5', [2000,1,31,13,20,0,'-5.5',-5*3600-30*60]],
['2000-01-31 13:20:00-5,5', [2000,1,31,13,20,0,'-5,5',-5*3600-30*60]],
['2000-01-31 13:20:00+3.5', [2000,1,31,13,20,0,'+3.5',3*3600+30*60]],
['2000-01-31 13:20:00+3,5', [2000,1,31,13,20,0,'+3,5',3*3600+30*60]],
].each do |str, expected|
assert_warning(/fraction of hour/) do
h = Date._parse(str)
assert_equal(expected, h.values_at(:year,:mon,:mday,:hour,:min,:sec,:zone,:offset), str)
end
end
# The colon forms have no fractional hour at all.
assert_warning('') do
assert_equal(1800, Date._parse('2001-02-03T00:00:00+00:30')[:offset])
assert_equal(86399, Date._parse('2001-02-03T00:00:00+23:59:59')[:offset])
end
end
end

def test__strptime_fractional_zone_offset_deprecated
with_deprecation_warnings do
assert_warning(/fraction of hour/) do
assert_equal(1800, Date._strptime('+00.5', '%z')[:offset])
end
assert_warning(/fraction of hour/) do
assert_equal(Rational(2214, 5), Date._strptime('+00,123', '%z')[:offset])
end
assert_warning(/fraction of hour/) do
assert_equal(['+01.0', 3600], Date._strptime('+01.0', '%z').values_at(:zone, :offset))
end
assert_warning(/fraction of hour/) do
h = Date._strptime('Thu Jul 29 16:39:41 GMT-3.5 1999', '%a %b %d %H:%M:%S %Z %Y')
assert_equal(['GMT-3.5', -3*3600-30*60], h.values_at(:zone, :offset))
end
assert_warning(/fraction of hour/) do
h = Date._strptime('Thu Jul 29 16:39:41 GMT-3,5 1999', '%a %b %d %H:%M:%S %Z %Y')
assert_equal(['GMT-3,5', -3*3600-30*60], h.values_at(:zone, :offset))
end
assert_warning(/fraction of hour/) do
assert_equal(3600, Date._strptime('+0.9999999999999999999999', '%Z')[:offset])
end
assert_warning('') do
assert_equal(1800, Date._strptime('+00:30', '%z')[:offset])
assert_equal(-3600, Date._strptime('-0100', '%z')[:offset])
end
end
end

def with_deprecation_warnings
deprecated = Warning[:deprecated] if Warning.respond_to?(:[])
Warning[:deprecated] = true if Warning.respond_to?(:[]=)
yield
ensure
Warning[:deprecated] = deprecated if Warning.respond_to?(:[]=)
end

def test__parse
[
# ctime(3), asctime(3)
Expand Down Expand Up @@ -134,8 +206,6 @@ def test__parse
[['19990523235521.123[+9]',false],[1999,5,23,23,55,21,'+9',+(9*3600),nil], __LINE__],
[['19990523235521.123[9]',false],[1999,5,23,23,55,21,'9',+(9*3600),nil], __LINE__],
[['19990523235521.123[9 ]',false],[1999,5,23,23,55,21,'9 ',+(9*3600),nil], __LINE__],
[['19990523235521.123[-9.50]',false],[1999,5,23,23,55,21,'-9.50',-(9*3600+30*60),nil], __LINE__],
[['19990523235521.123[+9.50]',false],[1999,5,23,23,55,21,'+9.50',+(9*3600+30*60),nil], __LINE__],
[['19990523235521.123[-5:EST]',false],[1999,5,23,23,55,21,'EST',-5*3600,nil], __LINE__],
[['19990523235521.123[+9:JST]',false],[1999,5,23,23,55,21,'JST',9*3600,nil], __LINE__],
[['19990523235521.123[+12:XXX YYY ZZZ]',false],[1999,5,23,23,55,21,'XXX YYY ZZZ',12*3600,nil], __LINE__],
Expand Down Expand Up @@ -166,10 +236,6 @@ def test__parse
[['2000-01-31 13:20:00-5',false],[2000,1,31,13,20,0,'-5',-5*3600,nil], __LINE__],

# [-+]\d+.\d+
[['2000-01-31 13:20:00-5.5',false],[2000,1,31,13,20,0,'-5.5',-5*3600-30*60,nil], __LINE__],
[['2000-01-31 13:20:00-5,5',false],[2000,1,31,13,20,0,'-5,5',-5*3600-30*60,nil], __LINE__],
[['2000-01-31 13:20:00+3.5',false],[2000,1,31,13,20,0,'+3.5',3*3600+30*60,nil], __LINE__],
[['2000-01-31 13:20:00+3,5',false],[2000,1,31,13,20,0,'+3,5',3*3600+30*60,nil], __LINE__],

# mil
[['2000-01-31 13:20:00 Z',false],[2000,1,31,13,20,0,'Z',0*3600,nil], __LINE__],
Expand Down
3 changes: 0 additions & 3 deletions test/date/test_date_strptime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,6 @@ def test__strptime__3
[['Thu Jul 29 16:39:41 GMT-09 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-09',-9*3600,4], __LINE__],
[['Thu Jul 29 16:39:41 GMT-09:08 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-09:08',-9*3600-8*60,4], __LINE__],
[['Thu Jul 29 16:39:41 GMT-09:08:07 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-09:08:07',-9*3600-8*60-7,4], __LINE__],
[['Thu Jul 29 16:39:41 GMT-3.5 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-3.5',-3*3600-30*60,4], __LINE__],
[['Thu Jul 29 16:39:41 GMT-3,5 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-3,5',-3*3600-30*60,4], __LINE__],
[['Thu Jul 29 16:39:41 Mountain Daylight Time 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'Mountain Daylight Time',-6*3600,4], __LINE__],
[['Thu Jul 29 16:39:41 E. Australia Standard Time 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'E. Australia Standard Time',10*3600,4], __LINE__],

Expand Down Expand Up @@ -182,7 +180,6 @@ def test__strptime__3
[['E. Australia Standard Time', '%Z'], [nil,nil,nil,nil,nil,nil,'E. Australia Standard Time',10*3600,nil], __LINE__],

# out of range
[['+0.9999999999999999999999', '%Z'], [nil,nil,nil,nil,nil,nil,'+0.9999999999999999999999',+1*3600,nil], __LINE__],
[['+9999999999999999999999.0', '%Z'], [nil,nil,nil,nil,nil,nil,'+9999999999999999999999.0',nil,nil], __LINE__],
].each do |x, y|
h = Date._strptime(*x)
Expand Down
Loading