summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2020-08-25 19:19:16 -0400
committerAndreas Kling <kling@serenityos.org>2020-08-26 08:52:07 +0200
commitc85e679e2d802159f7eb1a70a1667dd20dea0379 (patch)
tree9b99e1274e82e67fc40f3bf06d8ef1162ed3afe0
parent2c1b84b3e10e67d6aeb3006f7535b8990355d769 (diff)
downloadserenity-c85e679e2d802159f7eb1a70a1667dd20dea0379.zip
AK+LibCore+Kernel: Have fewer implementations of day_of_year
The JS tests pointed out that the implementation in DateTime had an off-by-one in the month when doing the leap year check, so this change fixes that bug.
-rw-r--r--AK/Time.cpp45
-rw-r--r--AK/Time.h8
-rw-r--r--Kernel/CMakeLists.txt1
-rw-r--r--Kernel/RTC.cpp47
-rw-r--r--Libraries/LibC/time.cpp8
-rw-r--r--Libraries/LibCore/DateTime.cpp8
6 files changed, 57 insertions, 60 deletions
diff --git a/AK/Time.cpp b/AK/Time.cpp
new file mode 100644
index 0000000000..63253f90b7
--- /dev/null
+++ b/AK/Time.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020, The SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <AK/Time.h>
+
+namespace AK {
+
+int day_of_year(int year, unsigned month, int day)
+{
+ ASSERT(month >= 1 && month <= 12);
+
+ static const int seek_table[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ int day_of_year = seek_table[month - 1] + day - 1;
+
+ if (is_leap_year(year) && month >= 3)
+ day_of_year++;
+
+ return day_of_year;
+}
+
+}
diff --git a/AK/Time.h b/AK/Time.h
index 309218747b..612b92f691 100644
--- a/AK/Time.h
+++ b/AK/Time.h
@@ -28,6 +28,13 @@
namespace AK {
+// Month and day start at 1. Month must be >= 1 and <= 12.
+// The return value is 0-indexed, that is Jan 1 is day 0.
+// Day may be negative or larger than the number of days
+// in the given month. If day is negative enough, the result
+// can be negative.
+int day_of_year(int year, unsigned month, int day);
+
inline bool is_leap_year(int year)
{
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
@@ -161,6 +168,7 @@ inline bool operator!=(const TimespecType& a, const TimespecType& b)
}
+using AK::day_of_year;
using AK::is_leap_year;
using AK::timespec_add;
using AK::timespec_add_timeval;
diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt
index ff9379d823..87befd7fc2 100644
--- a/Kernel/CMakeLists.txt
+++ b/Kernel/CMakeLists.txt
@@ -207,6 +207,7 @@ set(AK_SOURCES
../AK/StringImpl.cpp
../AK/StringUtils.cpp
../AK/StringView.cpp
+ ../AK/Time.cpp
)
set(ELF_SOURCES
diff --git a/Kernel/RTC.cpp b/Kernel/RTC.cpp
index 25f494bd98..bced1bf661 100644
--- a/Kernel/RTC.cpp
+++ b/Kernel/RTC.cpp
@@ -49,50 +49,6 @@ static bool update_in_progress()
return CMOS::read(0x0a) & 0x80;
}
-static unsigned days_in_months_since_start_of_year(unsigned month, unsigned year)
-{
- ASSERT(month <= 11);
- unsigned days = 0;
- switch (month) {
- case 11:
- days += 30;
- [[fallthrough]];
- case 10:
- days += 31;
- [[fallthrough]];
- case 9:
- days += 30;
- [[fallthrough]];
- case 8:
- days += 31;
- [[fallthrough]];
- case 7:
- days += 31;
- [[fallthrough]];
- case 6:
- days += 30;
- [[fallthrough]];
- case 5:
- days += 31;
- [[fallthrough]];
- case 4:
- days += 30;
- [[fallthrough]];
- case 3:
- days += 31;
- [[fallthrough]];
- case 2:
- if (is_leap_year(year))
- days += 29;
- else
- days += 28;
- [[fallthrough]];
- case 1:
- days += 31;
- }
- return days;
-}
-
static u8 bcd_to_binary(u8 bcd)
{
return (bcd & 0x0F) + ((bcd >> 4) * 10);
@@ -149,8 +105,7 @@ time_t now()
ASSERT(year >= 2018);
return years_to_days_since_epoch(year) * 86400
- + days_in_months_since_start_of_year(month - 1, year) * 86400
- + (day - 1) * 86400
+ + day_of_year(year, month, day) * 86400
+ hour * 3600
+ minute * 60
+ second;
diff --git a/Libraries/LibC/time.cpp b/Libraries/LibC/time.cpp
index 7a49ec8a95..032da5b6f0 100644
--- a/Libraries/LibC/time.cpp
+++ b/Libraries/LibC/time.cpp
@@ -117,13 +117,7 @@ static time_t tm_to_time(struct tm* tm, long timezone_adjust_seconds)
}
int days = years_to_days_since_epoch(1900 + tm->tm_year);
-
- tm->tm_yday = tm->tm_mday - 1;
- for (int month = 0; month < tm->tm_mon; ++month)
- tm->tm_yday += __days_per_month[month];
- if (tm->tm_mon > 1 && is_leap_year(1900 + tm->tm_year))
- ++tm->tm_yday;
-
+ tm->tm_yday = day_of_year(1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
days += tm->tm_yday;
int seconds = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
diff --git a/Libraries/LibCore/DateTime.cpp b/Libraries/LibCore/DateTime.cpp
index a1cd35cc7b..c4062699cc 100644
--- a/Libraries/LibCore/DateTime.cpp
+++ b/Libraries/LibCore/DateTime.cpp
@@ -81,13 +81,7 @@ unsigned DateTime::days_in_month() const
unsigned DateTime::day_of_year() const
{
- static const int seek_table[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
- int day_of_year = seek_table[m_month - 1] + m_day;
-
- if (is_leap_year() && m_month > 3)
- day_of_year++;
-
- return day_of_year - 1;
+ return ::day_of_year(m_year, m_month, m_day);
}
bool DateTime::is_leap_year() const