Core Date date comparion from date picker text field - ios

I am saving date in Core data successfully using Date type in model. Date saved in the format like 2017-04-02 14:56:41. When i retreive i want to filter date with current date text field which has a format like 02 April 2017. I am using predicate to compare both dates but app is crashed due to the difference or may be current date is in string.
let predicate = NSPredicate(format: "(dateSchedule >= %# )", fromTextField.text!)
core data date: 2017-04-02 14:56:41
currentdate textfield date: 02 April 2017
Any help?

I'm assuming dateSchedule is a Date in coredata.
You can convert your text on a date variable (make sure the format is correct)
let dateString = "2017-04-02 14:56:41"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
let dateObj = dateFormatter.date(from: dateString)
Then you create the predicate:
let predicate = NSPredicate(format: "(dateSchedule >= %# )", dateObj)
EDIT:
If the time of the date is annoying you, you can use a utility like this one:
https://github.com/erica/SwiftDates
So you can filter with:
let predicate = NSPredicate(format: "(dateSchedule >= %# )", dateObj.startOfDay)
In that way you are removing the time part and filtering by the beginning of the day

I would have formatted the dates this way:
let dateFormatter = Dateformatter()
dateFormatter.timeStyle = .none
dateFormatter.dateStyle = .medium
You can apply this to a date and get it as a string like this:
whatever you are saving it as = dateFormatter.string(from: Date())
Then you will get a date like this, "Mar 17, 2017".
This way of using the date formatter is very practical in your very situation.
When you are fetching you just do it the same way:
let predicate = NSPredicate(format: "(dateSchedule >= %# )", fromTextField.text!)
but I would advise you to use a UIDatePickerView instead:
let predicate = NSPredicate(format: "(dateSchedule >= %# ), dateFormatter.string(from: datePickerView.date)")

Related

DateFormatter returns nil with specific combination of TimeZone and Locale

In our app there is the issue with creating a date from string but is only reproducible with a very specific combination. Unfortunately, there is no way of getting it from the user that experienced the issue, so I decided to just go for it and try every possible combination:
import Foundation
var dateOnlyDateFormatter: (String, String) -> DateFormatter = { timeZoneS, localeS in
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.timeZone = TimeZone(identifier: timeZoneS)
formatter.locale = Locale(identifier: localeS)
return formatter
}
let date = "2022-05-27"
let time = "06:15"
for timeZone in TimeZone.knownTimeZoneIdentifiers {
for locale in Locale.availableIdentifiers {
let dateFormatter = dateOnlyDateFormatter(timeZone, locale)
let printDate = dateFormatter.date(from: date)
if printDate == nil {
print("TimeZone: \(timeZone), Locale: \(locale)")
}
}
}
The result:
TimeZone: America/Asuncion, Locale: ar_SA
TimeZone: America/Asuncion, Locale: en_SA
I am not too sure what is the best way to handle this issue. Obviously our BE could return date using one specific Locale, like en_US_POSIX, but I have very little control over that, being a part of a much bigger older system. Has anybody experienced an issue like that?
If you read the "Working With Fixed Format Date Representations" section of the DateFormatter docs, you'll find:
For most fixed formats, you should also set the locale property to a POSIX locale ("en_US_POSIX"), and set the timeZone property to UTC.
You should probably just follow the advice here... But here's possibly why SA and the Paraguay timezone produces nil.
Further down that section, there is a link to a technical Q&A where this is explained in more detail. The part that is most related to your problem is:
A user can change their calendar (using System Preferences > Language & Region > Calendar on OS X, or Settings > General > International > Calendar on iOS). In that case NSDateFormatter will treat the numbers in the string you parse as if they were in the user's chosen calendar. For example, if the user selects the Buddhist calendar, parsing the year "2010" will yield an NSDate in 1467, because the year 2010 on the Buddhist calendar was the year 1467 on the (Gregorian) calendar that we use day-to-day.
In the locale SA, the numbers of your date string seem to be interpreted using the Islamic Calendar. Take a look at today's date when formatted with en_SA and America/New_York.
let dateFormatter = dateOnlyDateFormatter("America/New_York", "en_SA")
let printDate = dateFormatter.string(from: .init())
print(printDate)
// 1443-10-26
Also take a look at the non-nil dates that is parsed by en_SA and America/New_York
let dateFormatter = dateOnlyDateFormatter("America/New_York", "en_SA")
let printDate = dateFormatter.date(from: date)
print(printDate)
// 2583-10-05 04:00:00 +0000
Notice that 10-05 is the first Sunday of the year 2583 (See this calendar). If Paraguay still uses the same DST rules as it does now in 2583, then it would mean that there is a DST gap transition at 2583-10-05 00:00:00, starting the DST period. The hour starting from 00:00:00 would be skipped, so 00:00:00 would not exist.
When parsing a date only, DateFormatter would try to set the time components to be 00:00:00 in the timezone of the formatter, but 00:00:00 does not exist, so the parsing fails.
In any case, just set locale to posix and timeZone to UTC when you have set dateFormat.
So if you use 'time' like this, there will be no nil values:
let dateOnlyDateFormatter: (String, String) -> DateFormatter = { timeZoneS, localeS in
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm"
formatter.timeZone = TimeZone(identifier: timeZoneS)
formatter.locale = Locale(identifier: localeS)
return formatter
}
let date = "2022-05-27 06:15"
//let time = "06:15"
for timeZone in TimeZone.knownTimeZoneIdentifiers {
for locale in Locale.availableIdentifiers {
let dateFormatter = dateOnlyDateFormatter(timeZone, locale)
let printDate = dateFormatter.date(from: date)
if printDate == nil {
print(">>>>>>>> TimeZone: \(timeZone), Locale: \(locale)")
} else {
print("..... \(printDate)")
}
}
}

