According to the specs, a date in an ID3 tag is supposed to be in ISO-8601 format, so I changed the calendar to that, and added the hour/minute ints, because with the exception of the v2.2/2.3 time/date frames, they're supposed to be in there.
I also created these formatters for DateFormatter, though I haven't found any use for them yet. Again, this is going off what the spec calls for.
extension DateFormatter {
// This is the format used in the ID3 "Date" frame
static let id3DayMonth: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
// This is the format used in the ID3 "Time" frame
static let id3HourMinute: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "HH-mm"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
// This is the format used in the ID3 "Year" frame
static let id3Year: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
// this is the format used in all other ID3 date-related frames
static let id3TimeStamp: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
My properties for the DateFrame are where I'm probably making things more complicated than they need to be. My initial thinking was that if I can parse whatever is coming in from a frame as a string into a timestamp, I can then use that to initialize all the individual components:
var year: Int?
var month: Int?
var day: Int?
var hour: Int?
var minute: Int?
var timeStamp: Date
var timeStampString: String?
Where things start breaking down is in the parsing, which I don't think I've implemented properly:
// assuming the timestamp is in ISO-8601 format as per the ID3 spec
self.timeStampString = parsing.extractPrefixAsStringUntilNullTermination(encoding) ?? ""
let formatter = DateFormatter()
let formattedTimeStamp = formatter.date(from: timeStampString ?? "")?.id3TimeStamp ?? (year: 0000, month: 00, day: 00, hour: 00, minute: 00)
self.timeStamp = Date(id3TimeStamp: formattedTimeStamp) ?? Date()
self.year = timeStamp.id3TimeStamp.year
self.month = timeStamp.id3TimeStamp.month
self.day = timeStamp.id3TimeStamp.day
self.hour = timeStamp.id3TimeStamp.hour
self.minute = timeStamp.id3TimeStamp.minute
And then the individual getter/setter properties can use whichever variables they need for a particular frame:
/// - (Release) Date frame getter-setter. Valid for versions 2.2 and 2.3 only.
/// ID3 Identifier: `TDA`/`TDAT`
public var date: (day: Int?, month: Int?)? {
get {
if let frame = self.frames[.date],
case .dateFrame(let dateFrame) = frame {
return (dateFrame.day, dateFrame.month)
} else {
return nil
}
}
set {
let date = Date(id3TimeStamp: (year: nil, month: newValue?.month, day: newValue?.day, hour: nil, minute: nil)) ?? Date()
let frame = DateFrame(.known(.date), timeStamp: date)
frames[.date] = .dateFrame(frame)
}
}
But yeah, like I said, I don't think I'm implementing it properly.
Okay, I could use some guidance on this, because I feel like I'm overthinking it or making it more complicated than it needs to be.
I'm starting off with a variation on the
Date
extension you created forAudiobookTagger
:According to the specs, a date in an ID3 tag is supposed to be in ISO-8601 format, so I changed the calendar to that, and added the hour/minute ints, because with the exception of the v2.2/2.3 time/date frames, they're supposed to be in there.
I also created these formatters for
DateFormatter
, though I haven't found any use for them yet. Again, this is going off what the spec calls for.My properties for the
DateFrame
are where I'm probably making things more complicated than they need to be. My initial thinking was that if I can parse whatever is coming in from a frame as a string into a timestamp, I can then use that to initialize all the individual components:Where things start breaking down is in the parsing, which I don't think I've implemented properly:
And then the individual getter/setter properties can use whichever variables they need for a particular frame:
But yeah, like I said, I don't think I'm implementing it properly.