App Crashed when device time is in 24 hour format - swift

In my App if IPhone device time is in 12 hour formate then date formatter works correctly but if device time is in 24 hour formate then app crashed.
let dateFormatter = NSDateFormatter();
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle;
dateFormatter.dateFormat = "hh:mm a";
var dt1 = dateFormatter.dateFromString(arrSecond.objectAtIndex(n) as! String)

#Rajan Thanks for giving me idea of NSLocale. I set the dateformatter's locale identifier to "en_US_POSIX".
i just add this below line in my code after allocating date formatter. dateformatter.locale = NSLocale(localeIdentifier:"en_US_POSIX")
Thanks frnd for giving this idea

Nandini answer is correct. But the only issue is that if you harcode the locale, the dates are displayed only in english.
In my case I wanted it in french, here is a workaround that worked for me in Swift 3 :
dateformatter.locale = Locale(identifier: NSLocale.current.identifier)

Assuming that you are using Swift 2.x version after seeing your code.
The problem is because your dateFormatter contains a and for the 24 Hour Format time we don't have a
So in order to fix your problem, you have to check whether your device is in 24-Hour format or 12 Hour format
Taking your array's index object in a variable time and keep that as var because we will change that later.
var time = arrSecond.objectAtIndex(n) as! String //this contains 07:45 AM
//Now create your Date Formatter
let dateFormatter = NSDateFormatter();
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle;
//Now check whether your phone is in 12 hour or 24 hour format
let locale = NSLocale.currentLocale()
let formatter : String = NSDateFormatter.dateFormatFromTemplate("j", options:0, locale:locale)!
//we have to change our dateFormatter as per the hour format
if formatter.containsString("a") {
print("phone is in 12 Hour Format")
dateFormatter.dateFormat = "hh:mm a";
} else {
print("phone is in 24 Hour Format")
time = convertTo24HourFormat(time) //time changed to 24 Hour format and AM/PM removed from string
dateFormatter.dateFormat = "HH:mm";
}
let finalDate = dateFormatter.dateFromString(time)
print(finalDate!)
And we need a function to make your time string converted to 24 hour format if your phone is in 24 Hour Format.Function defination of convertTo24HourFormat is
//Example 08:45 PM to 20:45
func convertTo24HourFormat(time:String) -> String {
var formattedTime = time
if formattedTime.containsString("PM") {
var hour = Int(formattedTime.substringToIndex(formattedTime.startIndex.advancedBy(2)))
if hour != 12 {
hour = hour! + 12
formattedTime.removeRange(Range<String.Index>(start: formattedTime.startIndex, end: formattedTime.startIndex.advancedBy(2)))
formattedTime = "\(hour!)\(formattedTime)"
}
} else {
// For AM time
var hour = Int(formattedTime.substringToIndex(formattedTime.startIndex.advancedBy(2)))
//case for 12 AM
if hour == 12 {
formattedTime.removeRange(Range<String.Index>(start: formattedTime.startIndex, end: formattedTime.startIndex.advancedBy(2)))
formattedTime = "00\(formattedTime)"
}
}
formattedTime = formattedTime.substringToIndex(time.startIndex.advancedBy(5))
return formattedTime
}
But converting only the time to date object don't make any sense as it will give a wrong date.
NOTE:-
The convertTo24HourFormat function will only work fine if you send the time in the format hh:mm a. For example 07:45 AM

I had to change my formatter from this:
dateFormatter.dateFormat = "dd MM yyyy hh:mm:ss.SSS"
to this:
dateFormatter.dateFormat = "dd MM yyyy HH:mm:ss.SSS"

Related

Getting error when converting date format error | Swift

