@@ -332,6 +332,23 @@ const CONVERSION_TRANSLATIONS = IdDict{Type, Any}(
332
332
Time => (Hour, Minute, Second, Millisecond, Microsecond, Nanosecond, AMPM),
333
333
)
334
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
+
335
352
"""
336
353
DateFormat(format::AbstractString, locale="english") -> DateFormat
337
354
@@ -379,8 +396,20 @@ function DateFormat(f::AbstractString, locale::DateLocale=ENGLISH)
379
396
prev = ()
380
397
prev_offset = 1
381
398
382
- letters = String (collect (keys (CONVERSION_SPECIFIERS)))
383
- for m in eachmatch (Regex (" (?<!\\\\ )([\\ Q$letters \\ E])\\ 1*" ), f)
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)
402
+ try
403
+ dateformat_regex_hash = hash (keys (CONVERSION_SPECIFIERS))
404
+ if dateformat_regex_hash != DATEFORMAT_REGEX_HASH[]
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)
410
+ end
411
+
412
+ for m in eachmatch (DATEFORMAT_REGEX_CACHE[], f)
384
413
tran = replace (f[prev_offset: prevind (f, m. offset)], r" \\ (.)" => s "\1 " )
385
414
386
415
if ! isempty (prev)
0 commit comments