Convert two strings to NSDate - ios

i am trying to calculate the time between two dates. One of the dates is today and the other date is somewhere in the future.
The issue is the date in future is separated into two string, the first containing the date and the other containing the time for that date. When i put the two strings together to a single string and try to convert it to a NSDate i get Nil.
I assume there is something wrong with my date variable.
let eventDate: String? = "21 Aug Sun 2016"
let eventTime: String? = "9:00 PM"
let date : String? = "\(eventDate!) \(eventTime!)"
print(date!) // "21 Aug Sun 2016 9:00 PM"
let formatter = NSDateFormatter()
formatter.dateFormat = "dd MMM eee yyyy HH:MM a"
formatter.AMSymbol = "AM"
formatter.PMSymbol = "PM"
if let dateTimeForEvent = formatter.dateFromString(date!) {
print(dateTimeForEvent)
}else {
print("Error")// prints error
}

Two things:
You have the wrong format for the time. It should be h:mm a. HH is for a two-digit, 24-hour hour. You have a 1 or 2 digit, 12-hour hour. And MM is for a 2-digit month. Use mm for a two-digit minute.
If your date and time strings will always be in English, you need to set the formatter's locale to an English locale. If you don't, your code will always return a nil date on any device using a language other than English.

Your primary issue is that you're using HH, which is for 24-hour time, instead of hh, and MM (which is for month) instead of mm. Try this:
import Foundation
let eventDate = "21 Aug Sun 2016"
let eventTime = "9:00 PM"
let eventDateTime = "\(eventDate) \(eventTime)"
print(eventDateTime) // "21 Aug Sun 2016 9:00 PM"
let formatter = NSDateFormatter()
formatter.dateFormat = "dd MMM eee yyyy hh:mm a"
if let date = formatter.dateFromString(eventDateTime) {
print(date) // 2016-08-21 21:00:00 +0000
}
else {
print("Error")// prints error, no shit? why is this comment here?
}
Side notes:
Why is a variable called date, if it's a String??
Why is date an optional, anyway? You assigned it a literal value.
You don't have to set the AMSymbol and the PMSymbol. Those only pertain to printing dates, not parsing them.

Related

Swift date formatter ignoring months

I wrote a date reformatter but it appears Swift's date formatter itself is ignoring the months. The documentation says this shouldn't be happening. How do I make it not ignore months?
let testDate:String = "2020-11-22-11:00"
print("start date: ",testDate," reformatted date: ", reformatDate(dateString: testDate))
func reformatDate(dateString: String) -> String? {
print("dateString: ",dateString)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-DD-HH:mm"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
return dateFormatter.string(from: dateString)
}
this prints:
start date: 2020-11-22-11:00 converted date: 22-01-2020 11:00 AM
It unreasonably turns all months to 1!
Your format string is incorrect. It should be:
yyyy-MM-dd-HH:mm
and
dd-MM-yyyy h:mm a
dd means day-of-month, whereas DD means day-of-year.
Note that you should also do:
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
whenever you are using a custom date format.
Parsing 2020-11-22-11:00 with yyyy-MM-DD-HH:mm means that you want the twenty second day of the year 2020, in the month November. That makes no sense, and DateFormatter ends up ignoring the month because apparently day-of-year is a "stronger" date component. The 22nd day of any year is the 22nd of January.
Then, when you format the parsed date with DD-MM-yyyy h:mm a, the month component gets displayed as 01, and the day-of-year is still displayed as 22.
Here are some useful links to learn about format specifiers, you'll just how much lowercase/uppercase matters.
NSDateFormatter.com
TR-35

FSCalendar select day selects previous day at 23:00

