summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2022-11-13 11:20:01 +0900
committernagachika <nagachika@ruby-lang.org>2022-11-13 11:20:01 +0900
commit728d9f18348bcffedb0880c67015f08a7c19665f (patch)
tree0e8593506d8aac41c097a94930b208c8ecb68bf1
parent61818395312c6e765dc8e7be8bf32cd2c82fec39 (diff)
merge revision(s) 011d4c57d21220249600dfb76db84840550da019: [Backport #19106]
[Bug #19106] Normalize time at 24:00:00 with a timezone object --- test/ruby/test_time_tz.rb | 5 +++++ time.c | 24 ++++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-)
-rw-r--r--test/ruby/test_time_tz.rb5
-rw-r--r--time.c24
-rw-r--r--version.h2
3 files changed, 22 insertions, 9 deletions
diff --git a/test/ruby/test_time_tz.rb b/test/ruby/test_time_tz.rb
index fdc9e114b5..b6785f3360 100644
--- a/test/ruby/test_time_tz.rb
+++ b/test/ruby/test_time_tz.rb
@@ -612,6 +612,11 @@ module TestTimeTZ::WithTZ
assert_raise(ArgumentError) {time_class.new(2018, 9, 1, 12, 0, 0, tzarg, in: tzarg)}
end
+ def subtest_hour24(time_class, tz, tzarg, tzname, abbr, utc_offset)
+ t = time_class.new(2000, 1, 1, 24, 0, 0, tzarg)
+ assert_equal([0, 0, 0, 2, 1, 2000], [t.sec, t.min, t.hour, t.mday, t.mon, t.year])
+ end
+
def subtest_now(time_class, tz, tzarg, tzname, abbr, utc_offset)
t = time_class.now(in: tzarg)
assert_equal(tz, t.zone)
diff --git a/time.c b/time.c
index 992e5403d0..a136dcbe8e 100644
--- a/time.c
+++ b/time.c
@@ -2324,6 +2324,19 @@ find_timezone(VALUE time, VALUE zone)
return rb_check_funcall_default(klass, id_find_timezone, 1, &zone, Qnil);
}
+/* Turn the special case 24:00:00 of already validated vtm into
+ * 00:00:00 the next day */
+static void
+vtm_day_wraparound(struct vtm *vtm)
+{
+ if (vtm->hour < 24) return;
+
+ /* Assuming UTC and no care of DST, just reset hour and advance
+ * date, not to discard the validated vtm. */
+ vtm->hour = 0;
+ vtm_add_day(vtm, 1);
+}
+
static VALUE
time_init_args(rb_execution_context_t *ec, VALUE time, VALUE year, VALUE mon, VALUE mday, VALUE hour, VALUE min, VALUE sec, VALUE zone)
{
@@ -2379,6 +2392,7 @@ time_init_args(rb_execution_context_t *ec, VALUE time, VALUE year, VALUE mon, VA
if (!NIL_P(zone)) {
tobj->timew = timegmw(&vtm);
+ vtm_day_wraparound(&vtm);
tobj->vtm = vtm;
tobj->tm_got = 1;
TZMODE_SET_LOCALTIME(tobj);
@@ -2393,13 +2407,7 @@ time_init_args(rb_execution_context_t *ec, VALUE time, VALUE year, VALUE mon, VA
if (utc == UTC_ZONE) {
tobj->timew = timegmw(&vtm);
- if (vtm.hour == 24) { /* special case: 24:00:00 only */
- /* Since no need to take care of DST in UTC, just reset
- * hour and advance date, not to discard the validated
- * vtm. */
- vtm.hour = 0;
- vtm_add_day(&vtm, 1);
- }
+ vtm_day_wraparound(&vtm);
tobj->vtm = vtm;
tobj->tm_got = 1;
TZMODE_SET_UTC(tobj);
@@ -4054,7 +4062,7 @@ time_inspect(VALUE time)
GetTimeval(time, tobj);
str = strftimev("%Y-%m-%d %H:%M:%S", time, rb_usascii_encoding());
subsec = w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE)));
- if (FIXNUM_P(subsec) && FIX2LONG(subsec) == 0) {
+ if (subsec == INT2FIX(0)) {
}
else if (FIXNUM_P(subsec) && FIX2LONG(subsec) < TIME_SCALE) {
long len;
diff --git a/version.h b/version.h
index 985014e52f..6a2e2abcf9 100644
--- a/version.h
+++ b/version.h
@@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 3
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 179
+#define RUBY_PATCHLEVEL 180
#define RUBY_RELEASE_YEAR 2022
#define RUBY_RELEASE_MONTH 11