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

JuliaLang / julia / #37599

16 Aug 2023 01:53AM UTC coverage: 86.427% (-1.1%) from 87.526%
#37599

push

local

web-flow
Change heap-size-hint in test processes to total memory (#50922)

It seems this is causing macos to hang because the shown free memory is
generally very small.

xref: JuliaLang/julia#50673

73086 of 84564 relevant lines covered (86.43%)

32342958.75 hits per line

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

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

3
"""
4
    AbstractDateToken
5

6
A token used in parsing or formatting a date time string. Each subtype must
7
define the tryparsenext and format methods.
8

9
"""
10
abstract type AbstractDateToken end
11

12
"""
13
    tryparsenext(tok::AbstractDateToken, str::String, i::Int, len::Int, locale::DateLocale)
14

15
`tryparsenext` parses for the `tok` token in `str` starting at index `i`.
16
`len` is the length of the string.  parsing can be optionally based on the
17
`locale`. If a `tryparsenext` method does not need a locale, it can leave
18
the argument out in the method definition.
19

20
If parsing succeeds, returns a tuple of 2 elements `(res, idx)`, where:
21

22
* `res` is the result of the parsing.
23
* `idx::Int`, is the index _after_ the index at which parsing ended.
24
"""
25
function tryparsenext end
26

27
"""
28
    format(io::IO, tok::AbstractDateToken, dt::TimeType, locale)
29

30
Format the `tok` token from `dt` and write it to `io`. The formatting can
31
be based on `locale`.
32

33
All subtypes of `AbstractDateToken` must define this method in order
34
to be able to print a Date / DateTime object according to a `DateFormat`
35
containing that token.
36
"""
37
format(io::IO, tok::AbstractDateToken, dt::TimeType, locale)
38

39
# fallback to tryparsenext/format methods that don't care about locale
40
@inline function tryparsenext(d::AbstractDateToken, str, i, len, locale)
83✔
41
    return tryparsenext(d, str, i, len)
166✔
42
end
43

44
function Base.string(t::Time)
×
45
    h, mi, s = hour(t), minute(t), second(t)
×
46
    hh = lpad(h, 2, "0")
×
47
    mii = lpad(mi, 2, "0")
×
48
    ss = lpad(s, 2, "0")
×
49
    nss = tons(Millisecond(t)) + tons(Microsecond(t)) + tons(Nanosecond(t))
×
50
    ns = nss == 0 ? "" : rstrip(@sprintf("%.9f", nss / 1e+9)[2:end], '0')
×
51
    return "$hh:$mii:$ss$ns"
×
52
end
53

54
Base.show(io::IO, ::MIME"text/plain", t::Time) = print(io, t)
×
55
Base.print(io::IO, t::Time) = print(io, string(t))
×
56

57
function Base.show(io::IO, t::Time)
×
58
    if get(io, :compact, false)::Bool
×
59
        print(io, t)
×
60
    else
61
        values = [
×
62
            hour(t)
63
            minute(t)
64
            second(t)
65
            millisecond(t)
66
            microsecond(t)
67
            nanosecond(t)
68
        ]
69
        index = something(findlast(!iszero, values), 1)
×
70

71
        print(io, Time, "(")
×
72
        for i in 1:index
×
73
            show(io, values[i])
×
74
            i != index && print(io, ", ")
×
75
        end
×
76
        print(io, ")")
×
77
    end
78
end
79

80
@inline function format(io, d::AbstractDateToken, dt, locale)
1,982✔
81
    format(io, d, dt)
2,028✔
82
end
83

84
# Information for parsing and formatting date time values.
85
struct DateFormat{S, T<:Tuple}
86
    tokens::T
2✔
87
    locale::DateLocale
88
end
89

90
### Token types ###
91

92
struct DatePart{letter} <: AbstractDateToken
93
    width::Int
13✔
94
    fixed::Bool
95
end
96

97
@inline min_width(d::DatePart) = d.fixed ? d.width : 1
94✔
98
@inline max_width(d::DatePart) = d.fixed ? d.width : 0
94✔
99

100
function _show_content(io::IO, d::DatePart{c}) where c
×
101
    for i = 1:d.width
×
102
        print(io, c)
×
103
    end
×
104
end
105

106
function Base.show(io::IO, d::DatePart{c}) where c
×
107
    print(io, "DatePart(")
×
108
    _show_content(io, d)
×
109
    print(io, ")")
×
110
end
111

112
### Parse tokens
113

114
for c in "yYmdHIMS"
115
    @eval begin
116
        @inline function tryparsenext(d::DatePart{$c}, str, i, len)
45✔
117
            return tryparsenext_base10(str, i, len, min_width(d), max_width(d))
90✔
118
        end
119
    end
120
end
121

122
function tryparsenext(d::DatePart{'p'}, str, i, len)
×
123
    i+1 > len && return nothing
×
124
    c, ii = iterate(str, i)::Tuple{Char, Int}
×
125
    ap = lowercase(c)
×
126
    (ap == 'a' || ap == 'p') || return nothing
×
127
    c, ii = iterate(str, ii)::Tuple{Char, Int}
×
128
    lowercase(c) == 'm' || return nothing
×
129
    return ap == 'a' ? AM : PM, ii
×
130
end
131

132
for (tok, fn) in zip("uUeE", Any[monthabbr_to_value, monthname_to_value, dayabbr_to_value, dayname_to_value])
133
    @eval @inline function tryparsenext(d::DatePart{$tok}, str, i, len, locale)
×
134
        next = tryparsenext_word(str, i, len, locale, max_width(d))
×
135
        next === nothing && return nothing
×
136
        word, i = next
×
137
        val = $fn(word, locale)
×
138
        val == 0 && return nothing
×
139
        return val, i
×
140
    end
141
end
142

143
# 3-digit (base 10) number following a decimal point. For InexactError below.
144
struct Decimal3 end
145

146
@inline function tryparsenext(d::DatePart{'s'}, str, i, len)
2✔
147
    val = tryparsenext_base10(str, i, len, min_width(d), max_width(d))
4✔
148
    val === nothing && return nothing
2✔
149
    ms0, ii = val
2✔
150
    len = ii - i
2✔
151
    if len > 3
2✔
152
        ms, r = divrem(ms0, Int64(10) ^ (len - 3))
×
153
        r == 0 || return nothing
×
154
    else
155
        ms = ms0 * Int64(10) ^ (3 - len)
2✔
156
    end
157
    return ms, ii
2✔
158
end
159

160
### Format tokens
161

162
hour12(dt) = let h = hour(dt); h > 12 ? h - 12 : h == 0 ? 12 : h; end
×
163

164
for (c, fn) in zip("YmdHIMS", Any[year, month, day, hour, hour12, minute, second])
165
    @eval function format(io, d::DatePart{$c}, dt)
861✔
166
        print(io, string($fn(dt), base = 10, pad = d.width))
1,737✔
167
    end
168
end
169

170
for (tok, fn) in zip("uU", Any[monthabbr, monthname])
171
    @eval function format(io, d::DatePart{$tok}, dt, locale)
×
172
        print(io, $fn(month(dt), locale))
×
173
    end
174
end
175

176
function format(io, d::DatePart{'p'}, dt, locale)
×
177
    ampm = hour(dt) < 12 ? "AM" : "PM" # fixme: locale-specific?
×
178
    print(io, ampm)
×
179
end
180

181
for (tok, fn) in zip("eE", Any[dayabbr, dayname])
182
    @eval function format(io, ::DatePart{$tok}, dt, locale)
×
183
        print(io, $fn(dayofweek(dt), locale))
×
184
    end
185
end
186

187
@inline function format(io, d::DatePart{'y'}, dt)
×
188
    y = year(dt)
×
189
    n = d.width
×
190

191
    # the last n digits of y
192
    # will be 0 padded if y has less than n digits
193
    str = string(y, base = 10, pad = n)
×
194
    l = lastindex(str)
×
195
    if l == n
×
196
        # fast path
197
        print(io, str)
×
198
    else
199
        print(io, SubString(str, l - (n - 1), l))
×
200
    end
201
end
202

203
function format(io, d::DatePart{'s'}, dt)
283✔
204
    ms = millisecond(dt)
283✔
205
    if ms % 100 == 0
283✔
206
        str = string(div(ms, 100))
9✔
207
    elseif ms % 10 == 0
274✔
208
        str = string(div(ms, 10), pad = 2)
32✔
209
    else
210
        str = string(ms, pad = 3)
242✔
211
    end
212

213
    print(io, rpad(str, d.width, '0'))
283✔
214
end
215

216
### Delimiters
217

218
struct Delim{T, length} <: AbstractDateToken
219
    d::T
13✔
220
end
221

222
Delim(d::T) where {T<:AbstractChar} = Delim{T, 1}(d)
13✔
223
Delim(d::String) = Delim{String, length(d)}(d)
×
224

225
@inline function tryparsenext(d::Delim{<:AbstractChar, N}, str, i::Int, len) where N
36✔
226
    for j = 1:N
36✔
227
        i > len && return nothing
36✔
228
        next = iterate(str, i)
72✔
229
        @assert next !== nothing
36✔
230
        c, i = next
36✔
231
        c != d.d && return nothing
36✔
232
    end
36✔
233
    return true, i
36✔
234
end
235

236
@inline function tryparsenext(d::Delim{String, N}, str, i::Int, len) where N
×
237
    i1 = i
×
238
    i2 = firstindex(d.d)
×
239
    for j = 1:N
×
240
        if i1 > len
×
241
            return nothing
×
242
        end
243
        next1 = iterate(str, i1)
×
244
        @assert next1 !== nothing
×
245
        c1, i1 = next1
×
246
        next2 = iterate(d.d, i2)
×
247
        @assert next2 !== nothing
×
248
        c2, i2 = next2
×
249
        if c1 != c2
×
250
            return nothing
×
251
        end
252
    end
×
253
    return true, i1
×
254
end
255

256
@inline function format(io, d::Delim, dt, locale)
1,698✔
257
    print(io, d.d)
1,741✔
258
end
259

260
function _show_content(io::IO, d::Delim{<:AbstractChar, N}) where N
×
261
    if d.d in keys(CONVERSION_SPECIFIERS)
×
262
        for i = 1:N
×
263
            print(io, '\\', d.d)
×
264
        end
×
265
    else
266
        for i = 1:N
×
267
            print(io, d.d)
×
268
        end
×
269
    end
270
end
271

272
function _show_content(io::IO, d::Delim)
×
273
    for c in d.d
×
274
        if c in keys(CONVERSION_SPECIFIERS)
×
275
            print(io, '\\')
×
276
        end
277
        print(io, c)
×
278
    end
×
279
end
280

281
function Base.show(io::IO, d::Delim)
×
282
    print(io, "Delim(")
×
283
    _show_content(io, d)
×
284
    print(io, ")")
×
285
end
286

287
### DateFormat construction
288

289
abstract type DayOfWeekToken end # special addition to Period types
290

291
# Map conversion specifiers or character codes to tokens.
292
# Note: Allow addition of new character codes added by packages
293
const CONVERSION_SPECIFIERS = Dict{Char, Type}(
294
    'y' => Year,
295
    'Y' => Year,
296
    'm' => Month,
297
    'u' => Month,
298
    'U' => Month,
299
    'e' => DayOfWeekToken,
300
    'E' => DayOfWeekToken,
301
    'd' => Day,
302
    'H' => Hour,
303
    'I' => Hour,
304
    'M' => Minute,
305
    'S' => Second,
306
    's' => Millisecond,
307
    'p' => AMPM,
308
)
309

310
# Default values are needed when a conversion specifier is used in a DateFormat for parsing
311
# and we have reached the end of the input string.
312
# Note: Allow `Any` value as a default to support extensibility
313
const CONVERSION_DEFAULTS = IdDict{Type, Any}(
314
    Year => Int64(1),
315
    Month => Int64(1),
316
    DayOfWeekToken => Int64(0),
317
    Day => Int64(1),
318
    Hour => Int64(0),
319
    Minute => Int64(0),
320
    Second => Int64(0),
321
    Millisecond => Int64(0),
322
    Microsecond => Int64(0),
323
    Nanosecond => Int64(0),
324
    AMPM => TWENTYFOURHOUR,
325
)
326

327
# Specifies the required fields in order to parse a TimeType
328
# Note: Allows for addition of new TimeTypes
329
const CONVERSION_TRANSLATIONS = IdDict{Type, Any}(
330
    Date => (Year, Month, Day),
331
    DateTime => (Year, Month, Day, Hour, Minute, Second, Millisecond, AMPM),
332
    Time => (Hour, Minute, Second, Millisecond, Microsecond, Nanosecond, AMPM),
333
)
334

335
# The `DateFormat(format, locale)` method just below consumes the following Regex.
336
# Constructing this Regex is fairly expensive; doing so in the method itself can
337
# consume half or better of `DateFormat(format, locale)`'s runtime. So instead we
338
# construct and cache it outside the method body. Note, however, that when
339
# `keys(CONVERSION_SPECIFIERS)` changes, the cached Regex must be updated accordingly;
340
# hence the mutability (Ref-ness) of the cache, the helper method with which to populate
341
# the cache, the cache of the hash of `keys(CONVERSION_SPECIFIERS)` (to facilitate checking
342
# for changes), and the lock (to maintain consistency of these objects across threads when
343
# threads simultaneously modify `CONVERSION_SPECIFIERS` and construct `DateFormat`s).
344
function compute_dateformat_regex(conversion_specifiers)
×
345
    letters = String(collect(keys(conversion_specifiers)))
×
346
    return Regex("(?<!\\\\)([\\Q$letters\\E])\\1*")
×
347
end
348
const DATEFORMAT_REGEX_LOCK = ReentrantLock()
349
const DATEFORMAT_REGEX_HASH = Ref(hash(keys(CONVERSION_SPECIFIERS)))
350
const DATEFORMAT_REGEX_CACHE = Ref(compute_dateformat_regex(CONVERSION_SPECIFIERS))
351

352
"""
353
    DateFormat(format::AbstractString, locale="english") -> DateFormat
354

355
Construct a date formatting object that can be used for parsing date strings or
356
formatting a date object as a string. The following character codes can be used to construct the `format`
357
string:
358

359
| Code       | Matches   | Comment                                                       |
360
|:-----------|:----------|:--------------------------------------------------------------|
361
| `Y`        | 1996, 96  | Returns year of 1996, 0096                                    |
362
| `y`        | 1996, 96  | Same as `Y` on `parse` but discards excess digits on `format` |
363
| `m`        | 1, 01     | Matches 1 or 2-digit months                                   |
364
| `u`        | Jan       | Matches abbreviated months according to the `locale` keyword  |
365
| `U`        | January   | Matches full month names according to the `locale` keyword    |
366
| `d`        | 1, 01     | Matches 1 or 2-digit days                                     |
367
| `H`        | 00        | Matches hours (24-hour clock)                                 |
368
| `I`        | 00        | For outputting hours with 12-hour clock                       |
369
| `M`        | 00        | Matches minutes                                               |
370
| `S`        | 00        | Matches seconds                                               |
371
| `s`        | .500      | Matches milliseconds                                          |
372
| `e`        | Mon, Tues | Matches abbreviated days of the week                          |
373
| `E`        | Monday    | Matches full name days of the week                            |
374
| `p`        | AM        | Matches AM/PM (case-insensitive)                              |
375
| `yyyymmdd` | 19960101  | Matches fixed-width year, month, and day                      |
376

377
Characters not listed above are normally treated as delimiters between date and time slots.
378
For example a `dt` string of "1996-01-15T00:00:00.0" would have a `format` string like
379
"y-m-dTH:M:S.s". If you need to use a code character as a delimiter you can escape it using
380
backslash. The date "1995y01m" would have the format "y\\ym\\m".
381

382
Note that 12:00AM corresponds 00:00 (midnight), and 12:00PM corresponds to 12:00 (noon).
383
When parsing a time with a `p` specifier, any hour (either `H` or `I`) is interpreted as
384
as a 12-hour clock, so the `I` code is mainly useful for output.
385

386
Creating a DateFormat object is expensive. Whenever possible, create it once and use it many times
387
or try the [`dateformat""`](@ref @dateformat_str) string macro. Using this macro creates the DateFormat
388
object once at macro expansion time and reuses it later. There are also several [pre-defined formatters](@ref
389
Common-Date-Formatters), listed later.
390

391
See [`DateTime`](@ref) and [`format`](@ref) for how to use a DateFormat object to parse and write Date strings
392
respectively.
393
"""
394
function DateFormat(f::AbstractString, locale::DateLocale=ENGLISH)
4✔
395
    tokens = AbstractDateToken[]
4✔
396
    prev = ()
×
397
    prev_offset = 1
×
398

399
    # To understand this block, please see the comments attached to the definitions of
400
    # DATEFORMAT_REGEX_LOCK, DATEFORMAT_REGEX_HASH, and DATEFORMAT_REGEX_CACHE.
401
    lock(DATEFORMAT_REGEX_LOCK)
2✔
402
    try
2✔
403
        dateformat_regex_hash = hash(keys(CONVERSION_SPECIFIERS))
2✔
404
        if dateformat_regex_hash != DATEFORMAT_REGEX_HASH[]
2✔
405
            DATEFORMAT_REGEX_HASH[] = dateformat_regex_hash
×
406
            DATEFORMAT_REGEX_CACHE[] = compute_dateformat_regex(CONVERSION_SPECIFIERS)
×
407
        end
408
    finally
409
        unlock(DATEFORMAT_REGEX_LOCK)
4✔
410
    end
411

412
    for m in eachmatch(DATEFORMAT_REGEX_CACHE[], f)
4✔
413
        tran = replace(f[prev_offset:prevind(f, m.offset)], r"\\(.)" => s"\1")
24✔
414

415
        if !isempty(prev)
24✔
416
            letter, width = prev
×
417
            push!(tokens, DatePart{letter}(width, isempty(tran)))
11✔
418
        end
419

420
        if !isempty(tran)
13✔
421
            push!(tokens, Delim(length(tran) == 1 ? first(tran) : tran))
11✔
422
        end
423

424
        letter = f[m.offset]
26✔
425
        width = length(m.match)
13✔
426

427
        prev = (letter, width)
×
428
        prev_offset = m.offset + width
13✔
429
    end
24✔
430

431
    tran = replace(f[prev_offset:lastindex(f)], r"\\(.)" => s"\1")
4✔
432

433
    if !isempty(prev)
4✔
434
        letter, width = prev
×
435
        push!(tokens, DatePart{letter}(width, false))
2✔
436
    end
437

438
    if !isempty(tran)
2✔
439
        push!(tokens, Delim(length(tran) == 1 ? first(tran) : tran))
2✔
440
    end
441

442
    tokens_tuple = (tokens...,)
2✔
443
    return DateFormat{Symbol(f),typeof(tokens_tuple)}(tokens_tuple, locale)
2✔
444
end
445

446
function DateFormat(f::AbstractString, locale::AbstractString)
×
447
    DateFormat(f, LOCALES[locale])
×
448
end
449

450
function Base.show(io::IO, df::DateFormat{S,T}) where {S,T}
6✔
451
    print(io, "dateformat\"", S, '"')
6✔
452
end
453
Base.Broadcast.broadcastable(x::DateFormat) = Ref(x)
×
454

455
"""
456
    dateformat"Y-m-d H:M:S"
457

458
Create a [`DateFormat`](@ref) object. Similar to `DateFormat("Y-m-d H:M:S")`
459
but creates the DateFormat object once during macro expansion.
460

461
See [`DateFormat`](@ref) for details about format specifiers.
462
"""
463
macro dateformat_str(str)
2✔
464
    DateFormat(str)
2✔
465
end
466

467
# Standard formats
468

469
"""
470
    Dates.ISODateTimeFormat
471

472
Describes the ISO8601 formatting for a date and time. This is the default value for `Dates.format`
473
of a `DateTime`.
474

475
# Example
476
```jldoctest
477
julia> Dates.format(DateTime(2018, 8, 8, 12, 0, 43, 1), ISODateTimeFormat)
478
"2018-08-08T12:00:43.001"
479
```
480
"""
481
const ISODateTimeFormat = DateFormat("yyyy-mm-dd\\THH:MM:SS.s")
482
default_format(::Type{DateTime}) = ISODateTimeFormat
18✔
483

484
"""
485
    Dates.ISODateFormat
486

487
Describes the ISO8601 formatting for a date. This is the default value for `Dates.format` of a `Date`.
488

489
# Example
490
```jldoctest
491
julia> Dates.format(Date(2018, 8, 8), ISODateFormat)
492
"2018-08-08"
493
```
494
"""
495
const ISODateFormat = DateFormat("yyyy-mm-dd")
496
default_format(::Type{Date}) = ISODateFormat
1✔
497

498
"""
499
    Dates.ISOTimeFormat
500

501
Describes the ISO8601 formatting for a time. This is the default value for `Dates.format` of a `Time`.
502

503
# Example
504
```jldoctest
505
julia> Dates.format(Time(12, 0, 43, 1), ISOTimeFormat)
506
"12:00:43.001"
507
```
508
"""
509
const ISOTimeFormat = DateFormat("HH:MM:SS.s")
510
default_format(::Type{Time}) = ISOTimeFormat
2✔
511

512
"""
513
    Dates.RFC1123Format
514

515
Describes the RFC1123 formatting for a date and time.
516

517
# Example
518
```jldoctest
519
julia> Dates.format(DateTime(2018, 8, 8, 12, 0, 43, 1), RFC1123Format)
520
"Wed, 08 Aug 2018 12:00:43"
521
```
522
"""
523
const RFC1123Format = DateFormat("e, dd u yyyy HH:MM:SS")
524

525

526
### API
527

528
const Locale = Union{DateLocale, String}
529

530
"""
531
    DateTime(dt::AbstractString, format::AbstractString; locale="english") -> DateTime
532

533
Construct a `DateTime` by parsing the `dt` date time string following the
534
pattern given in the `format` string (see [`DateFormat`](@ref)  for syntax).
535

536
!!! note
537
    This method creates a `DateFormat` object each time it is called. It is recommended
538
    that you create a [`DateFormat`](@ref) object instead and use that as the second
539
    argument to avoid performance loss when using the same format repeatedly.
540

541
# Example
542
```jldoctest
543
julia> DateTime("2020-01-01", "yyyy-mm-dd")
544
2020-01-01T00:00:00
545

546
julia> a = ("2020-01-01", "2020-01-02");
547

548
julia> [DateTime(d, dateformat"yyyy-mm-dd") for d ∈ a] # preferred
549
2-element Vector{DateTime}:
550
 2020-01-01T00:00:00
551
 2020-01-02T00:00:00
552
```
553
"""
554
function DateTime(dt::AbstractString, format::AbstractString; locale::Locale=ENGLISH)
×
555
    return parse(DateTime, dt, DateFormat(format, locale))
×
556
end
557

558
"""
559
    DateTime(dt::AbstractString, df::DateFormat=ISODateTimeFormat) -> DateTime
560

561
Construct a `DateTime` by parsing the `dt` date time string following the
562
pattern given in the [`DateFormat`](@ref) object, or $ISODateTimeFormat if omitted.
563

564
Similar to `DateTime(::AbstractString, ::AbstractString)` but more efficient when
565
repeatedly parsing similarly formatted date time strings with a pre-created
566
`DateFormat` object.
567
"""
568
DateTime(dt::AbstractString, df::DateFormat=ISODateTimeFormat) = parse(DateTime, dt, df)
×
569

570
"""
571
    Date(d::AbstractString, format::AbstractString; locale="english") -> Date
572

573
Construct a `Date` by parsing the `d` date string following the pattern given
574
in the `format` string (see [`DateFormat`](@ref) for syntax).
575

576
!!! note
577
    This method creates a `DateFormat` object each time it is called. It is recommended
578
    that you create a [`DateFormat`](@ref) object instead and use that as the second
579
    argument to avoid performance loss when using the same format repeatedly.
580

581
# Example
582
```jldoctest
583
julia> Date("2020-01-01", "yyyy-mm-dd")
584
2020-01-01
585

586
julia> a = ("2020-01-01", "2020-01-02");
587

588
julia> [Date(d, dateformat"yyyy-mm-dd") for d ∈ a] # preferred
589
2-element Vector{Date}:
590
 2020-01-01
591
 2020-01-02
592
```
593
"""
594
function Date(d::AbstractString, format::AbstractString; locale::Locale=ENGLISH)
×
595
    parse(Date, d, DateFormat(format, locale))
×
596
end
597

598
"""
599
    Date(d::AbstractString, df::DateFormat=ISODateFormat) -> Date
600

601
Construct a `Date` by parsing the `d` date string following the
602
pattern given in the [`DateFormat`](@ref) object, or $ISODateFormat if omitted.
603

604
Similar to `Date(::AbstractString, ::AbstractString)` but more efficient when
605
repeatedly parsing similarly formatted date strings with a pre-created
606
`DateFormat` object.
607
"""
608
Date(d::AbstractString, df::DateFormat=ISODateFormat) = parse(Date, d, df)
16✔
609

610
"""
611
    Time(t::AbstractString, format::AbstractString; locale="english") -> Time
612

613
Construct a `Time` by parsing the `t` time string following the pattern given
614
in the `format` string (see [`DateFormat`](@ref) for syntax).
615

616
!!! note
617
    This method creates a `DateFormat` object each time it is called. It is recommended
618
    that you create a [`DateFormat`](@ref) object instead and use that as the second
619
    argument to avoid performance loss when using the same format repeatedly.
620

621
# Example
622
```jldoctest
623
julia> Time("12:34pm", "HH:MMp")
624
12:34:00
625

626
julia> a = ("12:34pm", "2:34am");
627

628
julia> [Time(d, dateformat"HH:MMp") for d ∈ a] # preferred
629
2-element Vector{Time}:
630
 12:34:00
631
 02:34:00
632
```
633
"""
634
function Time(t::AbstractString, format::AbstractString; locale::Locale=ENGLISH)
×
635
    parse(Time, t, DateFormat(format, locale))
×
636
end
637

638
"""
639
    Time(t::AbstractString, df::DateFormat=ISOTimeFormat) -> Time
640

641
Construct a `Time` by parsing the `t` date time string following the
642
pattern given in the [`DateFormat`](@ref) object, or $ISOTimeFormat if omitted.
643

644
Similar to `Time(::AbstractString, ::AbstractString)` but more efficient when
645
repeatedly parsing similarly formatted time strings with a pre-created
646
`DateFormat` object.
647
"""
648
Time(t::AbstractString, df::DateFormat=ISOTimeFormat) = parse(Time, t, df)
×
649

650
@generated function format(io::IO, dt::TimeType, fmt::DateFormat{<:Any,T}) where T
292✔
651
    N = fieldcount(T)
4✔
652
    quote
4✔
653
        ts = fmt.tokens
292✔
654
        loc = fmt.locale
284✔
655
        Base.@nexprs $N i -> format(io, ts[i], dt, loc)
292✔
656
    end
657
end
658

659
function format(dt::TimeType, fmt::DateFormat, bufsize=12)
292✔
660
    # preallocate to reduce resizing
661
    io = IOBuffer(Vector{UInt8}(undef, bufsize), read=true, write=true)
300✔
662
    format(io, dt, fmt)
292✔
663
    String(io.data[1:io.ptr - 1])
292✔
664
end
665

666

667
"""
668
    format(dt::TimeType, format::AbstractString; locale="english") -> AbstractString
669

670
Construct a string by using a `TimeType` object and applying the provided `format`. The
671
following character codes can be used to construct the `format` string:
672

673
| Code       | Examples  | Comment                                                      |
674
|:-----------|:----------|:-------------------------------------------------------------|
675
| `y`        | 6         | Numeric year with a fixed width                              |
676
| `Y`        | 1996      | Numeric year with a minimum width                            |
677
| `m`        | 1, 12     | Numeric month with a minimum width                           |
678
| `u`        | Jan       | Month name shortened to 3-chars according to the `locale`    |
679
| `U`        | January   | Full month name according to the `locale` keyword            |
680
| `d`        | 1, 31     | Day of the month with a minimum width                        |
681
| `H`        | 0, 23     | Hour (24-hour clock) with a minimum width                    |
682
| `M`        | 0, 59     | Minute with a minimum width                                  |
683
| `S`        | 0, 59     | Second with a minimum width                                  |
684
| `s`        | 000, 500  | Millisecond with a minimum width of 3                        |
685
| `e`        | Mon, Tue  | Abbreviated days of the week                                 |
686
| `E`        | Monday    | Full day of week name                                        |
687

688
The number of sequential code characters indicate the width of the code. A format of
689
`yyyy-mm` specifies that the code `y` should have a width of four while `m` a width of two.
690
Codes that yield numeric digits have an associated mode: fixed-width or minimum-width.
691
The fixed-width mode left-pads the value with zeros when it is shorter than the specified
692
width and truncates the value when longer. Minimum-width mode works the same as fixed-width
693
except that it does not truncate values longer than the width.
694

695
When creating a `format` you can use any non-code characters as a separator. For example to
696
generate the string "1996-01-15T00:00:00" you could use `format`: "yyyy-mm-ddTHH:MM:SS".
697
Note that if you need to use a code character as a literal you can use the escape character
698
backslash. The string "1996y01m" can be produced with the format "yyyy\\ymm\\m".
699
"""
700
function format(dt::TimeType, f::AbstractString; locale::Locale=ENGLISH)
×
701
    format(dt, DateFormat(f, locale))
×
702
end
703

704
# show
705
function Base.print(io::IO, dt::DateTime)
284✔
706
    str = if millisecond(dt) == 0
284✔
707
        format(dt, dateformat"YYYY-mm-dd\THH:MM:SS", 19)
6✔
708
    else
709
        format(dt, dateformat"YYYY-mm-dd\THH:MM:SS.sss", 23)
562✔
710
    end
711
    print(io, str)
284✔
712
end
713

714
function Base.print(io::IO, dt::Date)
×
715
    # don't use format - bypassing IOBuffer creation
716
    # saves a bit of time here.
717
    y,m,d = yearmonthday(value(dt))
×
718
    yy = y < 0 ? @sprintf("%05i", y) : lpad(y, 4, "0")
×
719
    mm = lpad(m, 2, "0")
×
720
    dd = lpad(d, 2, "0")
×
721
    print(io, "$yy-$mm-$dd")
×
722
end
723

724
for date_type in (:Date, :DateTime)
725
    # Human readable output (i.e. "2012-01-01")
726
    @eval Base.show(io::IO, ::MIME"text/plain", dt::$date_type) = print(io, dt)
×
727
    # Parsable output (i.e. Date("2012-01-01"))
728
    @eval Base.show(io::IO, dt::$date_type) = print(io, typeof(dt), "(\"", dt, "\")")
×
729
    # Parsable output will have type info displayed, thus it is implied
730
    @eval Base.typeinfo_implicit(::Type{$date_type}) = true
×
731
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