I'm using FSCalendar in a Swift app, and when user selects a day, I'm printing the selected day, and the it prints the previous day, at 23:00. I'm not sure why and how can I solve this. I'm in spain. Maybe it's related with where you are and your local hour?
This is how I'm printing the selected day:
extension CalendarDataViewViewController: FSCalendarDataSource {
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm:ss"
let now = df.string(from: date)
logger.debug("Date: \(date)")
}
}
And this is what it's printed when I select 18 march:
21:01:24.646 đź’š DEBUG CalendarDataViewViewController.calendar():258 - Date: 2021-03-17 23:00:00 +0000
Your code creates a date formatter, converts the returned date to a date string with that formatter, and then ignores that and simply prints the date, which is being displayed in UTC. (Note the output Date: 2021-03-17 23:00:00 +0000)
Change your log command to read:
logger.debug("Date: \(now)")
And by the way, the variable name now is a terrible choice for holding a user-selected date that is not the current date.
I'd suggest renaming the returned date parameter selectedDate and the String output of the formatter as selectedDateString
Edit:
Consider this code:
import Foundation
func dateStringFromDate(_ inputDate: Date) -> String {
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm:ss a"
let dateString = df.string(from: inputDate)
return dateString
}
func isoDateStringFromDate(_ inputDate: Date) -> String {
let df = ISO8601DateFormatter()
df.formatOptions = .withInternetDateTime
df.timeZone = TimeZone.current //Force the formatter to express the time in the current time zone, including offset
let dateString = df.string(from: inputDate)
return dateString
}
let now = Date()
print("Current timezone = \(TimeZone.current)")
print("now in 'raw' format = \(now)")
let localizedDateString = DateFormatter.localizedString(from: now,
dateStyle: .medium,
timeStyle: .medium)
print("localizedString for the current date = \(localizedDateString)")
print("dateStringFromDate = \(dateStringFromDate(now))")
print("isoDateStringFromDate = \(isoDateStringFromDate(now))")
Right now, at about 9:16 PM EDT on Thursday March 18th, that logs the following:
Current timezone = America/New_York (current)
now in 'raw' format = 2021-03-19 01:16:52 +0000
localizedString for the current date = Mar 18, 2021 at 9:16:52 PM
dateStringFromDate = 2021-03-18 09:16:52 PM
isoDateStringFromDate = 2021-03-18T21:16:52-04:00
The 'raw' date format is in GMT, with an offset value of 0. In that form, in GMT, the calendar date is already March 19th. (Because GMT is 4 hours ahead of EDT)
The class function NSDateFormatter.localizedString(from:dateStyle:timeStyle) displays a date in the current time zone and using the device's locale settings. The dateStyle and timeStyle parameters give you the option to choose whether or not, and in what format (short, medium, or long) to display the date or time.
An ISO8601DateFormatter displays the date following the conventions in the ISO8601 standard. The isoDateStringFromDate(:) function above uses the .withInternetDateTime option to express the date in the ISO8601 "internet date and time" format. I forced that date to be in the local time zone, so it displays the date with a -4 hour offset from GMT (since it is EDT, eastern daylight savings time where I live.)
The function dateStringFromDate(_:) is a slight variation on your function. It returns a date string in the current time zone, using 12 hour times and an AM/PM string.

Convert date string to date object

Actual string - January 31, 2020 at 11:59:59 p.m. (ET).
format - "MMMM d, yyyy 'at' hh:mm:ss aa"
Not able to convert this string to Date object. Tried various date format and but unable to change string to Date object.
Please help
You could delete the non-standard character . between p and m and escape the parentheses around the time zone
let dateString = "January 31, 2020 at 11:59:59 p.m. (ET)"
let trimmedDateString = dateString.replacingOccurrences(of: ".m.", with: "m")
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "MMMM d, yyyy 'at' hh:mm:ss a (v)"
let date = formatter.date(from: trimmedDateString)
let raw = "January 31, 2020 at 11:59:59 p.m. (ET)"
func getDateFrom(_ raw: String) -> Date? {
if let i = (raw.range(of: "(")?.lowerBound) { // get index of open parenthesis
var zone: TimeZone?
let dateString = String(raw.prefix(upTo: i)) // January 31, 2020 at 11:59:59 p.m.
let zoneString = String(raw.suffix(from: i)) // (ET)
switch zoneString { // determine time zone
case "(ET)", "(EST)", "(EDT)": // study your data source and learn how they may express time zones
zone = TimeZone(abbreviation: "EDT")
default:
return nil // failure
}
let formatter = DateFormatter()
formatter.dateFormat = "MMMM d, yyyy 'at' hh:mm:ss a"
formatter.timeZone = zone
formatter.amSymbol = "a.m."
formatter.pmSymbol = "p.m."
if let date = formatter.date(from: dateString) {
return date
} else {
return nil
}
} else {
return nil
}
}
if let date = getDateFrom(raw) {
print(date) // 2020-02-01 04:59:59 +0000
}
This should be a good starting point. There are a number of ways to do this, such as whether you want it to fail if a time zone can't be determined, how to extract the time zone (using abbreviations, identifiers, seconds from GMT), etc. I like vadian's answer if I was completely comfortable with the time zone. But time zones are so inconsistent and surprisingly non-standardized when expressed as strings, that I'd rather dedicate a mechanism to getting it and making sure it's valid.
That said, this is a relatively crude example of where I'd begin—a finished version would be more nuanced. In this example, if the time zone fails, the function fails.

