Skip to content
This repository has been archived by the owner on Nov 16, 2020. It is now read-only.

Commit

Permalink
Use a default date formatter factory for additional thread safety.
Browse files Browse the repository at this point in the history
  • Loading branch information
MrMage committed Apr 29, 2019
1 parent f6371d1 commit 0b8991c
Showing 1 changed file with 26 additions and 17 deletions.
43 changes: 26 additions & 17 deletions Sources/TemplateKit/Tag/DateFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,39 @@
///
/// If no date format is supplied, a default will be used.
public final class DateFormat: TagRenderer {
private let defaultDateFormatter: DateFormatter
public typealias DateFormatterFactory = () -> DateFormatter

private static let dateAndTimeFormatter: DateFormatter = {
private let defaultDateFormatterFactory: DateFormatterFactory

private static let dateAndTimeFormatterFactory: DateFormatterFactory = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter
}()
}

private static let iso8601Formatter: DateFormatter = {
private static let iso8601FormatterFactory: DateFormatterFactory = {
let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar(identifier: .iso8601)
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return dateFormatter
}()
}

/// Creates a new `DateFormat` tag renderer.
public convenience init() {
self.init(defaultDateFormatter: DateFormat.dateAndTimeFormatter)
self.init(defaultDateFormatterFactory: DateFormat.dateAndTimeFormatterFactory)
}

/// Creates a new `DateFormat` tag renderer.
/// - parameter defaultDateFormatter: The date formatter to use when the tag invocation
/// does not specify a date format.
public init(defaultDateFormatter: DateFormatter) {
self.defaultDateFormatter = defaultDateFormatter
public init(defaultDateFormatterFactory: @escaping DateFormatterFactory) {
self.defaultDateFormatterFactory = defaultDateFormatterFactory
}

/// A `DateFormat` tag renderer that uses ISO 8601 date formatting by default.
public static let iso8601 = DateFormat(defaultDateFormatter: DateFormat.iso8601Formatter)
public static let iso8601 = DateFormat(defaultDateFormatterFactory: DateFormat.iso8601FormatterFactory)

/// See `TagRenderer`.
public func render(tag: TagContext) throws -> Future<TemplateData> {
Expand All @@ -58,17 +60,23 @@ public final class DateFormat: TagRenderer {
}

let dateFormatter: DateFormatter
/// Set format as the second param or default to ISO-8601 format.
if tag.parameters.count == 2, let dateFormat = tag.parameters[1].string {
if let formatter = dateFormatterCache.dateFormatters[dateFormat] {
dateFormatter = formatter
} else {
var dateFormat: String?
if tag.parameters.count == 2 {
/// Set format as the second param. If that's not available, we'll use `self.defaultDateFormatterFactory`.
dateFormat = tag.parameters[1].string
}

let cacheKey = dateFormat ?? DateFormatterCache.defaultFormatterPlaceholderKey
if let formatter = dateFormatterCache.dateFormatters[cacheKey] {
dateFormatter = formatter
} else {
if let dateFormat = dateFormat {
dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateFormat
dateFormatterCache.dateFormatters[dateFormat] = dateFormatter
} else {
dateFormatter = self.defaultDateFormatterFactory()
}
} else {
dateFormatter = self.defaultDateFormatter
dateFormatterCache.dateFormatters[cacheKey] = dateFormatter
}

/// Return formatted date
Expand All @@ -78,6 +86,7 @@ public final class DateFormat: TagRenderer {

private class DateFormatterCache {
static let userInfoKey = "TemplateKit.DateFormatterCache"
static let defaultFormatterPlaceholderKey = "DEFAULT"

var dateFormatters: [String: DateFormatter] = [:]
}

0 comments on commit 0b8991c

Please sign in to comment.