Essentially I would like to convert the following:
2022-07-01 14:35:00
To simply:
July 1st
The following is what I currently have because the initial input is string, but when I'm converting from string to date time the hour seems to have +2 hours added to it. Why is this happening?
// Create String
let string = "2022-07-01 14:35:00"
// Create Date Formatter
let dateFormatter = DateFormatter()
// Set Date Format
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
// Convert String to Date
let newdate = dateFormatter.date(from: string)
print(newdate!)
Time depends on where you are. So in this case the +2 hours you see, may be due to the difference in TimeZone. So adjust the TimeZone in the format to match the original place, or put everything in GMT TimeZone, or a common TimeZone of your choosing. Alternatively, keep the time difference.
Try something like this:
let string = "2022-07-01 14:35:00"
let readFormatter = DateFormatter()
readFormatter.timeZone = TimeZone(abbreviation: "GMT") // <-- here adjust
readFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let writeFormatter = DateFormatter()
writeFormatter.timeZone = TimeZone(abbreviation: "GMT") // <-- here adjust
writeFormatter.dateFormat = "LLLL dd"
if let theDate = readFormatter.date(from: string) {
print("\n----> theDate: \(theDate)") // ----> theDate: 2022-07-01 14:35:00 +0000
let simpleDate = writeFormatter.string(from: theDate)
print("\n----> simpleDate: \(simpleDate)") // ----> simpleDate: July 01
}

How to calculate the correct time interval between two times that span two days in swift?

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!

Assigning NSDateComponents to a label

I'm creating a mobile app that has a countdown to a specific date. I think I have the timer itself correct, but I'm struggling to get it into a format where I can assign it to my label. I'm getting an error "Cannot invoke initializer for type 'String' with an argument list of type '(NSDateComponents)'. This error is found at the line "var date = String(openingGavelDate)". The outlet for the label has been properly created in this file.
First step I took was creating the date variable and setting it equal to the converted value of my other variable. Second step involved trying to look through documentation but so far I haven't really found any substantial documentation that can help.
func createGavelTimer() {
let openingGavelDate = NSDateComponents()
openingGavelDate.year = 2019
openingGavelDate.month = 7
openingGavelDate.day = 16
openingGavelDate.hour = 14
openingGavelDate.minute = 00
openingGavelDate.timeZone = NSTimeZone(abbreviation: "CST")! as TimeZone
var date = String(openingGavelDate) //problem is here
countdownLabel.text = date
}
One of possible solutions:
let date = Calendar.current.date(from: openingGavelDate)
let dateFormatter = DateFormatter()
dateFormatter.timeStyle = .short
dateFormatter.dateStyle = .medium
dateFormatter.doesRelativeDateFormatting = true
dateFormatter.timeZone = TimeZone(abbreviation: "CST")!
let yourString = dateFormatter.string(from: date)
Try converting the NSDateComponents object to a Date by using Calendar.date(from:), and then converting that to a String using a DateFormatter:
let gregorianCalendar = Calendar(identifier: .gregorian)
if let date = gregorianCalendar.date(from: openingGavelDate as DateComponents) {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .none
countdownLabel.text = dateFormatter.string(from: date)
}
Also, as #Sh_Khan and #rmaddy have commented, you should be using DateComponents, TimeZone, etc. instead of their NS counterparts (unless you're using Swift 2 or lower).
Two things you need to do to form your date:
Set a calendar on the DateComponents instance.
Get your date by accessing the date property on your DateComponents instance.
Also, I'd recommend using time zone identifiers instead of abbreviation to specify a time zone; advantage is that identifiers will automatically apply special rules such as daylight savings as appropriate. (Below I've substituted the "America/Chicago" zone for UTC.)
Try this code in a playground:
var openingGavelDate = DateComponents()
let timeZone = TimeZone(identifier: "America/Chicago")!
openingGavelDate.year = 2019
openingGavelDate.month = 7
openingGavelDate.day = 16
openingGavelDate.hour = 14
openingGavelDate.minute = 00
openingGavelDate.calendar = Calendar.current
openingGavelDate.timeZone = timeZone
let date = openingGavelDate.date
print(date ?? "no date")
Output: 2019-07-16 19:00:00 +0000 (your date in GMT.)
This will get you a date, but notice that the Date class prints in GMT by default, because Date has no concept of timezone.
To print date in the timezone and format you want, use DateFormatter:
let f = DateFormatter()
f.dateFormat = "yyyy-MM-dd hh:mm a"
f.timeZone = TimeZone(identifier: "America/Chicago")!
print(f.string(from: date!))
Output: 2019-07-16 02:00 PM (your date & time, in CST and formatted for reading.)
DateFormatter allows you to either control the format yourself, or follow the user's system settings to determine what is in the final string. See the docs for DateFormatter to see how to get it into the format you want to display.

