• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37500

pending completion
#37500

push

local

web-flow
🤖 [master] Bump the Pkg stdlib from 429175914 to fe2b3bdac (#49295)

Co-authored-by: Dilum Aluthge <dilum@aluthge.com>

72466 of 83155 relevant lines covered (87.15%)

34054932.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/stdlib/Dates/src/rounding.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
# The epochs used for date rounding are based ISO 8601's "year zero" notation
4
const DATEEPOCH = value(Date(0))
5
const DATETIMEEPOCH = value(DateTime(0))
6

7
# According to ISO 8601, the first day of the first week of year 0000 is 0000-01-03
8
const WEEKEPOCH = value(Date(0, 1, 3))
9

10
const ConvertiblePeriod = Union{TimePeriod, Week, Day}
11
const TimeTypeOrPeriod = Union{TimeType, ConvertiblePeriod}
12

13
"""
14
    epochdays2date(days) -> Date
15

16
Take the number of days since the rounding epoch (`0000-01-01T00:00:00`) and return the
17
corresponding `Date`.
18
"""
19
epochdays2date(i) = Date(UTD(DATEEPOCH + Int64(i)))
×
20

21
"""
22
    epochms2datetime(milliseconds) -> DateTime
23

24
Take the number of milliseconds since the rounding epoch (`0000-01-01T00:00:00`) and
25
return the corresponding `DateTime`.
26
"""
27
epochms2datetime(i) = DateTime(UTM(DATETIMEEPOCH + Int64(i)))
×
28

29
"""
30
    date2epochdays(dt::Date) -> Int64
31

32
Take the given `Date` and return the number of days since the rounding epoch
33
(`0000-01-01T00:00:00`) as an [`Int64`](@ref).
34
"""
35
date2epochdays(dt::Date) = value(dt) - DATEEPOCH
×
36

37
"""
38
    datetime2epochms(dt::DateTime) -> Int64
39

40
Take the given `DateTime` and return the number of milliseconds since the rounding epoch
41
(`0000-01-01T00:00:00`) as an [`Int64`](@ref).
42
"""
43
datetime2epochms(dt::DateTime) = value(dt) - DATETIMEEPOCH
×
44

45
function Base.floor(dt::Date, p::Year)
×
46
    value(p) < 1 && throw(DomainError(p))
×
47
    years = year(dt)
×
48
    return Date(years - mod(years, value(p)))
×
49
end
50

51
function Base.floor(dt::Date, p::Month)
×
52
    value(p) < 1 && throw(DomainError(p))
×
53
    y, m = yearmonth(dt)
×
54
    months_since_epoch = y * 12 + m - 1
×
55
    month_offset = months_since_epoch - mod(months_since_epoch, value(p))
×
56
    target_month = mod(month_offset, 12) + 1
×
57
    target_year = div(month_offset, 12) - (month_offset < 0 && target_month != 1)
×
58
    return Date(target_year, target_month)
×
59
end
60

61
function Base.floor(dt::Date, p::Quarter)
×
62
    return floor(dt, Month(p))
×
63
end
64

65

66
function Base.floor(dt::Date, p::Week)
×
67
    value(p) < 1 && throw(DomainError(p))
×
68
    days = value(dt) - WEEKEPOCH
×
69
    days = days - mod(days, value(Day(p)))
×
70
    return Date(UTD(WEEKEPOCH + Int64(days)))
×
71
end
72

73
function Base.floor(dt::Date, p::Day)
×
74
    value(p) < 1 && throw(DomainError(p))
×
75
    days = date2epochdays(dt)
×
76
    return epochdays2date(days - mod(days, value(p)))
×
77
end
78

79
Base.floor(dt::DateTime, p::DatePeriod) = DateTime(Base.floor(Date(dt), p))
×
80

81
function Base.floor(dt::DateTime, p::TimePeriod)
×
82
    value(p) < 1 && throw(DomainError(p))
×
83
    milliseconds = datetime2epochms(dt)
×
84
    return epochms2datetime(milliseconds - mod(milliseconds, value(Millisecond(p))))
×
85
end
86

87
"""
88
    floor(x::Period, precision::T) where T <: Union{TimePeriod, Week, Day} -> T
89

90
Round `x` down to the nearest multiple of `precision`. If `x` and `precision` are different
91
subtypes of `Period`, the return value will have the same type as `precision`.
92

93
For convenience, `precision` may be a type instead of a value: `floor(x, Dates.Hour)` is a
94
shortcut for `floor(x, Dates.Hour(1))`.
95

96
```jldoctest
97
julia> floor(Day(16), Week)
98
2 weeks
99

100
julia> floor(Minute(44), Minute(15))
101
30 minutes
102

103
julia> floor(Hour(36), Day)
104
1 day
105
```
106

107
Rounding to a `precision` of `Month`s or `Year`s is not supported, as these `Period`s are of
108
inconsistent length.
109
"""
110
function Base.floor(x::ConvertiblePeriod, precision::T) where T <: ConvertiblePeriod
×
111
    value(precision) < 1 && throw(DomainError(precision))
×
112
    _x, _precision = promote(x, precision)
×
113
    return T(_x - mod(_x, _precision))
×
114
end
115

116
"""
117
    floor(dt::TimeType, p::Period) -> TimeType
118

119
Return the nearest `Date` or `DateTime` less than or equal to `dt` at resolution `p`.
120

121
For convenience, `p` may be a type instead of a value: `floor(dt, Dates.Hour)` is a shortcut
122
for `floor(dt, Dates.Hour(1))`.
123

124
```jldoctest
125
julia> floor(Date(1985, 8, 16), Month)
126
1985-08-01
127

128
julia> floor(DateTime(2013, 2, 13, 0, 31, 20), Minute(15))
129
2013-02-13T00:30:00
130

131
julia> floor(DateTime(2016, 8, 6, 12, 0, 0), Day)
132
2016-08-06T00:00:00
133
```
134
"""
135
Base.floor(::Dates.TimeType, ::Dates.Period)
136

137
"""
138
    ceil(dt::TimeType, p::Period) -> TimeType
139

140
Return the nearest `Date` or `DateTime` greater than or equal to `dt` at resolution `p`.
141

142
For convenience, `p` may be a type instead of a value: `ceil(dt, Dates.Hour)` is a shortcut
143
for `ceil(dt, Dates.Hour(1))`.
144

145
```jldoctest
146
julia> ceil(Date(1985, 8, 16), Month)
147
1985-09-01
148

149
julia> ceil(DateTime(2013, 2, 13, 0, 31, 20), Minute(15))
150
2013-02-13T00:45:00
151

152
julia> ceil(DateTime(2016, 8, 6, 12, 0, 0), Day)
153
2016-08-07T00:00:00
154
```
155
"""
156
function Base.ceil(dt::TimeType, p::Period)
×
157
    f = floor(dt, p)
×
158
    return (dt == f) ? f : f + p
×
159
end
160

161
"""
162
    ceil(x::Period, precision::T) where T <: Union{TimePeriod, Week, Day} -> T
163

164
Round `x` up to the nearest multiple of `precision`. If `x` and `precision` are different
165
subtypes of `Period`, the return value will have the same type as `precision`.
166

167
For convenience, `precision` may be a type instead of a value: `ceil(x, Dates.Hour)` is a
168
shortcut for `ceil(x, Dates.Hour(1))`.
169

170
```jldoctest
171
julia> ceil(Day(16), Week)
172
3 weeks
173

174
julia> ceil(Minute(44), Minute(15))
175
45 minutes
176

177
julia> ceil(Hour(36), Day)
178
2 days
179
```
180

181
Rounding to a `precision` of `Month`s or `Year`s is not supported, as these `Period`s are of
182
inconsistent length.
183
"""
184
function Base.ceil(x::ConvertiblePeriod, precision::ConvertiblePeriod)
×
185
    f = floor(x, precision)
×
186
    return (x == f) ? f : f + precision
×
187
end
188

189
"""
190
    floorceil(dt::TimeType, p::Period) -> (TimeType, TimeType)
191

192
Simultaneously return the `floor` and `ceil` of a `Date` or `DateTime` at resolution `p`.
193
More efficient than calling both `floor` and `ceil` individually.
194
"""
195
function floorceil(dt::TimeType, p::Period)
×
196
    f = floor(dt, p)
×
197
    return f, (dt == f) ? f : f + p
×
198
end
199

200
"""
201
    floorceil(x::Period, precision::T) where T <: Union{TimePeriod, Week, Day} -> (T, T)
202

203
Simultaneously return the `floor` and `ceil` of `Period` at resolution `p`.  More efficient
204
than calling both `floor` and `ceil` individually.
205
"""
206
function floorceil(x::ConvertiblePeriod, precision::ConvertiblePeriod)
×
207
    f = floor(x, precision)
×
208
    return f, (x == f) ? f : f + precision
×
209
end
210

211
"""
212
    round(dt::TimeType, p::Period, [r::RoundingMode]) -> TimeType
213

214
Return the `Date` or `DateTime` nearest to `dt` at resolution `p`. By default
215
(`RoundNearestTiesUp`), ties (e.g., rounding 9:30 to the nearest hour) will be rounded up.
216

217
For convenience, `p` may be a type instead of a value: `round(dt, Dates.Hour)` is a shortcut
218
for `round(dt, Dates.Hour(1))`.
219

220
```jldoctest
221
julia> round(Date(1985, 8, 16), Month)
222
1985-08-01
223

224
julia> round(DateTime(2013, 2, 13, 0, 31, 20), Minute(15))
225
2013-02-13T00:30:00
226

227
julia> round(DateTime(2016, 8, 6, 12, 0, 0), Day)
228
2016-08-07T00:00:00
229
```
230

231
Valid rounding modes for `round(::TimeType, ::Period, ::RoundingMode)` are
232
`RoundNearestTiesUp` (default), `RoundDown` (`floor`), and `RoundUp` (`ceil`).
233
"""
234
function Base.round(dt::TimeType, p::Period, r::RoundingMode{:NearestTiesUp})
×
235
    f, c = floorceil(dt, p)
×
236
    return (dt - f) < (c - dt) ? f : c
×
237
end
238

239
"""
240
    round(x::Period, precision::T, [r::RoundingMode]) where T <: Union{TimePeriod, Week, Day} -> T
241

242
Round `x` to the nearest multiple of `precision`. If `x` and `precision` are different
243
subtypes of `Period`, the return value will have the same type as `precision`. By default
244
(`RoundNearestTiesUp`), ties (e.g., rounding 90 minutes to the nearest hour) will be rounded
245
up.
246

247
For convenience, `precision` may be a type instead of a value: `round(x, Dates.Hour)` is a
248
shortcut for `round(x, Dates.Hour(1))`.
249

250
```jldoctest
251
julia> round(Day(16), Week)
252
2 weeks
253

254
julia> round(Minute(44), Minute(15))
255
45 minutes
256

257
julia> round(Hour(36), Day)
258
2 days
259
```
260

261
Valid rounding modes for `round(::Period, ::T, ::RoundingMode)` are `RoundNearestTiesUp`
262
(default), `RoundDown` (`floor`), and `RoundUp` (`ceil`).
263

264
Rounding to a `precision` of `Month`s or `Year`s is not supported, as these `Period`s are of
265
inconsistent length.
266
"""
267
function Base.round(x::ConvertiblePeriod, precision::ConvertiblePeriod, r::RoundingMode{:NearestTiesUp})
×
268
    f, c = floorceil(x, precision)
×
269
    _x, _f, _c = promote(x, f, c)
×
270
    return (_x - _f) < (_c - _x) ? f : c
×
271
end
272

273
Base.round(x::TimeTypeOrPeriod, p::Period, r::RoundingMode{:Down}) = Base.floor(x, p)
×
274
Base.round(x::TimeTypeOrPeriod, p::Period, r::RoundingMode{:Up}) = Base.ceil(x, p)
×
275

276
# No implementation of other `RoundingMode`s: rounding to nearest "even" is skipped because
277
# "even" is not defined for Period; rounding toward/away from zero is skipped because ISO
278
# 8601's year 0000 is not really "zero".
279
Base.round(::TimeTypeOrPeriod, p::Period, ::RoundingMode) = throw(DomainError(p))
×
280

281
# Default to RoundNearestTiesUp.
282
Base.round(x::TimeTypeOrPeriod, p::Period) = Base.round(x, p, RoundNearestTiesUp)
×
283

284
# Make rounding functions callable using Period types in addition to values.
285
Base.floor(x::TimeTypeOrPeriod, ::Type{P}) where P <: Period = Base.floor(x, oneunit(P))
×
286
Base.ceil(x::TimeTypeOrPeriod, ::Type{P}) where P <: Period = Base.ceil(x, oneunit(P))
×
287
Base.floor(::Type{Date}, x::TimeTypeOrPeriod, ::Type{P}) where P <: Period = Base.floor(Date(x), oneunit(P))
×
288
Base.ceil(::Type{Date}, x::TimeTypeOrPeriod, ::Type{P}) where P <: Period = Base.ceil(Date(x), oneunit(P))
×
289

290
function Base.round(x::TimeTypeOrPeriod, ::Type{P}, r::RoundingMode=RoundNearestTiesUp) where P <: Period
×
291
    return Base.round(x, oneunit(P), r)
×
292
end
293

294
function Base.round(::Type{Date}, x::TimeTypeOrPeriod, ::Type{P}, r::RoundingMode=RoundNearestTiesUp) where P <: Period
×
295
    return Base.round(Date(x), oneunit(P), r)
×
296
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc