UTC time conversion: How do I convert an integer (UTC) into a 'datetime' time stamp? [duplicate] - swift

My current code:
if let var timeResult = (jsonResult["dt"] as? Double) {
timeResult = NSDate().timeIntervalSince1970
println(timeResult)
println(NSDate())
}
The results:
println(timeResult) = 1415639000.67457
println(NSDate()) = 2014-11-10 17:03:20 +0000 was just to test to see what NSDate was providing.
I want the first to look like the last. The value for dt = 1415637900.
Also, how can I adjust to time zone? Running on iOS.

You can get a date with that value by using the NSDate(withTimeIntervalSince1970:) initializer:
let date = NSDate(timeIntervalSince1970: 1415637900)

To get the date to show as the current time zone I used the following.
if let timeResult = (jsonResult["dt"] as? Double) {
let date = NSDate(timeIntervalSince1970: timeResult)
let dateFormatter = NSDateFormatter()
dateFormatter.timeStyle = NSDateFormatterStyle.MediumStyle //Set time style
dateFormatter.dateStyle = NSDateFormatterStyle.MediumStyle //Set date style
dateFormatter.timeZone = NSTimeZone()
let localDate = dateFormatter.stringFromDate(date)
}
Swift 3.0 Version
if let timeResult = (jsonResult["dt"] as? Double) {
let date = Date(timeIntervalSince1970: timeResult)
let dateFormatter = DateFormatter()
dateFormatter.timeStyle = DateFormatter.Style.medium //Set time style
dateFormatter.dateStyle = DateFormatter.Style.medium //Set date style
dateFormatter.timeZone = self.timeZone
let localDate = dateFormatter.string(from: date)
}
Swift 5
if let timeResult = (jsonResult["dt"] as? Double) {
let date = Date(timeIntervalSince1970: timeResult)
let dateFormatter = DateFormatter()
dateFormatter.timeStyle = DateFormatter.Style.medium //Set time style
dateFormatter.dateStyle = DateFormatter.Style.medium //Set date style
dateFormatter.timeZone = .current
let localDate = dateFormatter.string(from: date)
}

It's simple to convert the Unix timestamp into the desired format. Lets suppose _ts is the Unix timestamp in long
let date = NSDate(timeIntervalSince1970: _ts)
let dayTimePeriodFormatter = NSDateFormatter()
dayTimePeriodFormatter.dateFormat = "MMM dd YYYY hh:mm a"
let dateString = dayTimePeriodFormatter.stringFromDate(date)
print( " _ts value is \(_ts)")
print( " _ts value is \(dateString)")

For managing dates in Swift 3 I ended up with this helper function:
extension Double {
func getDateStringFromUTC() -> String {
let date = Date(timeIntervalSince1970: self)
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US")
dateFormatter.dateStyle = .medium
return dateFormatter.string(from: date)
}
}
This way it easy to use whenever you need it - in my case it was converting a string:
("1481721300" as! Double).getDateStringFromUTC() // "Dec 14, 2016"
Reference the DateFormatter docs for more details on formatting (Note that some of the examples are out of date)
I found this article to be very helpful as well

Here is a working Swift 3 solution from one of my apps.
/**
*
* Convert unix time to human readable time. Return empty string if unixtime
* argument is 0. Note that EMPTY_STRING = ""
*
* #param unixdate the time in unix format, e.g. 1482505225
* #param timezone the user's time zone, e.g. EST, PST
* #return the date and time converted into human readable String format
*
**/
private func getDate(unixdate: Int, timezone: String) -> String {
if unixdate == 0 {return EMPTY_STRING}
let date = NSDate(timeIntervalSince1970: TimeInterval(unixdate))
let dayTimePeriodFormatter = DateFormatter()
dayTimePeriodFormatter.dateFormat = "MMM dd YYYY hh:mm a"
dayTimePeriodFormatter.timeZone = NSTimeZone(name: timezone) as TimeZone!
let dateString = dayTimePeriodFormatter.string(from: date as Date)
return "Updated: \(dateString)"
}

func timeStringFromUnixTime(unixTime: Double) -> String {
let date = NSDate(timeIntervalSince1970: unixTime)
// Returns date formatted as 12 hour time.
dateFormatter.dateFormat = "hh:mm a"
return dateFormatter.stringFromDate(date)
}
func dayStringFromTime(unixTime: Double) -> String {
let date = NSDate(timeIntervalSince1970: unixTime)
dateFormatter.locale = NSLocale(localeIdentifier: NSLocale.currentLocale().localeIdentifier)
dateFormatter.dateFormat = "EEEE"
return dateFormatter.stringFromDate(date)
}

In Swift 5
Using this implementation you just have to give epoch time as a parameter and you will the output as (1 second ago, 2 minutes ago, and so on).
func setTimestamp(epochTime: String) -> String {
let currentDate = Date()
let epochDate = Date(timeIntervalSince1970: TimeInterval(epochTime) as! TimeInterval)
let calendar = Calendar.current
let currentDay = calendar.component(.day, from: currentDate)
let currentHour = calendar.component(.hour, from: currentDate)
let currentMinutes = calendar.component(.minute, from: currentDate)
let currentSeconds = calendar.component(.second, from: currentDate)
let epochDay = calendar.component(.day, from: epochDate)
let epochMonth = calendar.component(.month, from: epochDate)
let epochYear = calendar.component(.year, from: epochDate)
let epochHour = calendar.component(.hour, from: epochDate)
let epochMinutes = calendar.component(.minute, from: epochDate)
let epochSeconds = calendar.component(.second, from: epochDate)
if (currentDay - epochDay < 30) {
if (currentDay == epochDay) {
if (currentHour - epochHour == 0) {
if (currentMinutes - epochMinutes == 0) {
if (currentSeconds - epochSeconds <= 1) {
return String(currentSeconds - epochSeconds) + " second ago"
} else {
return String(currentSeconds - epochSeconds) + " seconds ago"
}
} else if (currentMinutes - epochMinutes <= 1) {
return String(currentMinutes - epochMinutes) + " minute ago"
} else {
return String(currentMinutes - epochMinutes) + " minutes ago"
}
} else if (currentHour - epochHour <= 1) {
return String(currentHour - epochHour) + " hour ago"
} else {
return String(currentHour - epochHour) + " hours ago"
}
} else if (currentDay - epochDay <= 1) {
return String(currentDay - epochDay) + " day ago"
} else {
return String(currentDay - epochDay) + " days ago"
}
} else {
return String(epochDay) + " " + getMonthNameFromInt(month: epochMonth) + " " + String(epochYear)
}
}
func getMonthNameFromInt(month: Int) -> String {
switch month {
case 1:
return "Jan"
case 2:
return "Feb"
case 3:
return "Mar"
case 4:
return "Apr"
case 5:
return "May"
case 6:
return "Jun"
case 7:
return "Jul"
case 8:
return "Aug"
case 9:
return "Sept"
case 10:
return "Oct"
case 11:
return "Nov"
case 12:
return "Dec"
default:
return ""
}
}
How to call?
setTimestamp(epochTime: time) and you'll get the desired output as a string.

Convert timestamp into Date object.
If timestamp object is invalid then return current date.
class func toDate(_ timestamp: Any?) -> Date? {
if let any = timestamp {
if let str = any as? NSString {
return Date(timeIntervalSince1970: str.doubleValue)
} else if let str = any as? NSNumber {
return Date(timeIntervalSince1970: str.doubleValue)
}
}
return nil
}

Swift:
extension Double {
func getDateStringFromUnixTime(dateStyle: DateFormatter.Style, timeStyle: DateFormatter.Style) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = dateStyle
dateFormatter.timeStyle = timeStyle
return dateFormatter.string(from: Date(timeIntervalSince1970: self))
}
}

Anyway #Nate Cook's answer is accepted but I would like to improve it with better date format.
with Swift 2.2, I can get desired formatted date
//TimeStamp
let timeInterval = 1415639000.67457
print("time interval is \(timeInterval)")
//Convert to Date
let date = NSDate(timeIntervalSince1970: timeInterval)
//Date formatting
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd, MMMM yyyy HH:mm:a"
dateFormatter.timeZone = NSTimeZone(name: "UTC")
let dateString = dateFormatter.stringFromDate(date)
print("formatted date is = \(dateString)")
the result is
time interval is 1415639000.67457
formatted date is = 10, November 2014 17:03:PM

