Compare date components Swift - ios

I have a task where I have to read the file once a day.
1)Label with text and the date blank.
2)When the user first goes to view. I need to show the text, save it and the date when it was followed
3)Leave it all on the screen all day.
4)When the next day comes. Compare the saved date with the current date.
5)If the current date is greater than the stored date. then read the file again, show the text and the date when this is done and save
(While there is this. The text changes every time you enter the application.
A saved date = 0,)
// compare oderDate and currentDate
func showTextToDay() {
let newDatePredict = Date()
let olderDate = UserDefaults.standard.object(forKey: dateUser) as! Date // THIS PROBLEM
let order = Calendar.current.compare(olderDate, to: newDatePredict, toGranularity: .day)
switch order {
case .orderedDescending:
print("DESCENDING")
case .orderedAscending:
readFilePrediction() //read again file bcs new day
print("ASCENDING")
case .orderedSame:
print("SAME")
}
}
func readFilePrediction() {
//some code
}
// save olderDate Func
func saveDatePredictFunc() {
let oldDatePredict = Date()
UserDefaults.standard.set(oldDatePredict, forKey: dateUser)
let dateLabel = UserDefaults.standard.object(forKey: dateUser) as! Date
let df = DateFormatter()
df.dateFormat = "dd/MM/yyyy"
toDateOutlet.text = df.string(from: dateLabel)
defaults.set(toDateOutlet.text, forKey: dateUser)
}

You have to check also if a date a available at all.
The guard statement represents a NOR expression. readFilePrediction will be executed if the date does NOT exist OR the date comparison is ascending.
func showTextToDay()
{
guard let olderDate = UserDefaults.standard.object(forKey: dateUser) as? Date,
Calendar.current.compare(olderDate, to: Date(), toGranularity: .day) != .orderedAscending else {
readFilePrediction()
saveDatePredictFunc()
return
}
}
And reading the data right after saving it to UserDefaults (dateLabel) is very bad practice. You got the value. And delete also the line to save the string representation of the date. The line breaks the ability to read the value as Date.
func saveDatePredictFunc()
{
let oldDatePredict = Date()
UserDefaults.standard.set(oldDatePredict, forKey: dateUser)
let df = DateFormatter()
df.dateFormat = "dd/MM/yyyy"
toDateOutlet.text = df.string(from: oldDatePredict)
}

Related

Not able to get date based on current locale

