I have a date/time returning from an API that is formatted in RFC 3339. RFC3399 looks like the following: "2021-07-24T22:36:39-04:00"
To be even more clear, it can be generated directly in swift doing something like the following:
let RFC3339DateFormatter = DateFormatter()
RFC3339DateFormatter.locale = Locale(identifier: "en_US_POSIX")
RFC3339DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
RFC3339DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
/* 39 minutes and 57 seconds after the 16th hour of December 19th, 1996 with an offset of -08:00 from UTC (Pacific Standard Time) */
let string = "1996-12-19T16:39:57-08:00"
let date = RFC3339DateFormatter.date(from: string)
My question is, how can I find the difference between times stored in RFC 3339 format in String variables.
For example, I have one variable titled currentTime that returns the current date/time in RFC 3339 format, and I have data from my API that returns a future time in RFC 3339 format. How can I subtract the time returned in each of these to determine the difference between the two?
Also, the date returned is not a concern to me. Only need to find the difference in time.
once you have your dates from the strings, you coud do something like this using component:
EDIT, using Alexander suggestion:
struct ContentView: View {
#State var timediff = ""
var body: some View {
Text(timediff)
.onAppear {
let RFC3339DateFormatter = DateFormatter()
RFC3339DateFormatter.locale = Locale(identifier: "en_US_POSIX")
RFC3339DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
RFC3339DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
let string1 = "1996-12-19T16:39:57-08:00"
let date1 = RFC3339DateFormatter.date(from: string1)
let string2 = "1996-12-19T13:19:27-08:00"
let date2 = RFC3339DateFormatter.date(from: string2)
if let d1 = date1, let d2 = date2 {
let result = Calendar.current.dateComponents([.hour, .minute], from: d1, to: d2)
timediff = result.description
}
}
}
Related
I would like to format my dates to not have zeros in the beginning.
For example
04/03/20 -> swift should display as 4/3/20
I basically want to remove the zero that may be in front of the day, month, or year. The purpose of this is not for style purposes but for me to access data in a JSON. That's why it needs to be soo specific.
You can get by using Date & DateFormatter
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yy" // change formate as per your requirement
let date = formatter.date(from: "04/03/20") //change "04/03/20" to your input string
formatter.dateFormat = "d/M/yy"
let dateString = formatter.string(from: date!)
print(dateString) // 4/3/20
let date = "04/03/20"
let parts = date.split(separator: "/")
var newDate = ""
for i in 0..<parts.count {
newDate = "\(newDate)\(i == 0 ? "" :"/")\(Int(parts[i])!)"
}
print(newDate) //Result - 4/3/20
I am removing the current time from the current time and trying to find the minute difference. But it says 10/09/2019 13:13 and there is an error in the extraction process (I want to print as 1313) .1313 I can perform the extraction process. How do I print this data the way I want? I want to print dateFormat = "HHmm". In timertext2New.text, dateFormat = "dd / MM / yyyy HH: mm" like this. But I want to save it in HHmm format.
save12 output: 05/09/2019 10:48 but I want it to be "1048" . To perform extraction.
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy HH:mm"
timertext2New.text = formatter.string(from: datePicker.date)
let timehafıza2 = String(self.timertext2New.text!)
let df2 = DateFormatter()
df2.dateFormat = "HHmm"
var str2 = df2.string(from: Date())
str2 = timehafıza2
UserDefaults.standard.setValue(str2, forKey: "timertext2")
override func viewDidLoad() {
super.viewDidLoad()
let date = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HHmm"
let hour = dateFormatter.string(from: date)
var save12 = UserDefaults.standard.integer(forKey: "timertext2")
var fark : Int = (Int(hour)! - Int(save12))
}
Your code is pretty confusing and cannot work
You convert a date from a date picker with format "dd/MM/yyyy HH:mm"
Then you create a string with format "HHmm" from the current date which will be destroyed immediately because
You overwrite this string with the dd/MM/yyyy HH:mm string and save it to UserDefaults
Later you read the value from UserDefaults as integer which returns 0 because the "dd/MM/yyyy HH:mm" format is not representable by an integer.
My suggestion is to save all dates as Date and perform the date math with the dedicated methods of Calendar
I'm trying to get the correct time interval between two times that span two days (Overnight). Here is my code successfully printing out the difference between two times - however for my use case I need the ability to span overnight, how might I do this?
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
//This time represents (23:00, Aug 07) for example
let date1 = dateFormatter.date(from: "23:00")!
//This time represents (06:00, Aug 08) for example
let date2 = dateFormatter.date(from: "06:00")!
let elapsedTime = date2.timeIntervalSince(date1)
print(abs(elapsedTime)/60/60)
//prints 17.0
My desired result is a print out of 7, as that is the amount of hours between 23:00, Aug 7 and 06:00, Aug 8 - My current code is correctly showing me the interval between those two times (as if they were from the same day) but I am trying to work out how to account for when those times overlap two days. Any help would be much appreciated.
UPDATE:
To give a more complete picture I have an object that has a start and and end date represented by a string:
Activity(startTime: "23:00", endTime: "06:00")
I use some functions to turn those strings into dates:
func startDate(startTime: String) -> Date {
let currentDate = Date().string(format: "dd-MM-yyyy")
let myStartingDate = "\(currentDate) \(startTime)"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
let startDate = dateFormatter.date(from: myStartingDate)
return startDate!
}
func endDate(endTime: String) -> Date {
let currentDate = Date().string(format: "dd-MM-yyyy")
let myEndingDate = "\(currentDate) \(endTime)"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
let endDate = dateFormatter.date(from: myEndingDate)
return endDate!
}
So my more complete workings look more like this:
func calculateTimeInterval(activity: Activity) {
let startHourDate = self.startDate(startTime: activity.startTime)
let endHourDate = self.endDate(endTime: activity.endTime)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
//This time represents (23:00, Aug 07) for example
let date1 = startHourDate!
//This time represents (06:00, Aug 08) for example
let date2 = endHourDate!
let elapsedTime = date2.timeIntervalSince(date1)
print(abs(elapsedTime)/60/60)
}
//prints 17.0
Without a date part the only way to determine if the end time is past midnight is if the end time is less than the start time. If so your code can be changed to
var elapsedTime = date2.timeIntervalSince(date1)
if elapsedTime < 0 {
let date3 = date2 + 60 * 60 * 24
elapsedTime = date3.timeIntervalSince(date1)
}
print(elapsedTime/60/60)
You can write an Extension to Date like this:
extension Date {
func hours(from date: Date) -> Int {
return Calendar.current.dateComponents([.hour], from: date).hour ?? 0
}
}
And just use it on any Date directly. This way you don't need DateFormatter at all. Hope this helps!
Using the following overly complex code a date can almost be extracted from a string:
let dateStringArray:[String] = ["29-01-2017 10:41:18:825325012","29-01-2017 10:41:18:894631028"]
let formatString = "dd-MM-yyyy HH:mm:ss:nnnnnnnnn"
let dayRange = formatString.range(of: "dd")
let monthRange = formatString.range(of: "MM")
let yearRange = formatString.range(of: "yyyy")
let hourRange = formatString.range(of: "HH")
let minuteRange = formatString.range(of: "mm")
let secondRange = formatString.range(of: "ss")
let nanoRange = formatString.range(of:"nnnnnnnnn")
let dateString = dateStringArray[0]
let dateComponents = DateComponents( year:Int(dateString.substring(with: yearRange!)),
month:Int(dateString.substring(with: monthRange!)),
day:Int(dateString.substring(with: dayRange!)),
hour:Int(dateString.substring(with: hourRange!)),
minute:Int(dateString.substring(with: minuteRange!)),
second:Int(dateString.substring(with: secondRange!)),
nanosecond:Int(dateString.substring(with: nanoRange!)))
let nano = Int(dateString.substring(with: nanoRange!))
let currentCalendar = Calendar.current
let dateExtracted = currentCalendar.date(from: dateComponents)
print("\(dateExtracted!)")
The output from the final print is: "2017-01-29 10:41:18 +0000\n"
There are issues with this (1) there must be an easier way. (2) & more important, why is the nanosecond component apparently not appearing?
(1) there must be an easier way
Use a date formatter:
let dateString = "29-01-2017 10:41:18:825325012"
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm:ss:SSSSSSSS"
let dateExtracted = dateFormatter.date(from: dateString)!
(2) why is the nanosecond component apparently not appearing?
The description method of Date does not show fractional seconds, but
you can extract it again with
currentCalendar.component(.nanosecond, from: dateExtracted!)
The result may be slightly different from the original nanosecond value
in the string due to rounding errors, because Date stores internally
a floating point number (number of seconds since the reference date
Jan 1, 2001). If you use a date formatter as suggested above then
the resolution is limited to milliseconds (compare NSDateFormatter milliseconds bug).
I am trying to convert fajerTime to NSDate. When I compile the project the dateValue is nil. Any idea how to fix this issue?
if prayerCommingFromAdan.id == 0 && prayerCommingFromAdan.ringToneId != 0{
// NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"NotificationIdentifier", object: nil)
let fajerTime = "\(prayer0.time[0...1]):\(prayer0.time[3...4])" as String
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
dateFormatter.timeZone = NSTimeZone.localTimeZone()
// convert string into date
let dateValue = dateFormatter.dateFromString(fajerTime) as NSDate!
print(dateValue)
var dateComparisionResult:NSComparisonResult = NSDate().compare(dateValue)
if dateComparisionResult == NSComparisonResult.OrderedDescending {
addNotificationAlarm(year, month: month, day: day, hour: prayer0.time[0...1], minutes: prayer0.time[3...4], soundId: prayerCommingFromAdan.ringToneId, notificationBody: "It is al fajr adan")
}
The problem seems be the format of fajerTime. It looks like fajerTime is a time string, e.g. 12:34, whereas the date formatter is configured to accept string containing a month, day and year, e.g. 24-07-2016.
You need to format fajerTime to include the year, month and day, as well as the time. Also configure the date formatter to accept the full date and time.
Assuming prayer0 is an array, you will also need to combine the elements into a string, using joinWithSeparator.
e.g.
let hours = prayer0.time[0...1].joinWithSeparator("")
let minutes = prayer0.time[3...4].joinWithSeparator("")
let fajerTime = "\(month)-\(day)-\(year) \(hours):\(minutes)"
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy hh:mm"
dateFormatter.timeZone = NSTimeZone.localTimeZone()
// convert string into date
let dateValue = dateFormatter.dateFromString(fajerTime) as NSDate!
Please follow example (Swift 3):
let dateStr = "2016-01-15 20:10:01 +0000"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let myDate = dateFormatter.date(from: dateStr)
Keep in mind:
Date format e.g. "yyyy-MM-dd HH:mm:ss Z" must match the date string pattern
In your case, your date string contains only time, yet, your date
formatter contains only date
When using dateFormatter.date() there is no need to cast it to Date as it returns a Date:
Helpful website for date formats:
http://nsdateformatter.com/