summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-28 14:08:31 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-28 14:08:31 +0000
commit337b4b634495f247711cb25636364cc7f967e457 (patch)
treee05a5a70a05aae8e7eeb543eee93bd44e9a70f09
parentfe08f99e9388c9f4f2eccc66a260330252c62a81 (diff)
Try Time.find_timezone to convert name to timezone
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66076 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--test/ruby/test_time_tz.rb31
-rw-r--r--time.c71
2 files changed, 74 insertions, 28 deletions
diff --git a/test/ruby/test_time_tz.rb b/test/ruby/test_time_tz.rb
index f6635f6ce1..5360666d3c 100644
--- a/test/ruby/test_time_tz.rb
+++ b/test/ruby/test_time_tz.rb
@@ -503,41 +503,49 @@ End
def abbr(t)
@abbr
end
+
+ def ==(other)
+ @name == other.name and @abbr == other.abbr(0) and @offset == other.offset
+ end
+
+ def inspect
+ "#<TZ: #@name #@abbr #@offset>"
+ end
end
end
module TestTimeTZ::WithTZ
- def subtest_new(time_class, tz, tzname, abbr, utc_offset)
- t = time_class.new(2018, 9, 1, 12, 0, 0, tz)
+ def subtest_new(time_class, tz, tzarg, tzname, abbr, utc_offset)
+ t = time_class.new(2018, 9, 1, 12, 0, 0, tzarg)
assert_equal([2018, 9, 1, 12, 0, 0, tz], [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.zone])
h, m = (-utc_offset / 60).divmod(60)
assert_equal(time_class.utc(2018, 9, 1, 12+h, m, 0).to_i, t.to_i)
end
- def subtest_getlocal(time_class, tz, tzname, abbr, utc_offset)
- t = time_class.utc(2018, 9, 1, 12, 0, 0).getlocal(tz)
+ def subtest_getlocal(time_class, tz, tzarg, tzname, abbr, utc_offset)
+ t = time_class.utc(2018, 9, 1, 12, 0, 0).getlocal(tzarg)
h, m = (utc_offset / 60).divmod(60)
assert_equal([2018, 9, 1, 12+h, m, 0, tz], [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.zone])
assert_equal(time_class.utc(2018, 9, 1, 12, 0, 0), t)
end
- def subtest_strftime(time_class, tz, tzname, abbr, utc_offset)
- t = time_class.new(2018, 9, 1, 12, 0, 0, tz)
+ def subtest_strftime(time_class, tz, tzarg, tzname, abbr, utc_offset)
+ t = time_class.new(2018, 9, 1, 12, 0, 0, tzarg)
h, m = (utc_offset.abs / 60).divmod(60)
h = -h if utc_offset < 0
assert_equal("%+.2d%.2d %s" % [h, m, abbr], t.strftime("%z %Z"))
end
- def subtest_plus(time_class, tz, tzname, abbr, utc_offset)
- t = time_class.new(2018, 9, 1, 12, 0, 0, tz) + 4000
+ def subtest_plus(time_class, tz, tzarg, tzname, abbr, utc_offset)
+ t = time_class.new(2018, 9, 1, 12, 0, 0, tzarg) + 4000
assert_equal([2018, 9, 1, 13, 6, 40, tz], [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.zone])
m, s = (4000-utc_offset).divmod(60)
h, m = m.divmod(60)
assert_equal(time_class.utc(2018, 9, 1, 12+h, m, s), t)
end
- def subtest_marshal(time_class, tz, tzname, abbr, utc_offset)
- t = time_class.new(2018, 9, 1, 12, 0, 0, tz)
+ def subtest_marshal(time_class, tz, tzarg, tzname, abbr, utc_offset)
+ t = time_class.new(2018, 9, 1, 12, 0, 0, tzarg)
t2 = Marshal.load(Marshal.dump(t))
assert_equal(t, t2)
assert_equal(t.utc_offset, t2.utc_offset)
@@ -561,7 +569,8 @@ module TestTimeTZ::WithTZ
define_method("#{test}@#{tzname}") do
tz = make_timezone(tzname, abbr, utc_offset)
time_class = self.class::TIME_CLASS
- __send__(subtest, time_class, tz, tzname, abbr, utc_offset)
+ __send__(subtest, time_class, tz, tz, tzname, abbr, utc_offset)
+ __send__(subtest, time_class, tz, tzname, tzname, abbr, utc_offset)
end
end
end
diff --git a/time.c b/time.c
index c9cfa3a721..f9a13f9169 100644
--- a/time.c
+++ b/time.c
@@ -642,6 +642,7 @@ static uint32_t obj2subsecx(VALUE obj, VALUE *subsecx);
static VALUE time_gmtime(VALUE);
static VALUE time_localtime(VALUE);
static VALUE time_fixoff(VALUE);
+static VALUE time_zonelocal(VALUE time, VALUE off);
static time_t timegm_noleapsecond(struct tm *tm);
static int tmcmp(struct tm *a, struct tm *b);
@@ -2040,6 +2041,13 @@ maybe_tzobj_p(VALUE obj)
return TRUE;
}
+NORETURN(static void invalid_utc_offset(void));
+static void
+invalid_utc_offset(void)
+{
+ rb_raise(rb_eArgError, "\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
+}
+
static VALUE
utc_offset_arg(VALUE arg)
{
@@ -2049,7 +2057,7 @@ utc_offset_arg(VALUE arg)
char *s = RSTRING_PTR(tmp);
if (!rb_enc_str_asciicompat_p(tmp)) {
invalid_utc_offset:
- rb_raise(rb_eArgError, "\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
+ return Qnil;
}
switch (RSTRING_LEN(tmp)) {
case 9:
@@ -2263,8 +2271,9 @@ time_init_1(int argc, VALUE *argv, VALUE time)
vtm.isdst = 0;
else if (maybe_tzobj_p(arg))
zone = arg;
- else
- vtm.utc_offset = utc_offset_arg(arg);
+ else if (NIL_P(vtm.utc_offset = utc_offset_arg(arg)))
+ if (NIL_P(zone = find_timezone(time, arg)))
+ invalid_utc_offset();
}
validate_vtm(&vtm);
@@ -2280,8 +2289,9 @@ time_init_1(int argc, VALUE *argv, VALUE time)
if (zone_timelocal(zone, time)) {
return time;
}
- else {
- vtm.utc_offset = utc_offset_arg(zone);
+ else if (NIL_P(vtm.utc_offset = utc_offset_arg(zone))) {
+ if (NIL_P(zone = find_timezone(time, zone)) || !zone_timelocal(zone, time))
+ invalid_utc_offset();
}
}
@@ -2480,11 +2490,18 @@ rb_time_num_new(VALUE timev, VALUE off)
VALUE time = time_new_timew(rb_cTime, rb_time_magnify(v2w(timev)));
if (!NIL_P(off)) {
- if (maybe_tzobj_p(off)) {
+ VALUE zone = off;
+
+ if (maybe_tzobj_p(zone)) {
time_gmtime(time);
- if (zone_timelocal(off, time)) return time;
+ if (zone_timelocal(zone, time)) return time;
+ }
+ if (NIL_P(off = utc_offset_arg(off))) {
+ if (NIL_P(zone = find_timezone(time, zone))) invalid_utc_offset();
+ time_gmtime(time);
+ if (!zone_timelocal(zone, time)) invalid_utc_offset();
+ return time;
}
- off = utc_offset_arg(off);
validate_utc_offset(off);
time_set_utc_offset(time, off);
return time;
@@ -3682,6 +3699,23 @@ time_localtime(VALUE time)
return time;
}
+static VALUE
+time_zonelocal(VALUE time, VALUE off)
+{
+ VALUE zone = off;
+ if (zone_localtime(zone, time)) return time;
+
+ if (NIL_P(off = utc_offset_arg(off))) {
+ if (NIL_P(zone = find_timezone(time, zone))) invalid_utc_offset();
+ if (!zone_localtime(zone, time)) invalid_utc_offset();
+ return time;
+ }
+ validate_utc_offset(off);
+
+ time_set_utc_offset(time, off);
+ return time_fixoff(time);
+}
+
/*
* call-seq:
* time.localtime -> time
@@ -3712,13 +3746,7 @@ time_localtime_m(int argc, VALUE *argv, VALUE time)
rb_scan_args(argc, argv, "01", &off);
if (!NIL_P(off)) {
- if (zone_localtime(off, time)) return time;
-
- off = utc_offset_arg(off);
- validate_utc_offset(off);
-
- time_set_utc_offset(time, off);
- return time_fixoff(time);
+ return time_zonelocal(time, off);
}
return time_localtime(time);
@@ -3835,12 +3863,18 @@ time_getlocaltime(int argc, VALUE *argv, VALUE time)
rb_scan_args(argc, argv, "01", &off);
if (!NIL_P(off)) {
- if (maybe_tzobj_p(off)) {
+ VALUE zone = off;
+ if (maybe_tzobj_p(zone)) {
VALUE t = time_dup(time);
if (zone_localtime(off, t)) return t;
}
- off = utc_offset_arg(off);
+ if (NIL_P(off = utc_offset_arg(off))) {
+ if (NIL_P(zone = find_timezone(time, zone))) invalid_utc_offset();
+ time = time_dup(time);
+ if (!zone_localtime(zone, time)) invalid_utc_offset();
+ return time;
+ }
validate_utc_offset(off);
time = time_dup(time);
@@ -5417,6 +5451,9 @@ rb_time_zone_abbreviation(VALUE zone, VALUE time)
*
* At loading marshaled data, a timezone name will be converted to a timezone
* object by +find_timezone+ class method, if the method is defined.
+ *
+ * Similary, that class method will be called when a timezone argument does
+ * not have the necessary methods mentioned above.
*/
void