I’m populating month and date in a tableview. I have the app supporting France language also along with English. But I’m not able to get the months in France language when I change the locale to French. It’s getting reflected only once I launch the app again and not immediately after I change the language within the app.
This is what I have tried in cellForRowAtIndexPath…
let dic = myArray[indexPath.row] as! NSMutableDictionary
var utcTime = "\(dic["Due_Date"]!)"
self.dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss”
let currentLanguage = …. (Correctly gives ‘en’ OR ‘fr')
self.dateFormatter.locale = Locale.init(identifier: currentLanguage)
self.dateFormatter.timeZone = TimeZone(abbreviation: "UTC”)
if let date = dateFormatter.date(from:utcTime) {
let monthInt = Calendar.current.component(.month, from: date)
dayInt = Calendar.current.component(.day, from: date)
let yearInt = Calendar.current.component(.year, from: date)
let monthStr = Calendar.current.monthSymbols[monthInt-1]
print(monthStr, dayInt). //If the current language is ‘fr’ the month is printed here in English. It changes back to French only after I launch the app again
}
EDIT: This is how I changed the language within the app..
There is a class like so...
let APPLE_LANGUAGE_KEY = "AppleLanguages"
class TheLanguage {
class func currentAppleLanguage() -> String{
let userdef = UserDefaults.standard
let langArray = userdef.object(forKey: APPLE_LANGUAGE_KEY) as! NSArray
let current = langArray.firstObject as! String
return current
}
class func setAppleLAnguageTo(lang: String) {
let userdef = UserDefaults.standard
userdef.set([lang,currentAppleLanguage()], forKey: APPLE_LANGUAGE_KEY)
userdef.synchronize()
}
}
And I get the current language like so...
let currentLanguage = TheLanguage.currentAppleLanguage()
From the docs:
monthSymbols:
A list of months in this calendar, localized to the Calendar’s locale.
So I guess you need to change the calendar's locale to the one the user has selected.
Edit:
But, if you just need the month name from a given date (don't known what type dueDate is in your example) you can use this code:
let dueDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "LLLL"
dateFormatter.locale = Locale(identifier: "fr")
let month = dateFormatter.string(from: dueDate)

Once a 13 digit timestamp is saved in firebase, how can it be fetched and converted into a date in Xcode?

This is the database below. I need to take the 'caption' child which is a timestamp and convert it into date format in Xcode.
"UserS" : {
"K1eqsVZfKGgIf0sS1UZcPNxY62x1" : {
"Education" : "William Taft Elementary",
"PhotoPosts" : "https://firebasestorage.googleapis.com/v0/b/daylike-2f938.appspot.com/o/images%2FPhotoPosts?alt=media&token=fd92856e-f7d2-4558-82c4-ee49f580icc5e",
"caption" : 1563277511065,
"users" : "jane19#aol.com"
},
This is what I have under super view did load.
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
databaseRef.child("UserS").child(uid).child("caption").observeSingleEvent(of: .value, with: { (snapshot) in
guard let message = snapshot.value as? [String:String] else { return }
let caption = message["caption"]
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss.SSSSxxx"
guard let date = dateFormatter.date(from: caption!) else {
fatalError("ERROR: Date conversion failed due to mismatched format.")
}
if (snapshot.exists()){
print ("mmmmmmm")
}else{
print("badddddd")
}
})
At the end I want to print out the timestamp in date format so that I can check it it is 24 hours old.
"13 digit timestamp" is just and number of milliseconds since 1st of January 1970 UTC.
Date already has initializer for timestamps since that timepoint. Only difference is it's number of seconds, not milliseconds.
Therefore only thing you should do is to divide it by 1000:
// skipping unrelevant boilerplate
// assuming caption is Int
let date = Date(timeIntervalSince1970: TimeInterval(caption)/1000.0) // for `1563277511065` it would be `"Jul 16, 2019 at 11:45 AM"`(UTC)
// skipping unrelevant boilerplate
EDIT:
To check if date from timestamp is not "older" than 24 hours you have several options:
Get difference between the date and now and check if it's under 24 hours:
let secondsInDay = 86400
if (-date.timeIntervalSinceNow < secondsInDay) { … } // negative, because that date would be in the past
Get one day before using calendar:
let calendar = Calendar.autoupdatingCurrent // or whatever you prefer
let dayBefore = calendar.date(
byAdding: .day,
value: -1,
to: Date(),
wrappingComponents: true)!
if (date > dayBefore) { … }
Since you listen to UserS->caption then snapshot.value is an Int . so you need
databaseRef.child("UserS").child(uid).child("caption").observeSingleEvent(of: .value, with: { (snapshot) in
guard let caption = snapshot.value as? Int else { return }
print(caption)
let date = Date(timeIntervalSince1970: TimeInterval(caption)/1000.0)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss.SSSSxxx"
let res = dateFormatter.string(from: date)
print(res)
}
Edit:
if Calendar.current.dateComponents([.day], from:date, to: Date()).day! > 0 {
/// at least 1 day passed
}

Filter array of all events and find which event is still going on

I did a lot of searching through Stackoverflow but I havent found answer for my problem.
I am developing an app and I get JSON data for some events. What I get is the start time of the event and the duration of the event. All data in recived as String.
In one screen of the app I would like to show only the event that are currently going on.
for example:
Class Event {
var startTime: String?
var duration: String?
}
let event1 = Event()
event1.starTime = "12-12-2016, 10:50 AM"
event1.duration = "50min"
let event2 = Event()
event2.starTime = "12-12-2016, 09:50 AM"
event2.duration = "40min"
let event3 = Event()
event3.starTime = "12-12-2016, 10:10 AM"
event3.duration = "90min"
let allEvents = [event1, event2, event3]
and let say the the current date and time is 12-12-2016, 11:00AM. How can I filter/find events in allEvents that are still going on if we compare them to the current date?
Thank you in advance.
EDIT: My solution
I created method for converting dateString and durationString to startDate: Date and endDate: Date
static func convertDateStringAndDurationStringToStartAndEndDate(date: String, duration: String) -> (start: Date, end: Date)? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
guard let startDate = dateFormatter.date(from: date) else { return nil }
guard let duration = Int(duration) else { return nil }
// recived interval is in minutes, time interval must be calculated in seconds
let timeInterval = TimeInterval(Int(duration) * 60 )
let endDate = Date(timeInterval: timeInterval, since: startDate)
return (startDate, endDate)
}
For filtering I have created separated method. In my case I am using Realm database, but you will get the point.
static func filterResultsForNowPlaying(results: Results<Show>?) -> Results<Show>? {
let currentDate = NSDate()
let datePredicate = NSPredicate(format: "startDate <= %# AND %# <= endDate", currentDate, currentDate)
let filteredShows = results?.filter(datePredicate)
return filteredShows
}
You will need to convert them into dates, using DateFormatter, and then use a .filter over the array and have it match on if the current date is in range.
If you have the ability to change the Event class, you can greatly simplify your code if you replace your Event class with the DateInterval class, which does the same thing:
let minutes = 60;
let formatter = DateFormatter()
formatter.dateFormat = "MM-dd-yyyy"
let event1 = DateInterval(
start: formatter.date(from: "12-12-2016")!,
duration: TimeInterval(20 * minutes)
)
let now = Date()
if (event1.contains(now)) {
print("Event 1 is still active")
}

How to verify today date with last CoreData entry

I have a CoreData attributes that 2 (value, date). When I click on a UIButton, it added an entry corresponding to the value of the UIButton.
I will wish to limit the addition of entry to a daily. Basically, I will wish to check the current date and the date of the last entry. If it's value are identical, this is not added.
My Function
func data(sender: UIButton) {
// Date Format
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "YYYY/MM/dd"
let dateFormat = formatter.stringFromDate(date)
// Load Entity
let AppDel : AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let theContext : NSManagedObjectContext = AppDel.managedObjectContext
let theEnt = NSEntityDescription.entityForName("Mood", inManagedObjectContext: theContext)
// Create Item
let newItem = Mood(entity: theEnt!, insertIntoManagedObjectContext: theContext)
newItem.mood = String(sender.tag)
newItem.date = dateFormat
// Save Item
do {
try theContext.save()
} catch _ {
}
}
Thank you in advance for your response.
If you fetch the Mood objects, sorted by date in descending order, the first item returned will be the last entry. You can set the fetchLimit to 1 to avoid loading more objects than are necessary. You can then test to see whether the date attribute matches, and handle accordingly:
func data(sender: UIButton) {
// Date Format
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "YYYY/MM/dd"
let dateFormat = formatter.stringFromDate(date)
// Get context and entity details
let AppDel : AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let theContext : NSManagedObjectContext = AppDel.managedObjectContext
let theEnt = NSEntityDescription.entityForName("Mood", inManagedObjectContext: theContext)
// Fetch the latest entry
let fetch = NSFetchRequest()
fetch.entity = theEnt!
let sort = NSSortDescriptor(key: "date", ascending:false)
fetch.sortDescriptors = [sort]
fetch.fetchLimit = 1
let results = try! theContext.executeFetchRequest(fetch) as! [Mood]
// NB should do proper try/catch error checking
// Check for existing entry
if (results.count > 0) {
// Check whether date matches
if (results[0].date != dateFormat) {
let newItem = Mood(entity: theEnt!, insertIntoManagedObjectContext: theContext)
newItem.mood = String(sender.tag)
newItem.date = dateFormat
}
} else { // No entries yet, I assume you want to add one...
let newItem = Mood(entity: theEnt!, insertIntoManagedObjectContext: theContext)
newItem.mood = String(sender.tag)
newItem.date = dateFormat
}
// Save Item
do {
try theContext.save()
} catch _ {
}
}
Note that (given your code newItem.date = dateFormat) I am assuming the date attribute is a string which you set using the same format ("YYYY/MM/dd"). This strips out the time information and so avoids the need for the date comparisons, but also has the advantage that a string sort is equivalent to a date sort (perhaps you chose that format for that reason). If date is in fact a Date attribute, the sort will still work but you will need to use a date comparison.
I use an NSDate extension for this.
extension NSDate {
class func areDatesSameDay(dateOne:NSDate,dateTwo:NSDate) -> Bool {
let calender = NSCalendar.currentCalendar()
let flags: NSCalendarUnit = [.Day, .Month, .Year]
let compOne: NSDateComponents = calender.components(flags, fromDate: dateOne)
let compTwo: NSDateComponents = calender.components(flags, fromDate: dateTwo);
return (compOne.day == compTwo.day && compOne.month == compTwo.month && compOne.year == compTwo.year);
}
}
Usage is like this.
if NSDate.areDatesSameDay(dateOne, dateTwo: dateTwo) {
// Dates are same day
} else {
// Dates are not the same day
}
#Tom Harrington Has just pointed out that you can use the NSCalendar methods to do this more simply
let calender = NSCalendar.currentCalendar()
if calender.isDate(dateOne, inSameDayAsDate: dateTwo) {
// Dates are same day
}
So we can make my lovely extension even simpler...
extension NSDate {
func isSameDayAs(date:NSDate) -> Bool {
let calender = NSCalendar.currentCalendar()
return calender.isDate(self, inSameDayAsDate: date)
}
}
Then use it like this.
if dateOne.isSameDayAs(dateTwo) {
// Dates are same day
} else {
// Dates are not the same day
}
And thats Numberwang!

Saving Date and time in Parse backend

I have searched Parse blog to see if I can get the solution to this, but didn't get any satisfactory answer. So I though I will clearly ask the question here with all the details so anyone else stuck at similar situation will find it easy to work.
Need:
I have a departure and return text field which are updated using a single UIDatePicker. I want to save the selected dates in my Parse.com database. To which I can query and filter data. I also want to store local timezone in parse if possible. I am working with checking number of days but it was not relevant to this question so not including the code for that.
Success & Problem:
I am able to save correct date and time in String format , but when I try to save in NSDate format using the code below, I get wrong time.
For ex: my date selection and stored result in parse are as below:
Departure date:
Date Picker selection: 01/May/2015 01:00 AM +0530
Stored date in Parse: Apr 30, 2015, 19:30
Return Date:
Date Picker selection: 02/May/2015 01:00 AM +0530
Stored date in Parse: May 01, 2015, 19:30
//My code is as below:
#IBOutlet var dOfTravelText: UITextField!
#IBOutlet var returnDateText: UITextField!
lazy var dateFormatter: NSDateFormatter = {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd/MMM/yyyy hh:mm a Z"
// dateFormatter.dateStyle = .MediumStyle
// dateFormatter.timeStyle = .ShortStyle
return dateFormatter
}()
#IBAction func travelDatePicker(sender: UITextField) {
datePickerView.minimumDate = NSDate()
datePickerView.datePickerMode = UIDatePickerMode.DateAndTime
sender.inputView = datePickerView
timeSelected = sender
datePickerView.addTarget(self, action: "handleDatePicker:", forControlEvents: UIControlEvents.AllEvents)
}
// Date Picker target - Displaying date in textfield
func handleDatePicker(sender: UIDatePicker) {
//var dateFormatter = NSDateFormatter()
//dateFormatter.dateFormat = "mm/dd/yyyy"
timeSelected.text = dateFormatter.stringFromDate(sender.date)
println("From Date \(dOfTravelText.text!)")
println("To Date \(returnDateText.text!)")
}
// Submitting the dates to parse backend
#IBAction func postBtn(sender: AnyObject) {
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: date)
let dateMakerFormatter = NSDateFormatter()
dateMakerFormatter.dateFormat = "dd/MMM/yyyy hh:mm a Z"
let dD = dateMakerFormatter.dateFromString("\(dOfTravelText.text!)")!
let departureD = NSDateFormatter.localizedStringFromDate(dD, dateStyle: .MediumStyle, timeStyle: .ShortStyle)
println("From-------...\(departureD)")
let rD = dateMakerFormatter.dateFromString("\(returnDateText.text!)")!
let returnD = NSDateFormatter.localizedStringFromDate(rD, dateStyle: .MediumStyle, timeStyle: .ShortStyle)
println("To-------\(returnD)")
var userPost = PFObject(className:"UserPost")
userPost["departureDate"] = dD // Works but has Wrong time
userPost["rDate"] = rD // Works but Wrong time
userPost["travelDate"] = dOfTravelText.text // Works but it is stored in String format
userPost["returnDate"] = returnDateText.text // Works but it is stored in string format
userPost.saveInBackgroundWithBlock {
(success, error: NSError?) -> Void in
if (success) {
// The object has been saved.
println("Saved")
} else {
// There was a problem, check error.description
println("Error")
}
}
}
}
// Parse database column and type
travelDate & returnDate are defined as of type "String"
departureDate & rDate are defined as Of type "Date"
Just for information: I am using
Platform - iOS Swift (xcode 6.3, swift 1.2)
Database backend = Parse.com
Since Parse stores the dates referenced to GMT, when you check them on parse or retrieve them, you may find this difference to your local timezone. In general dates are stored in GMT.
You can add an extra field in your Parse database and store the local timezone there. When retrieving data you can then use that information to interpret the date in the zone it is referenced in.
Depending on the type of data you store it might be okay to always interpret the date in the users local timezone, even when this has changed. You also could ask the user for a resolution if saved timezone and user timezone are different (so the user has moved).
Setting up date pickers:
#IBOutlet weak var dDDatePicker: UIDatePicker!
#IBOutlet weak var rdDatePicker: UIDatePicker!
override func viewDidLoad() {
super.viewDidLoad()
setUpDatePickers()
}
func setUpDatePickers() {
// Set start date
dDDatePicker.date = Date()
rdDatePicker.date = Date()
// Set min and max date if you want
dDDatePicker.maximumDate = minDepartDate
rdDatePicker.maximumDate = minReturnDate
dDDatePicker.minimumDate = maxDepartDate
rdDatePicker.minimumDate = maxReturnDate
}
Saving dates to Parse:
func saveUserPost() {
let dD = dDDatePicker.date
let rd = rdDatePicker.date
let userPost = PFObject(className: "UserPost")
userPost["departureDate"] = dD
userPost["rDate"] = rD
userPost.saveInBackgroundWithBlock {
(success, error) -> Void in
if (success) {
// The object has been saved.
print("Saved")
} else {
// There was a problem, check error.description
print("Error")
}
}
}
As mentioned date is saved in UTC I would use DateFormatter() to get it back to string in the correct time zone:
if let dD = userPost["departureDate"] as? Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let str = dateFormatter.string(from: dD)
print("Depart date \(str)")
}
if let rD = userPost["rDate"] as? Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let str = dateFormatter.string(from: rD)
print("Return date \(str)")
}
Use this link to set 'dateFormat' however you want:
https://nsdateformatter.com/
From my understanding dateFormatter will format to the devices current timeZone - Honestly I never tested it in different time zones but it works for EST - you can test and if not as mentioned you can also save the user time zone and then specify in date formatter like so
dateFormatter.timeZone = TimeZone(abbreviation: "\(usertimeZone)")
Hope this helps!

Resources