How to parse a ISO 8601 duration format in Swift?
You can also just search the indexes of your hours, minutes and seconds and use DateComponentsFormatter positional style to format your video duration:
Create a static positional date components formatter:
extension Formatter {
static let positional: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
return formatter
}()
}
And your format duration method:
func formatVideo(duration: String) -> String {
var duration = duration
if duration.hasPrefix("PT") { duration.removeFirst(2) }
let hour, minute, second: Double
if let index = duration.firstIndex(of: "H") {
hour = Double(duration[..<index]) ?? 0
duration.removeSubrange(...index)
} else { hour = 0 }
if let index = duration.firstIndex(of: "M") {
minute = Double(duration[..<index]) ?? 0
duration.removeSubrange(...index)
} else { minute = 0 }
if let index = duration.firstIndex(of: "S") {
second = Double(duration[..<index]) ?? 0
} else { second = 0 }
return Formatter.positional.string(from: hour * 3600 + minute * 60 + second) ?? "0:00"
}
let duration = "PT1H3M20S"
formatVideo(duration: duration) // "1:03:20"
How to parse an ISO-8601 duration in Objective C?
If you know exactly which fields you'll be getting, you can use one invocation of sscanf()
:
const char *stringToParse = ...;
int days, hours, minutes, seconds;
NSTimeInterval interval;
if(sscanf(stringToParse, "P%dDT%dH%dM%sS", &days, &hours, &minutes, &seconds) == 4)
interval = ((days * 24 + hours) * 60 + minutes) * 60 + seconds;
else
; // handle error, parsing failed
If any of the fields might be omitted, you'll need to be a little smarter in your parsing, e.g.:
const char *stringToParse = ...;
int days = 0, hours = 0, minutes = 0, seconds = 0;
const char *ptr = stringToParse;
while(*ptr)
{
if(*ptr == 'P' || *ptr == 'T')
{
ptr++;
continue;
}
int value, charsRead;
char type;
if(sscanf(ptr, "%d%c%n", &value, &type, &charsRead) != 2)
; // handle parse error
if(type == 'D')
days = value;
else if(type == 'H')
hours = value;
else if(type == 'M')
minutes = value;
else if(type == 'S')
seconds = value;
else
; // handle invalid type
ptr += charsRead;
}
NSTimeInterval interval = ((days * 24 + hours) * 60 + minutes) * 60 + seconds;
Parsing a ISO8601 String to Date in Swift
Your date format is incorrect, you need to take into account the milliseconds.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let updatedAtStr = "2016-06-05T16:56:57.019+01:00"
let updatedAt = dateFormatter.date(from: updatedAtStr) // "Jun 5, 2016, 4:56 PM"
Just to clarify, the addition of .SSS
in the date format is what fixes the problem.
How do you back up your development machine?
There's an important distinction between backing up your development machine and backing up your work.
For a development machine your best bet is an imaging solution that offers as near a "one-click-restore" process as possible. TimeMachine (Mac) and Windows Home Server (Windows) are both excellent for this purpose. Not only can you have your entire machine restored in 1-2 hours (depending on HDD size), but both run automatically and store deltas so you can have months of backups in relatively little space. There are also numerous "ghosting" packages, though they usually do not offer incremental/delta backups so take more time/space to backup your machine.
Less good are products such as Carbonite/Mozy/JungleDisk/RSync. These products WILL allow you to retrieve your data, but you will still have to reinstall the OS and programs. Some have limited/no histories either.
In terms of backing up your code and data then I would recommend a sourcecode control product like SVN. While a general backup solution will protect your data, it does not offer the labeling/branching/history functionality that SCC packages do. These functions are invaluable for any type of project with a shelf-life.
You can easily run a SVN server on your local machine. If your machine is backed up then your SVN database will be also. This IMO is the best solution for a home developer and is how I keep things.
How can I parse / create a date time stamp formatted with fractional seconds UTC timezone (ISO 8601, RFC 3339) in Swift?
Swift 4 • iOS 11.2.1 or later
extension ISO8601DateFormatter {
convenience init(_ formatOptions: Options) {
self.init()
self.formatOptions = formatOptions
}
}
extension Formatter {
static let iso8601withFractionalSeconds = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
}
extension Date {
var iso8601withFractionalSeconds: String { return Formatter.iso8601withFractionalSeconds.string(from: self) }
}
extension String {
var iso8601withFractionalSeconds: Date? { return Formatter.iso8601withFractionalSeconds.date(from: self) }
}
Usage:
Date().description(with: .current) // Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
let dateString = Date().iso8601withFractionalSeconds // "2019-02-06T00:35:01.746Z"
if let date = dateString.iso8601withFractionalSeconds {
date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"
print(date.iso8601withFractionalSeconds) // "2019-02-06T00:35:01.746Z\n"
}
iOS 9 • Swift 3 or later
extension Formatter {
static let iso8601withFractionalSeconds: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return formatter
}()
}
Codable Protocol
If you need to encode and decode this format when working with Codable
protocol you can create your own custom date encoding/decoding strategies:
extension JSONDecoder.DateDecodingStrategy {
static let iso8601withFractionalSeconds = custom {
let container = try $0.singleValueContainer()
let string = try container.decode(String.self)
guard let date = Formatter.iso8601withFractionalSeconds.date(from: string) else {
throw DecodingError.dataCorruptedError(in: container,
debugDescription: "Invalid date: " + string)
}
return date
}
}
and the encoding strategy
extension JSONEncoder.DateEncodingStrategy {
static let iso8601withFractionalSeconds = custom {
var container = $1.singleValueContainer()
try container.encode(Formatter.iso8601withFractionalSeconds.string(from: $0))
}
}
Playground Testing
let dates = [Date()] // ["Feb 8, 2019 at 9:48 PM"]
encoding
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
let data = try! encoder.encode(dates)
print(String(data: data, encoding: .utf8)!)
decoding
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 8, 2019 at 9:48 PM"]
Swift ISO8601 format to Date
You can specify ISO8601 date formate to the NSDateFormatter to get Date:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd'T'HHmmssZ"
print(dateFormatter.date(from: dateString)) //2018-02-07 12:46:00 +0000
Related Topics
How to Indicate a View Which Has Created with Uikit from a Skscene
Facebook Sdk Login Throws Error in Swift 2 iOS 9
Swift3 Random Extension Method
Animating Button Allowuserinteraction Not Working
How to Remove Single Object in Array from Multiple Matching Object
Adding Firebase Data to an Array in iOS Swift
Avplayerlayer Shows Black Screen But Sound Is Working
How to Catch Accessibility Focus Changed
How to Authorize Twitter with Swifter
How to Set the Local Storage Before a Uiwebview Loading Its Initial Request
Swift Unable to Use API Data in Collection View
Swift Calling Setnavigationbarhidden But View Wont Move to Top