I have 2 times that create a time range that a map annotation is visible(a start time and an end time). Whenever the current time is greater than the end time, the annotation is removed. The user inputs the times as a string then I add that time string to the current date string, then I convert the date as "h:mm a, M/dd/yyyy" into an actual date. The problem I am having is that if someone says the event starts at night (PM) then ends in the early morning or something (AM) then the event annotation is instantly removed because it creates the end time as AM time of the day that is about to end instead of the new day. Here is my current method for getting the time strings in code:
let SpotStartTime = StartTimeTextField.text;
let SpotEndTime = EndTimeTextField.text;
let date = NSDate();
let formatter = NSDateFormatter();
formatter.dateFormat = "M/dd/yyyy";
let Date = formatter.stringFromDate(date)
let EndTime = SpotEndTime;
let RealEndTime = (EndTime! + ", " + Date);
print(RealEndTime);
then I convert this string into a date using this method:
let TimeStr = EndTime
let dateFormater : NSDateFormatter = NSDateFormatter()
dateFormater.dateFormat = "h:mm a, M/dd/yyyy
let EndDate = (dateFormater.dateFromString(TimeStr))
let realEnd = EndDate
How do I modify this so that I can compare the StartTimeTextField to the EndTimeTextField? I need something that basically compares the two and if the StartTimeTextField has "PM" in it and the EndTimeTextField has "AM" in it then the EndTime gets 24 hours added to it, but I don't know how to do this in code.
Can anyone help? Thanks
I hope that I understood what you want to do, I come up with this function:
func getTime(startTime:String, startM:String, endTiem: String, endM:String) {
let date = NSDate();
let formatter = NSDateFormatter();
formatter.dateFormat = "M/dd/yyyy";
let dateStrStart = formatter.stringFromDate(date)
var dateStrEnd = ""
if (startM == "PM" && endM == "AM") {
let dateEnd = NSDate(timeInterval: 86400, sinceDate: date)
let formatter = NSDateFormatter();
formatter.dateFormat = "M/dd/yyyy";
dateStrEnd = formatter.stringFromDate(dateEnd)
} else {
dateStrEnd = dateStrStart
}
let RealEndTime = (endTiem + ", " + dateStrEnd);
let RealStartTime = (startTime + ", " + dateStrStart);
}
you just have to grab the AM or PM part.
And if the startTime is PM and the endTime is AM then your dateEnd is the currentDate plus one day.
Related
I have a list of date strings in which I want to sort the list closest to the given time. If two times are clashing then earlier date priority would be considered.
var givenTIme = "10:00AM"
var strDates = ["2021-04-30 10:00AM", "2021-04-16 10:00AM", "2021-04-26 12:00AM", "2021-04-28 09:00AM"]
var output = ["2021-04-16 10:00AM", "2021-04-30 10:00AM", "2021-04-28 09:00AM", "2021-04-26 12:00AM"]
in here we have to find sort the array dates close 10:00AM
If anybody knows the solution please help me out.
Not 100% sure what you need but something like this could be a start?
The strategy is to transform the data into things that can be easily compared to give the sort order that we want.
Working with dates and times is always tricky because of calendars and locale issues.
var givenTIme = "10:00AM"
var calendar = Calendar.current
let strDates = ["2021-04-30 10:00AM", "2021-04-16 10:00AM", "2021-04-26 12:00AM", "2021-04-28 09:00AM"]
let formatter = DateFormatter()
formatter.dateFormat = "y-M-d hh:mma"// hh:mma"
let dates = strDates.compactMap(formatter.date(from:))
struct CompareHelper {
let date: Date
let deltaT: Int
}
let hhmmformatter = DateFormatter()
hhmmformatter.dateFormat = "hh:mma"
let target = hhmmformatter.date(from: givenTIme)!
let dts = dates.map { date -> CompareHelper in
let minute = calendar.component(.minute, from: date)
let hour = calendar.component(.hour, from: date)
let targetMinute = calendar.component(.minute, from: target)
let targetHour = calendar.component(.hour, from: target)
let deltaT = (targetMinute + targetHour * 60) - (minute + hour * 60)
return CompareHelper(date: date, deltaT: deltaT)
}
let sorted = dts.sorted { (lhs: CompareHelper, rhs:CompareHelper) -> Bool in
if lhs.deltaT == rhs.deltaT {
return lhs.date < rhs.date
}
else {
return lhs.deltaT < rhs.deltaT
}
}
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'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!
What would be a clean way to initialise a Swift TimeZone object from timeZoneOffset string of the form: "+HH:MM".
I am looking for something of the form:
extension TimeZone {
init?(UTCOffsetString ofs: String) {
let signIndex = ofs.firstIndex(of: "+") ?? ofs.firstIndex(of: "-")
let sign = ofs[signIndex!]
let separatorIndex = ofs.firstIndex(of: ":")!
let hhRange = ofs.index(signIndex!, offsetBy: 1)..<separatorIndex
let hh = ofs[hhRange]
let mmRange = ofs.index(separatorIndex, offsetBy: 1)..<ofs.index(separatorIndex, offsetBy: 3)
let mm = ofs[mmRange]
var offsetInMin = (Int(String(hh))! * 60) + Int(String(mm))!
if sign == "-" {
offsetInMin.negate()
}
let offsetInSec = offsetInMin * 60
// Convert string to TimeZone, eg.
self.init(secondsFromGMT: offsetInSec)
}
}
let tz = TimeZone.init(UTCOffsetString: "-07:30")
print(tz?.identifier ?? "unknown")
The above code block is a correct solution and prints:
GMT-0730
However I am looking for a cleaner solution where I don't need to extract substrings in order to compute the offset.
My suggestion is to use DateFormatter which is able to parse the time zone string format. refZoneString is the reference to UTC in the current time zone.
extension TimeZone {
init?(UTCOffsetString ofs: String) {
let refZoneString = "+0000"
let formatter = DateFormatter()
formatter.dateFormat = "Z"
guard let refDate = formatter.date(from: refZoneString),
let date = formatter.date(from: ofs) else { return nil }
self.init(secondsFromGMT: Calendar.current.dateComponents([.second], from: date, to: refDate).second!)
}
}
let tz = TimeZone.init(UTCOffsetString: "-07:30")
print(tz?.identifier ?? "unknown")
I don't know what you mean by a cleaner but you can combine collection methods suffix and prefix to avoid the need to use String index to access the desired values:
let time = "-02:00"
let hours = Int(time.suffix(5).prefix(2)) ?? 0
let minutes = Int(time.suffix(2)) ?? 0
var offset = hours * 3600 + minutes * 60
if time.first == "-" { offset = -offset }
print(offset) // -7200
I want to get the difference between server UTC time and Local time.
I write some code here..
var localTime:String!
var timeString:String = "06:05:00" //This is server UTC time
let dateFormator = DateFormatter()
dateFormator.dateFormat = "H:mm:ss"
dateFormator.timeZone = TimeZone(abbreviation: "UTC")
let dt = dateFormator.date(from: timeString)
if dt != nil {
dateFormator.timeZone = TimeZone.current
dateFormator.dateFormat = "h:mm a"
localTime = dateFormator.string(from: dt!) //Converted current local time
}
let date = Date()
let dateFormatter2 = DateFormatter()
dateFormatter2.dateFormat = "h:mm a"
let timeStr = dateFormatter2.string(from: date)// Current time
let date1 = dt!
let date2 = dateFormatter2.date(from: timeStr)!
var _date1:String = localTime
var _date2:String = timeStr
//TODO: Remove the bellow two line and Comment *Line: 1 , Uncomment *Line: 2
//_date1 = "11:00"
//_date2 = "12:00"
let _dateFormatter = DateFormatter()
_dateFormatter.dateFormat = "HH:mm a" //*Line: 1
//_dateFormatter.dateFormat = "HH:mm" //*Line: 2
let date3 = _dateFormatter.date(from: _date1)
let date4 = _dateFormatter.date(from: _date2)
let _interval = date4!.timeIntervalSince(date3!)
let intervalInInt = Int(_interval)
let minutes3 = Int((_interval / 60).truncatingRemainder(dividingBy: 60))
let hours3 = Int((_interval / 3600))
String(format: "%02d:%02d", hours3, minutes3)
In this code time interval chunk of code works fine when time is in HH:mm formate, But I would like to check difference between "11:00 AM" & "1:00 PM" so it's fails. So please help me. Thanks in advance.
Use following to difference with local timestamp
let date = Date()
let timeZoneOffset = Double(TimeZone.current.secondsFromGMT(for: date))