I can't convert iso8601 to string swift

I have a string coming from API and its format will be like this
"2021-03-01T15:00:00+07:00"
so i try to convert this string to date using this code
// string to date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
let date = dateFormatter.date(from: isoDate)!
print("date from date Formatter = \(date)")
// convert date back to string
dateFormatter.dateFormat = "EEEE HH:mm"
let dateString = dateFormatter.string(from: date)
print("date string \(dateString)")
return dateString
The result that I expect is -> "2021-03-01 08:00:00 +0000", "Monday 15:00"
When I try this on playground the result is what I want, but when I try this on my project the result is
-> "1478-03-01 08:00:00 +0000", "Sunday 14:42"
How can I change the result to the same as i expect? Thanks
It looks like you are using a different calendar than you expect in your project (buddhist maybe?) and I guess this is because you haven't set one explicitly so it's the one set in System Preferences.
So if you for some reason do not want to use the users current calendar (and locale and time zone) you need to set those properties on your date formatter instance
//Gregorian calendar
dateFormatter.calendar = Calendar.init(identifier: .gregorian)
//UTC time zone
dateFormatter.timeZone = TimeZone(identifier: "UTC")
//English locale
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
This will give you the expected output.
Note that the playground is a bit inconsequent in what it uses and it seems to be a mix of what we have set in our System preferences and hardcoded values.

best way to convert date in English to French, nsdate, localization