If you are maximizing the Codable protocol for parsing your JSON data. You could simply make the data type of dt as Date and do:
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970

For me: Converting timestamps coming from API to a valid date :
`let date = NSDate.init(fromUnixTimestampNumber: timesTamp /* i.e 1547398524000 */) as Date?`

By using this code you will be able to convert timeStamp to Time and Date
let timeStamp = Date().timeIntervalSince1970
let date = NSDate(timeIntervalSince1970: timeStamp)
let dayTimePeriodFormatter = DateFormatter()
dayTimePeriodFormatter.dateFormat = "dd MMMM,YYYY.hh:mm a"
let dateTimeString = dayTimePeriodFormatter.string(from: date as Date)
let dateTime = dateTimeString.split(separator: ".")
print( "Date = \(dateTime[0])")
print( "Time = \(dateTime[1])")
Output:
Date = 19 January,2022
Time = 10:46 AM

Related

DateFormater gives day before swift

when I use DateFormateer it returns me a day before.
nextDayShouldBe = currectDay.addingTimeInterval(24 * 3600)
print(nextDayShouldBe) //prints (2022-07-02 21:58:11 +0000) it's right
let nextDay = nextDayShouldBe?.getFormattedDate(format: format)
try? realm.write({
userData?.nextDay = nextDay
print(nextDayShouldBe?.getFormattedDate(format: format)) // prints "01/07/2022"
})
I tried all methods to fix it (dateformatter.locale, timeZone, calendar).
extension Date {
func getFormattedDate(format: String) -> String {
let dateformat = DateFormatter()
dateformat.dateFormat = format
dateformat.timeZone = TimeZone(secondsFromGMT: 10800)
dateformat.calendar = .current
dateformat.locale = Locale.autoupdatingCurrent
return dateformat.string(from: self)
}
}
How to get 2022-07-02 ??
okey, I did it and it works:
nextDayShouldBe = currectDay.addingTimeInterval(24 * 3600)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
let fromDateToString = dateFormatter.string(from: nextDayShouldBe!)
print(fromDateToString)

Compare current system date with another date(which is coming as string format 2019-11-22) in swift

