Coverage Report

Created: 2026-09-26 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/Time.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2020, the SerenityOS developers.
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/Checked.h>
8
#include <AK/Time.h>
9
10
// Make a reasonable guess as to which timespec/timeval definition to use.
11
// It doesn't really matter, since both are identical.
12
#ifdef KERNEL
13
#    include <Kernel/UnixTypes.h>
14
#else
15
#    include <sys/time.h>
16
#    include <time.h>
17
#endif
18
19
namespace AK {
20
21
int days_in_month(int year, unsigned month)
22
0
{
23
0
    VERIFY(month >= 1 && month <= 12);
24
0
    if (month == 2)
25
0
        return is_leap_year(year) ? 29 : 28;
26
27
0
    bool is_long_month = (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12);
28
0
    return is_long_month ? 31 : 30;
29
0
}
30
31
unsigned day_of_week(int year, unsigned month, int day)
32
0
{
33
0
    VERIFY(month >= 1 && month <= 12);
34
0
    constexpr Array seek_table = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
35
0
    if (month < 3)
36
0
        --year;
37
38
0
    return (year + year / 4 - year / 100 + year / 400 + seek_table[month - 1] + day) % 7;
39
0
}
40
41
Duration Duration::from_ticks(clock_t ticks, time_t ticks_per_second)
42
0
{
43
0
    auto secs = ticks % ticks_per_second;
44
45
0
    i32 nsecs = 1'000'000'000 * (ticks - (ticks_per_second * secs)) / ticks_per_second;
46
0
    i32 extra_secs = sane_mod(nsecs, 1'000'000'000);
47
0
    return Duration::from_half_sanitized(secs, extra_secs, nsecs);
48
0
}
49
50
Duration Duration::from_timespec(const struct timespec& ts)
51
48
{
52
48
    i32 nsecs = ts.tv_nsec;
53
48
    i32 extra_secs = sane_mod(nsecs, 1'000'000'000);
54
48
    return Duration::from_half_sanitized(ts.tv_sec, extra_secs, nsecs);
55
48
}
56
57
Duration Duration::from_timeval(const struct timeval& tv)
58
0
{
59
0
    i32 usecs = tv.tv_usec;
60
0
    i32 extra_secs = sane_mod(usecs, 1'000'000);
61
0
    VERIFY(0 <= usecs && usecs < 1'000'000);
62
0
    return Duration::from_half_sanitized(tv.tv_sec, extra_secs, usecs * 1'000);
63
0
}
64
65
i64 Duration::to_truncated_seconds() const
66
0
{
67
0
    VERIFY(m_nanoseconds < 1'000'000'000);
68
0
    if (m_seconds < 0 && m_nanoseconds) {
69
        // Since m_seconds is negative, adding 1 can't possibly overflow
70
0
        return m_seconds + 1;
71
0
    }
72
0
    return m_seconds;
73
0
}
74
75
i64 Duration::to_truncated_milliseconds() const
76
0
{
77
0
    VERIFY(m_nanoseconds < 1'000'000'000);
78
0
    Checked<i64> milliseconds((m_seconds < 0) ? m_seconds + 1 : m_seconds);
79
0
    milliseconds *= 1'000;
80
0
    milliseconds += m_nanoseconds / 1'000'000;
81
0
    if (m_seconds < 0) {
82
0
        if (m_nanoseconds % 1'000'000 != 0) {
83
            // Does not overflow: milliseconds <= 1'999.
84
0
            milliseconds++;
85
0
        }
86
        // We dropped one second previously, put it back in now that we have handled the rounding.
87
0
        milliseconds -= 1'000;
88
0
    }
89
0
    if (!milliseconds.has_overflow())
90
0
        return milliseconds.value();
91
0
    return m_seconds < 0 ? -0x8000'0000'0000'0000LL : 0x7fff'ffff'ffff'ffffLL;
92
0
}
93
94
i64 Duration::to_truncated_microseconds() const
95
0
{
96
0
    VERIFY(m_nanoseconds < 1'000'000'000);
97
0
    Checked<i64> microseconds((m_seconds < 0) ? m_seconds + 1 : m_seconds);
98
0
    microseconds *= 1'000'000;
99
0
    microseconds += m_nanoseconds / 1'000;
100
0
    if (m_seconds < 0) {
101
0
        if (m_nanoseconds % 1'000 != 0) {
102
            // Does not overflow: microseconds <= 1'999'999.
103
0
            microseconds++;
104
0
        }
105
        // We dropped one second previously, put it back in now that we have handled the rounding.
106
0
        microseconds -= 1'000'000;
107
0
    }
108
0
    if (!microseconds.has_overflow())
109
0
        return microseconds.value();
110
0
    return m_seconds < 0 ? -0x8000'0000'0000'0000LL : 0x7fff'ffff'ffff'ffffLL;
111
0
}
112
113
timespec Duration::to_timespec() const
114
0
{
115
0
    VERIFY(m_nanoseconds < 1'000'000'000);
116
0
    return { static_cast<time_t>(m_seconds), static_cast<long>(m_nanoseconds) };
117
0
}
118
119
timeval Duration::to_timeval() const
120
0
{
121
0
    VERIFY(m_nanoseconds < 1'000'000'000);
122
    // This is done because winsock defines tv_sec and tv_usec as long, and Linux64 as long int.
123
0
    using sec_type = decltype(declval<timeval>().tv_sec);
124
0
    using usec_type = decltype(declval<timeval>().tv_usec);
125
0
    return { static_cast<sec_type>(m_seconds), static_cast<usec_type>(m_nanoseconds) / 1000 };
126
0
}
127
128
Duration Duration::from_half_sanitized(i64 seconds, i32 extra_seconds, u32 nanoseconds)
129
48
{
130
48
    VERIFY(nanoseconds < 1'000'000'000);
131
132
48
    if ((seconds <= 0 && extra_seconds > 0) || (seconds >= 0 && extra_seconds < 0)) {
133
        // Opposite signs mean that we can definitely add them together without fear of overflowing i64:
134
0
        seconds += extra_seconds;
135
0
        extra_seconds = 0;
136
0
    }
137
138
    // Now the only possible way to become invalid is overflowing i64 towards positive infinity:
139
48
    if (Checked<i64>::addition_would_overflow<i64, i64>(seconds, extra_seconds)) {
140
0
        if (seconds < 0) {
141
0
            return Duration::min();
142
0
        } else {
143
0
            return Duration::max();
144
0
        }
145
0
    }
146
147
48
    return Duration { seconds + extra_seconds, nanoseconds };
148
48
}
149
150
#ifndef KERNEL
151
namespace {
152
static Duration now_time_from_clock(clockid_t clock_id)
153
48
{
154
48
    timespec now_spec {};
155
48
    ::clock_gettime(clock_id, &now_spec);
156
48
    return Duration::from_timespec(now_spec);
157
48
}
158
}
159
160
MonotonicTime MonotonicTime::now()
161
48
{
162
48
    return MonotonicTime { now_time_from_clock(CLOCK_MONOTONIC) };
163
48
}
164
165
MonotonicTime MonotonicTime::now_coarse()
166
0
{
167
0
    return MonotonicTime { now_time_from_clock(CLOCK_MONOTONIC_COARSE) };
168
0
}
169
170
UnixDateTime UnixDateTime::now()
171
0
{
172
0
    return UnixDateTime { now_time_from_clock(CLOCK_REALTIME) };
173
0
}
174
175
UnixDateTime UnixDateTime::now_coarse()
176
0
{
177
    return UnixDateTime { now_time_from_clock(CLOCK_REALTIME_COARSE) };
178
0
}
179
180
#endif
181
182
}