My property dob of Patient object is String and currently storing 12-Jan-2017 and I want to convert it to French locale such as 12-Janv.-2017.
Below are my steps:
Converting 12-Jan-2017 into 1954-09-07 04:00:00 UTC
let dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale.init(localeIdentifier: "en_US_POSIX")
dateFormatter.dateFormat = "dd-MMM-yyyy"
let date = dateFormatter.dateFromString("12-Jan-2017") // now date is 1954-09-07 04:00:00 UTC
Next I have to set the locale of dateFormatter to fr
dateFormatter.locale = NSLocale.init(localeIdentifier: "fr")
let frenchDate = dateFormatter.stringFromDate(date!) // now it is 12-Janv.-2017
I dont think it is the best way to do a conversion. Are there any other efficient way for it. Any comments are welcomed.
(NS)DateFormatter has methods to convert a date to a string representation and vice versa. There is no (built-in) method to convert
from one date format directly to another format without intermediate
(NS)Date. So what you are doing is fine.
Some suggestions though:
Use optional binding instead of forced unwrapping to avoid a crash
at runtime if the input string is not in a valid format.
Use DateFormatter.dateFormat(fromTemplate:...) to get the
date format string appropriate for the chosen locale.
Then your code would be (in Swift 3):
let inputDate = "12-Jan-2017"
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "dd-MMM-yyyy"
if let date = dateFormatter.date(from: inputDate) {
dateFormatter.locale = Locale(identifier: "fr")
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "dd-MMM-yyyy", options: 0, locale: dateFormatter.locale)
let frenchDate = dateFormatter.string(from: date)
print(frenchDate) // 12 janv. 2017
} else {
print("invalid input date")
}

Same Date... But Different? Maybe timezone confusion

My problem is that I save a date into a string and as a date in CoreData. Later, I need to pull the date out of the string, compare the two, and find that they're the same date. Right now, that equality check fails. The two dates are 7 hours apart but with the minutes correct. I think it's a timezone issue but I can't figure out how to solve it.
The Origin of the Dates
I have a date from a date picker that I save to CoreData like this:
task.setValue(dueDatePicker.date, forKey: "dueDate")
After that I format the date and insert that date into a message:
let dateFormatter = DateFormatter()
let dateFormat = DateFormatter.Style.medium
let timeFormat = DateFormatter.Style.short
dateFormatter.dateStyle = dateFormat
dateFormatter.timeStyle = timeFormat
let formattedDate = dateFormatter.string(from: date)
let message = ("Upcoming task on \(formattedDate)")
That message becomes part of a notification. Hours or days later (when the notification fires and the user selects an action) I get the CoreData date:
fetchRequest.predicate = NSPredicate(format: "dueDate = %#", dateOfTask)
Then I decompose the notification message and get the date:
let start = notifString.range(of: "on ")
let rawDate = notifString[(start.upperBound)!..<(notifString.endIndex)]
let dateFormatter = DateFormatter()
dateFormatter.timeZone =
dateFormatter.dateFormat = "MMM-d-yyyy, H:mm a"
let dateFromString = dateFormatter.date(from: rawDate)
Lastly, I compare them. Currently the times are clearly the same day and minute but the timezones differ by about 7 hours. However, I don't want to just force a timezone that matches (Maybe force UTC for example) because that may not work for a user in another location.
How do I retrieve both dates without getting this apparent timezone issue?
Blatantly obvious, use userInfo as #Paulw11 suggested:
newLocalNotif.fireDate = dueDateWarningTime
newLocalNotif.alertBody = message
newLocalNotif.timeZone = TimeZone.autoupdatingCurrent
newLocalNotif.soundName = UILocalNotificationDefaultSoundName
newLocalNotif.category = "DueDates"
newLocalNotif.userInfo = ["name": name, "desc": desc, "dueDate" : date]

Searching by NSDate in Coredata not working - Swift

I am searching for a record in coredata by a specific NSDate but it's returning no results. It does not throw any error too..
When I loop through all the records I can output to the console the date.
Here is the predicate.. created is NSDate
let resultPredicate = NSPredicate(format: "created == %#", created)
..After digging around some more, the issue appears to be when I am handling the JSON of the timestamp:
var createdJSON:String = subJson["created"].string!
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = NSTimeZone(abbreviation: "EST")
var dateConverted:NSDate = dateFormatter.dateFromString(createdJSON)!
The time was stored in the MySQL database under eastern timezone, and maybe that's my mistake? Even though I can convert that JSON response to appear to be the same value, maybe it has to be UTC from the beginning?
-edit-
Converting to UTC does not help.
I think you'll have better luck if you search for a date range e.g.
let resultPredicate = NSPredicate(format: "created >= %# AND created <= %#", startDate, endDate)
where startDate and endDate are NSDates that you expect your results to fall between.

Resources