I'm getting date as a sting format from API (2019-11-22), I want to compare this date with current date.
I tried converting current date as string format this is success but this is not satisfying requiremet. I have to convert to String(2019-11-22) to Date and then I can compare two dates.
How can I convert string (2019-11-22) to Date to compare with system date pls help I'm lead knowledge in dates. Thanks in advance.
extension Date {
static func getCurrentDate() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
return dateFormatter.string(from: Date())
}
}
if Date() < apiEach["ExpiryDate"]! as! Date{
//apiEach["ExpiryDate"]! is 2019-11-22
pritn("You can proceed it's not outdated")
}
apiEach["ExpiryDate"] is a string (apiEach["ExpiryDate"] as! Date will crash) so you have two options:
Convert the current date to string
if Date.getCurrentDate() < apiEach["ExpiryDate"] as! String { ...
Convert the API string to Date and compare that
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd"
if let apiDate = dateFormatter.date(from: apiEach["ExpiryDate"] as! String),
Date() < apiDate { ...
func minimumDate(result:String) -> Bool {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let myDate = dateFormatter.date(from: "\(result)")
dateFormatter.dateFormat = "yyyy-MM-dd"
let now = Date()
let startDateComparisionResult:ComparisonResult = now.compare(myDate!)
if startDateComparisionResult == ComparisonResult.orderedAscending {
print("Current date is smaller than end date.")
let somedateString = dateFormatter.string(from: myDate!)
print(somedateString)
return true
}
else if startDateComparisionResult == ComparisonResult.orderedDescending {
// Current date is greater than end date.
print("Current date is greater than end date.")
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let date1String = dateFormatter.string(from: myDate!)
let date2String = dateFormatter.string(from: now)
if date1String == date2String {
print("Equal date")
return true
}
return false
}
else if startDateComparisionResult == ComparisonResult.orderedSame {
// Current date and end date are same
print("Current date and end date are same")
return true
}
return true
}
Since the date format "yyyy-MM-dd" can be properly sorted/compared you can either convert current date to a string and compare it with your API value
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let now = dateFormatter.string(from: Date())
switch now.compare(input) { //input is from API
case .orderedSame:
print("Same")
case .orderedAscending:
print("Before")
case .orderedDescending:
print("After")
}
If you want to compare dates it is important that Date() will also include the current time while a date converted using a date formatter with a date only format will have its time zeroed out (midnight) so the comparison might not be correct if the date part is the same. To handle this it is better to use DateComponents
let calendar = Calendar.current
guard let date = dateFormatter.date(from: input) else { return //or error }
let components = calendar.dateComponents([.year, .month, .day], from: now, to: date)
if let year = components.year, let month = components.month, let day = components.day {
switch (year + month + day) {
case 0: // all values are zero
print("Same")
case ..<0 : // values will be zero or negative so sum is negative
print("After")
default: // values will be zero or positive so sum is positive
print("Before")
}
}

How to convert date "MM-dd-yyyy hh:mm:ss a" into text format?

I am trying to create a function which will convert date into text format like "Just now, 2mins, 1hour, 1day, oct 10". Here is my sample code where I am getting an error at:
let components = cal.components([.Day,.Hour,.Minute], fromDate: date, toDate: NSDate(), options:[])
Here is my full code:
func getTextToDisplayFormattingDate(date: NSDate) -> String {
var textToDisplay = ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy hh:mm:ss a"
dateFormatter.timeZone = TimeZone(identifier: "UTC")
let cal = NSCalendar.current
let components = cal.components([.Day,.Hour,.Minute], fromDate: date, toDate: NSDate(), options:[])
switch components.day {
case 0:
if components.hour == 0 {
if components.minute <= 0 {
textToDisplay = "just now "
} else {
textToDisplay = "\(components.minute) min"
}
} else {
textToDisplay = "\(components.hours) hrs"
}
case 1...6:
textToDisplay = "\(components.day) d"
default:
dateFormatter.dateFormat = "MMM dd"
textToDisplay = dateFormatter.string(from: date as Date)
}
return textToDisplay
}
Use like this :
Changes in my code :
In place of NSDate, I used Date.
In place of NSCalendar I used Calendar
components(_:from:to:options:) has been renamed to dateComponents(_:from:to:)
components values like day, minute, hour are optional. Thats why i added check before switch.
func getTextToDisplayFormattingDate(date: Date) -> String {
var textToDisplay = ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy hh:mm:ss a"
dateFormatter.timeZone = TimeZone(identifier: "UTC")
let cal = Calendar.current
let components = cal.dateComponents([.day, .hour , .minute], from: date, to: Date())
if let day = components.day, let minute = components.minute, let hour = components.hour {
switch day {
case 0:
if hour == 0 {
if minute <= 0 {
textToDisplay = "just now "
} else {
textToDisplay = "\(minute) min"
}
} else {
textToDisplay = "\(hour) hrs"
}
case 1...6:
textToDisplay = "\(day) d"
default:
dateFormatter.dateFormat = "MMM dd"
textToDisplay = dateFormatter.string(from: date)
}
}
return textToDisplay
}
Actually, it's hard to calculate the days, hours, minutes between 2 dates by NSCalendar.components, your procedure will cause an unexpected result. Usually, we calculate it by the TimeInterval between them. Try this in swift 3.2 or swift 4.0:
func getTextToDisplayFormattingDate(date: Date) -> String {
var textToDisplay = ""
let now = Date()
let timeInterval = now.timeIntervalSince(date)
if timeInterval < 60 {
textToDisplay = "just now "
}
else if timeInterval < 60 * 60 {
textToDisplay = "\(Int(timeInterval / 60)) min"
}
else if timeInterval < 60 * 60 * 24 {
textToDisplay = "\(Int(timeInterval / 60 / 60)) hrs"
}
else {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(identifier: "UTC")
if timeInterval < 60 * 60 * 24 * 6 { //less than 6 days
// For getting days
// textToDisplay = "\(Int(timeInterval / 60 / 60 / 24)) d"
// For getting weekday name
dateFormatter.dateFormat = "EEEE"
textToDisplay = dateFormatter.string(from: date) //weekday name
}
else{
dateFormatter.dateFormat = "MMM dd"
textToDisplay = dateFormatter.string(from: date as Date)
}
}
return textToDisplay
}
And remember use constants to replace expresses like 60 * 60 * 24 to improve performance.

Unix time stamp conversion issue in swift 3

I am trying to convert the timestamp from server and it is converting also but only month is coming wrong.Like timestamp is 1492747393892 and it convert into 21/03/17 - 12:03PM but it should be 21/04/17 - 12:03PM.
Here is my code
var arriveTimestamp: Int
if let timeStampToDate = arriveTimestamp {
let timeSt = Date(jsonTimeDate:"/Date(\(timeStampToDate))/")
let time = Date().dateTime(date: timeSt!)
valueLbl.text = time
}
init?(jsonTimeDate: String) {
// "/Date(1487058855745)/"
let prefix = "/Date("
let suffix = ")/"
let scanner = Scanner(string: jsonTimeDate)
// Check prefix:
guard scanner.scanString(prefix, into: nil) else { return nil }
// Read milliseconds part:
var milliseconds : Int64 = 0
guard scanner.scanInt64(&milliseconds) else { return nil }
// Milliseconds to seconds:
var timeStamp = TimeInterval(milliseconds)/1000.0
// Read optional timezone part:
var timeZoneOffset : Int = 0
if scanner.scanInt(&timeZoneOffset) {
let hours = timeZoneOffset / 100
let minutes = timeZoneOffset % 100
// Adjust timestamp according to timezone:
timeStamp += TimeInterval(3600 * hours + 60 * minutes)
}
// Check suffix:
guard scanner.scanString(suffix, into: nil) else { return nil }
// Success! Create NSDate and return.
self.init(timeIntervalSince1970: timeStamp)
}
func dateTime(date: Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/mm/yy - hh:mm a"
return dateFormatter.string(from: date as Date)
}
The main error in your code is the wrong date format for the month,
which should be "MM", not "mm" (which is for the minutes).
Apart from that, your approach is far too complicated. All you have to
do is to divide the timestamp (which is in milliseconds) by 1000
and call Date(timeIntervalSince1970:):
let arriveTimestamp = 1492747393892
let date = Date(timeIntervalSince1970: TimeInterval(arriveTimestamp)/1000)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yy - hh:mm a"
let text = dateFormatter.string(from: date)
print(text) // 21/04/17 - 06:03 AM

How to configure DateFormatter to capture microseconds

iOS Date() returns date with at least microsecond precision.
I checked this statement by calling Date().timeIntervalSince1970 which results in 1490891661.074981
Then I need to convert date into string with microsecond precision.
I am using DateFormatter in following way:
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZZZZZ"
print(formatter.string(from: date))
which results in
"2017-03-30T16:34:21.075000Z"
Now if we compare two results:
1490891661.074981 and "2017-03-30T16:34:21.075000Z"
we can notice that DateFormatter rounds date to millisecond precision while still presenting zeros for microseconds.
Does anybody know how to configure DateFormatter so I can keep microseconds and get correct result: "2017-03-30T16:34:21.074981Z"?
Thanks to #MartinR for solving first half of my problem and to #ForestKunecke for giving me tips how to solve second half of the problem.
Based on their help I created ready to use solution which converts date from string and vice versa with microsecond precision:
public final class MicrosecondPrecisionDateFormatter: DateFormatter {
private let microsecondsPrefix = "."
override public init() {
super.init()
locale = Locale(identifier: "en_US_POSIX")
timeZone = TimeZone(secondsFromGMT: 0)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func string(from date: Date) -> String {
dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let components = calendar.dateComponents(Set([Calendar.Component.nanosecond]), from: date)
let nanosecondsInMicrosecond = Double(1000)
let microseconds = lrint(Double(components.nanosecond!) / nanosecondsInMicrosecond)
// Subtract nanoseconds from date to ensure string(from: Date) doesn't attempt faulty rounding.
let updatedDate = calendar.date(byAdding: .nanosecond, value: -(components.nanosecond!), to: date)!
let dateTimeString = super.string(from: updatedDate)
let string = String(format: "%#.%06ldZ",
dateTimeString,
microseconds)
return string
}
override public func date(from string: String) -> Date? {
dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
guard let microsecondsPrefixRange = string.range(of: microsecondsPrefix) else { return nil }
let microsecondsWithTimeZoneString = String(string.suffix(from: microsecondsPrefixRange.upperBound))
let nonDigitsCharacterSet = CharacterSet.decimalDigits.inverted
guard let timeZoneRangePrefixRange = microsecondsWithTimeZoneString.rangeOfCharacter(from: nonDigitsCharacterSet) else { return nil }
let microsecondsString = String(microsecondsWithTimeZoneString.prefix(upTo: timeZoneRangePrefixRange.lowerBound))
guard let microsecondsCount = Double(microsecondsString) else { return nil }
let dateStringExludingMicroseconds = string
.replacingOccurrences(of: microsecondsString, with: "")
.replacingOccurrences(of: microsecondsPrefix, with: "")
guard let date = super.date(from: dateStringExludingMicroseconds) else { return nil }
let microsecondsInSecond = Double(1000000)
let dateWithMicroseconds = date + microsecondsCount / microsecondsInSecond
return dateWithMicroseconds
}
}
Usage:
let formatter = MicrosecondPrecisionDateFormatter()
let date = Date(timeIntervalSince1970: 1490891661.074981)
let formattedString = formatter.string(from: date) // 2017-03-30T16:34:21.074981Z
The resolution of (NS)DateFormatter is limited to milliseconds, compare
NSDateFormatter milliseconds bug. A possible solution is to retrieve all date components (up to
nanoseconds) as numbers and do a custom string formatting. The date formatter can still be used for the timezone string.
Example:
let date = Date(timeIntervalSince1970: 1490891661.074981)
let formatter = DateFormatter()
formatter.dateFormat = "ZZZZZ"
let tzString = formatter.string(from: date)
let cal = Calendar.current
let comps = cal.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond],
from: date)
let microSeconds = lrint(Double(comps.nanosecond!)/1000) // Divide by 1000 and round
let formatted = String(format: "%04ld-%02ld-%02ldT%02ld:%02ld:%02ld.%06ld",
comps.year!, comps.month!, comps.day!,
comps.hour!, comps.minute!, comps.second!,
microSeconds) + tzString
print(formatted) // 2017-03-30T18:34:21.074981+02:00
Solution by #Vlad Papko has some issue:
For dates like following:
2019-02-01T00:01:54.3684Z
it can make string with extra zero:
2019-02-01T00:01:54.03684Z
Here is fixed solution, it's ugly, but works without issues:
override public func string(from date: Date) -> String {
dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let components = calendar.dateComponents(Set([Calendar.Component.nanosecond]), from: date)
let nanosecondsInMicrosecond = Double(1000)
let microseconds = lrint(Double(components.nanosecond!) / nanosecondsInMicrosecond)
// Subtract nanoseconds from date to ensure string(from: Date) doesn't attempt faulty rounding.
let updatedDate = calendar.date(byAdding: .nanosecond, value: -(components.nanosecond!), to: date)!
let dateTimeString = super.string(from: updatedDate)
let stingWithMicroseconds = "\(date.timeIntervalSinceReferenceDate)"
let dotIndex = stingWithMicroseconds.lastIndex(of: ".")!
let hasZero = stingWithMicroseconds[stingWithMicroseconds.index(after: dotIndex)] == "0"
let format = hasZero ? "%#.%06ldZ" : "%#.%6ldZ"
let string = String(format: format,
dateTimeString,
microseconds)
return string
}
It is a bit of a hack, but not that complex and 100% Swift:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.'MICROS'xx"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
// Get the number of microseconds with a precision of 6 digits
let now = Date()
let dateParts = Calendar.current.dateComponents([.nanosecond], from: now)
let microSeconds = Int((Double(dateParts.nanosecond!) / 1000).rounded(.toNearestOrEven))
let microSecPart = String(microSeconds).padding(toLength: 6, withPad: "0", startingAt: 0)
// Format the date and add in the microseconds
var timestamp = dateFormatter.string(from: now)
timestamp = timestamp.replacingOccurrences(of: "MICROS", with: microSecPart)