@@ -8,6 +8,7 @@ public enum TokenLogParser {
88 var model = " Unknown "
99 var previousTotal : TokenUsage ?
1010 let sessionId = sessionIdFromFileName ( url. lastPathComponent)
11+ let dateParser = DateParser ( )
1112
1213 try forEachJSONLine ( in: url, isCancelled: isCancelled) { index, object in
1314 guard let payload = object [ " payload " ] as? [ String : Any ] else { return }
@@ -19,8 +20,8 @@ public enum TokenLogParser {
1920 model = payloadModel
2021 }
2122
22- let timestamp = parseDate ( object [ " timestamp " ] as? String )
23- ?? parseDate ( payload [ " timestamp " ] as? String )
23+ let timestamp = dateParser . parse ( object [ " timestamp " ] as? String )
24+ ?? dateParser . parse ( payload [ " timestamp " ] as? String )
2425 ?? Date ( timeIntervalSince1970: 0 )
2526
2627 let totalDict = nestedDict ( payload, [ " info " , " total_token_usage " ] )
@@ -64,6 +65,7 @@ public enum TokenLogParser {
6465 public static func parseClaudeFile( at url: URL , isCancelled: ( ) -> Bool = { false } ) throws -> [ TokenEvent ] {
6566 var events : [ TokenEvent ] = [ ]
6667 var seenRequests = Set < String > ( )
68+ let dateParser = DateParser ( )
6769
6870 try forEachJSONLine ( in: url, isCancelled: isCancelled) { index, object in
6971 guard let message = object [ " message " ] as? [ String : Any ] ,
@@ -75,7 +77,7 @@ public enum TokenLogParser {
7577 if seenRequests. contains ( dedupeKey) { return }
7678 seenRequests. insert ( dedupeKey)
7779
78- let timestamp = parseDate ( object [ " timestamp " ] as? String ) ?? Date ( timeIntervalSince1970: 0 )
80+ let timestamp = dateParser . parse ( object [ " timestamp " ] as? String ) ?? Date ( timeIntervalSince1970: 0 )
7981 let model = ( message [ " model " ] as? String ) ?? " Unknown "
8082 let projectPath = ( object [ " cwd " ] as? String ) ?? " Unknown "
8183 let sessionId = ( object [ " sessionId " ] as? String ) ?? sessionIdFromFileName ( url. lastPathComponent)
@@ -187,15 +189,21 @@ public enum TokenLogParser {
187189 return 0
188190 }
189191
190- private static func parseDate( _ string: String ? ) -> Date ? {
191- guard let string else { return nil }
192- let formatter = ISO8601DateFormatter ( )
193- formatter. formatOptions = [ . withInternetDateTime, . withFractionalSeconds]
194- if let date = formatter. date ( from: string) {
195- return date
192+ private final class DateParser {
193+ private let fractionalFormatter : ISO8601DateFormatter
194+ private let plainFormatter : ISO8601DateFormatter
195+
196+ init ( ) {
197+ fractionalFormatter = ISO8601DateFormatter ( )
198+ fractionalFormatter. formatOptions = [ . withInternetDateTime, . withFractionalSeconds]
199+ plainFormatter = ISO8601DateFormatter ( )
200+ plainFormatter. formatOptions = [ . withInternetDateTime]
201+ }
202+
203+ func parse( _ string: String ? ) -> Date ? {
204+ guard let string else { return nil }
205+ return fractionalFormatter. date ( from: string) ?? plainFormatter. date ( from: string)
196206 }
197- formatter. formatOptions = [ . withInternetDateTime]
198- return formatter. date ( from: string)
199207 }
200208
201209 private static func sessionIdFromFileName( _ fileName: String ) -> String {
0 commit comments