iOS Swift: how to convert specific date string format to Date object, when string contains time zone abbreviation?

I am getting a date string from server in the format of "March 08, 2018 16:00:00 PST" where there is a lot of whitespace between Month & Date.
My intention is to basically remove those extra whitespaces. My idea is that- I will convert the string into Date object, and then convert back to string.
How can I convert this into Date object using Date Formatter, taking timezone into consideration.
I am concerned about the "PST" here. While converting the Date to String, I will need in the format - "March 08, 2018 16:00:00 PST" i.e. PST (or whatever time zone comes in) should stay intact in the final string.
extension String {
func getDate(fromFormat format: String = "MMMM dd, yyyy HH:mm:ss zzz") -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
return dateFormatter.date(from: self)
}
}
let myDateString = "March 08, 2018 16:00:00 PST"
myDateString.getDate()
You can call with other time formats too.
Try this
let isoDate = "March 08, 2018 16:00:00 PST"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM dd, yyyy HH:mm:ss z"
let date = dateFormatter.date(from: isoDate)!
Try this
class func stringToDate (dateString:String, dateFormat:String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateFormat
let dateFromString = dateFormatter.date(from: dateString)
return dateFromString
}

Issue in formatting date string Swift 3 [duplicate]

This question already has answers here:
NSDateFormatter doesn't show time zone abbreviation for "Asia/Kolkata" for the "z" or "zzz" specifier, just the GMT offset
(1 answer)
What is the best way to deal with the NSDateFormatter locale "feature"?
(4 answers)
Closed 5 years ago.
I need to convert the following date string in to a Date in Swift 3.
Fri Dec 09 16:18:43 AMST 2016
Here is the code that i have been using, but it's getting cash on this particular date string conversion. (This date was logged on Android using new Date().toString() method.)
static func formatDate(date: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dateFormatter.dateFormat = "EEE MMM dd HH:mm:ss zzz yyyy"
//Works for "Fri Sep 16 10:55:48 GMT+05:30 2016"
var myDate = dateFormatter.date(from: date)
// My date returns nil on "Fri Dec 09 16:18:43 AMST 2016"
dateFormatter.dateFormat = "dd/MM/yyyy"
return "\(dateFormatter.string(from: myDate!))"
}
There are both type of strings in the database. I tried with various types of Timezone formats (z/zz/zzz/zzzz/zzzzz) but always myDate returns nil.
Any help would be appreciated.
Thanks In Advance.
Apple doc for TimeZone(abbreviation:):
In general, you are discouraged from using abbreviations except for unique instances such as “GMT”. Time Zone abbreviations are not standardized and so a given abbreviation may have multiple meanings.
Does AMST represents "Amazon Summer Time" (UTC-3) or "Armenia Summer Time" (UTC+5)? See: https://www.timeanddate.com/time/zones
That's probably why it can't detect the proper timezone to use.
Solutions I can propose:
If you know which timezone AMST is:
replace AMST by UTC-3 or UTC+5 in the date string
remove AMST from the date string and use dateFormatter.timeZone = TimeZone(secondsFromGMT: -3 or 5 * 3600)
Have your source output a more precise timezone.
Note the following code, where AMST is understood correctly:
let df = DateFormatter()
df.locale = Locale.init(identifier: "pt_BR") // assuming AMST is Amazon Summer Time (UTC -3)
df.dateFormat = "HH:mm:ss z"
print(df.date(from: "16:18:43 AMST")) // Optional(2000-01-01 19:18:43 +0000)
But as soon as you include English day or month names (e.g. Fri or Dec) it will produce nil (because they aren't in Portuguese).

Resources