Converting string to date returning the day before

I have a date in a string with this format "2017-03-14" (yyyy-MM-dd) and i am trying to convert it into a string with this format "Tuesday, March 14, 2017".
This is my code:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let date = dateFormatter.date(from: "2017-03-14")
Now if i print the value of "date", i get this:
2017-03-13 22:00:00 +0000
This is just the day before. Why is that ?
EDIT:
I need to compare date before formatting it.
var newDateString : String = ""
let date2 = Date()
let comp = date2.compare(date!)
if comp.rawValue == 0 {
newDateString = "TONIGHT"
} else {
dateFormatter.dateFormat = "EEEE, MMMM d, yyyy"
newDateString = dateFormatter.string(from: date!)
}
Thanks
The desired Format should be:
EEEE, MMMM dd, yyyy
All you have to do is to add after your code the following code snippet:
dateFormatter.dateFormat = "EEEE, MMMM dd, yyyy"
let string = dateFormatter.string(from: date!) // "Tuesday, March 14, 2017"
Remark:
I'd like to suggest to do optional binding for declaring the date, as follows:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
if let date = dateFormatter.date(from: "2017-03-14") {
dateFormatter.dateFormat = "EEEE, MMMM dd, yyyy"
let string = dateFormatter.string(from: date) // "Tuesday, March 14, 2017"
}
Your confusion is based on a misunderstanding of what Time and Date are. Evidently, you are currently located in a time zone that is 2 hours ahead of UTC (Coordinated Universal Time), previously known as Greenwich Mean Time (GMT).
When you ask the OS for a Date object converted from "2017-03-14" you get a date/time reference of Midnight the morning of 2017-03-14 in your time zone which is, correctly, 10:00 pm (22:00) then night before in UTC.
When you ask the OS for a Date object for now with Date() you get a date/time reference of now in your time zone, which will be two hours earlier in UTC.
To accurately evaluate your date string to say "is now earlier than 'tonight of 2017-03-14'" you will probably want to convert from "2017-03-14 23:59" (or 11:59 pm, or perhaps prior to the start of tonight's event of 8:00 pm, etc).
This will do your original comparison, but would work better as a function (although I'm not sure how you want to use it)...
var newDateString : String = ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
// set tonightDate to 1 minute before midnight, tonight, in local time
if let tonightDate = dateFormatter.date(from: "2017-03-14 23:59") {
// set nowDate to current local time
let nowDate = Date()
let comp = nowDate.compare(tonightDate)
if comp.rawValue <= 0 {
newDateString = "TONIGHT"
} else {
dateFormatter.dateFormat = "EEEE, MMMM d, yyyy"
newDateString = dateFormatter.string(from: tonightDate)
}
}
print(newDateString)
It is calculated time based on UTC so you are getting day before.You can get proper format using below code:
func chageDateFormat(date:String) -> String{
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
guard let date = dateFormatter.dateFromString(date) else {
assert(false, "No date from string")
return ""
}
print(date)
dateFormatter.dateFormat = "EEEE, dd MMMM, yyyy"
let result = dateFormatter.stringFromDate(date)
return result
}
let resultFormateDate = chageDateFormat("2017-03-14")
For comparison you also need to convert Date() to proper format.Both date must be in same format.
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let date = NSDate()
let strdate = dateFormatter.stringFromDate(date)
let resultFormateDate2 = chageDateFormat(strdate)
Now you can compare two strings
if resultFormateDate == resultFormateDate2{
print("True")
}

How to convert a String to NSdate?

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/