Swift - timeIntervalSinceNow Only want to show up to minutes (excluding the seconds part) - swift

I'm using a timeIntervalSinceNow function to determine the difference between a certain time and the current time. I have used the "ZeroFormattingBehaviour" to .DropAll to get rid of any 0's in the date. However I want to make it so the difference doesn't include the seconds difference. For example if the difference is 2 days , 5 hours , 25min and 40 sec I want it to only show 2days,5h,25min. (e.g. excluding the seconds part) Is there any way to do so?
Code is as follows:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Values")
let sortDescriptor = NSSortDescriptor(key: "time", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
Values = results as! [NSManagedObject]
for result in results as! [NSManagedObject] {
times = result.valueForKey("time") as! String
let timeFormatter = NSDateFormatter()
timeFormatter.locale = NSLocale.currentLocale()
timeFormatter.dateFormat = "HH:mm dd/MM/yy"
let otherTime = timeFormatter.dateFromString(times)
let dateComponentsFormatter = NSDateComponentsFormatter()
dateComponentsFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyle.Abbreviated
dateComponentsFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehavior.DropAll
let difference = otherTime?.timeIntervalSinceNow
let diffAbs = abs(difference!)
let stringDiff = dateComponentsFormatter.stringFromTimeInterval(diffAbs)
// "\n" skips a line in the text
TimerLabel.text = stringDiff!
}
} catch let error as NSError {
TimerLabel.text = "There seems to be an error. Please try again later"
print("Could not fetch \(error), \(error.userInfo)")
}
Thanks

Specify the units you want to display
dateComponentsFormatter.allowedUnits = [.Day, .Hour, .Minute]

Related

Core Data. Filter by date

I have a .xcdatamodel in Core Data with the Entity Content and the Attributes dateCreated Type Date and text1 Type String.
//CREATE
func createData() {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let contentEntity = NSEntityDescription.entity(forEntityName: "Content", in: managedContext)!
let content = NSManagedObject(entity: contentEntity, insertInto: managedContext)
content.setValue(Date(), forKey: "dateCreated")
content.setValue("someText", forKey: "text1")
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
//READ
func readData() {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Content")
fetchRequest.predicate = NSPredicate(format: "text1 = %#", "some text")
do {
let result = try managedContext.fetch(fetchRequest)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "dateCreated") as! Date)
print(data.value(forKey: "text1") as! String)
}
} catch {
print("Failed")
}
}
if I print dateCreated, it gives: 2020-03-12 10:20:42 +0000
My question is: how can I read and filter by date? Only date, not time. For instance 2020-03-12 or any other date without time:
fetchRequest.predicate = NSPredicate(format: "dateCreated = %#", ?????)
In CreateData() you're storing the date by using Date(). So that it will be stored in you're database with the format yyyy-MM-dd HH:mm:ss ZZZZ. That's why it prints this 2020-03-12 10:20:42 +0000
Change from
fetchRequest.predicate = NSPredicate(format: "text1 = %#", "some text")
to
fetchRequest.predicate = NSPredicate(format: "dateCreated = %#", Date())
if you using this predicate instead of text1, the core data will give you result with Date and it'll be difficult to filter if there is time. So you have to insert the date by changing its format to yyyy-MM-dd
You can change the current date format by using DateFormatter().
//Needed date format
let dateFormat = DateFormatter()
dateFormat.dateFormat = "yyyy-MM-dd"
let formattedDate = dateFormat.string(from: Date())
So try by inserting the Date() by changing its format
//in CreateData()
content.setValue(formattedDate, forKey: "dateCreated")
//in ReadData()
fetchRequest.predicate = NSPredicate(format: "dateCreated = %#", formattedDate)

CKQuery with Todays Date

Would really value some support.
I am designing an tvOS app which displays certain CloudKit content in a tableView, the data is different depending on the current date.
Each calendar date correspondents to the data within that Type.
e.g. RecordType "A13032019" relates to 13th March 2019.
I generate the date in the correct format using a func fired within ViewDidLoad (generateDate():
*
func generateDate() {
let formatter = DateFormatter()
//2016-12-08 03:37:22 +0000
formatter.dateFormat = "ddMMyyyy"
let now = Date()
let dateString = formatter.string(from:now)
NSLog("%#", dateString)
let generateOperationalDate = ("A\(dateString)")
print(generateOperationalDate)
}
I then try to use generateOperationalData to run in the below CKQuery:
func queryDatabase() {
let query = CKQuery(recordType: "\(generateDate())", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
let sort = NSSortDescriptor(key: "trainDepartureTime", ascending: true)
query.sortDescriptors = [sort]
database.perform(query, inZoneWith: nil) { (records, _) in
guard let records = records else { return }
let sortedRecords = records
When I try to run this it throws a Thread Error with reason "* Terminating app due to uncaught exception 'CKException', reason: 'recordType can not be empty'
* "
So it appears to me that the queryDatabase function is running before the generateDate function, however I have tried delaying the queryDatabase function and this still throws the same error!
Is there anyway I can generate the date (via generateDate) before the queryDatabase function runs?
Thanks
You want to write generateDate() so it returns a String. Then, inside queryDatabase(), call generateDate() so you're guaranteed to have a value to pass to "recordType".
I also condensed the calls a little bit. Hope this helps.
func generateDate() -> String {
let formatter = DateFormatter()
formatter.dateFormat = "ddMMyyyy"
let dateString = formatter.string(from:Date())
return "A\(dateString)"
}
func queryDatabase() {
// this will make sure you have a String value
let type = generateDate()
// now you can pass it
let query = CKQuery(recordType: type, predicate: NSPredicate(value: true))
//...
}

Check Core Data for an entry with Today's Date & perform function

I am fairly new to Swift & hoping someone knows the answer to this - nothing I try seems to work!
I have a Swift app which has a Core Data entity called "Drink" with 2 keys: a Date & then one called "drinkWater" which stores a value of "1" when a button is pushed.
I am trying to write a separate function where I can check if an entry exists for todays date and, if so, perform an action (in this case change an imageview).
I realise the below isn't the answer but it's as far as I got! Basically I can get all of the entries based on the value of drinkWater (this would need to be by Date I am guessing?) and I can get today's date all printing to the console. Now I'm stuck ...
private func updateMyImageView() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Drink")
request.predicate = NSPredicate(format: "drinkWater = %#", "1")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "timestamp") as! Date)
}
} catch {
print("Failed")
}
let dateNow = Date()
print("Date is \(dateNow)")
}
This returns:
2018-12-29 01:27:27 +0000
Date is 2018-12-29 12:21:21 +0000
Any ideas on how to turn this all into the correct function would be greatly appreciated!!
You need to use a date range from start of day to end of day (midnight to midnight) in a compound predicate. Here is a solution based on a similar SO question
var calendar = Calendar.current
calendar.timeZone = NSTimeZone.local
let dateFrom = calendar.startOfDay(for: Date())
let dateTo = calendar.date(byAdding: .day, value: 1, to: dateFrom)
let fromPredicate = NSPredicate(format: "timestamp >= %#", dateFrom as NSDate)
let toPredicate = NSPredicate(format: "timestamp < %#", dateTo! as NSDate)
let waterPredicate = NSPredicate(format: "drinkWater = %#", "1")
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Drink")
request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [waterPredicate, fromPredicate, toPredicate])
Thank you for all of your help. I have it all working now. My final code is:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
var calendar = Calendar.current
calendar.timeZone = NSTimeZone.local
let dateFrom = calendar.startOfDay(for: Date())
let dateTo = calendar.date(byAdding: .day, value: 1, to: dateFrom)
let fromPredicate = NSPredicate(format: "timestamp >= %#", dateFrom as NSDate)
let toPredicate = NSPredicate(format: "timestamp < %#", dateTo! as NSDate)
let waterPredicate = NSPredicate(format: "drinkWater = %#", "1")
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Drink")
request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [waterPredicate, fromPredicate, toPredicate])
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "timestamp") as! Date)
drinkMoreButton.setBackgroundImage(UIImage(named: "watericonselected.png"), for: UIControlState.normal)
}
} catch {
print("Failed")
}

Error handling on fetch request and NSpredicate

I am extracting data from the past week using CoreData. It all works fine for days when some data is stored. However, when no data is stored, the program crashes. How can I handle this error?
for i in 0...6 { // Get every day in the past week
let appDel = (UIApplication.sharedApplication().delegate as! AppDelegate)
let context: NSManagedObjectContext = appDel.managedObjectContext
let request = NSFetchRequest(entityName: "Pulser")
request.returnsObjectsAsFaults = false
let calendar = NSCalendar.currentCalendar()
let now = NSDate()
let beginningOfToday = calendar.startOfDayForDate(now)
let previousDay = calendar.startOfDayForDate(calendar.dateByAddingUnit(.Day, value: -i, toDate: beginningOfToday, options: [])!)
let previousPreiviousDay = calendar.startOfDayForDate(calendar.dateByAddingUnit(.Day, value: -i - 1 , toDate: beginningOfToday, options: [])!)
request.predicate = NSPredicate(format:"(date >= %#) AND (date < %#)", previousPreiviousDay, previousDay)
do {
let results = try context.executeFetchRequest(request) as! [Pulser]
pulseArray.append(meanValue(results)) // if more than one value stored for each day, take the mean value of it
}
catch let error as NSError {
print(error)
}
}
It works like a charm now, thanks.
if results.count > 0 {
pulseArray.append(meanValue(results))
}

MapKit adding multiple annotations from core data

This is my code. It loops for the number records in the database but only retrieves the first records lat and lon.
func fetch() {
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = appDel.managedObjectContext!
let freq = NSFetchRequest(entityName: "Mappoints")
let fetchResults = try! context.executeFetchRequest(freq) as! [NSManagedObject]
self.mapView.delegate = self
myData = fetchResults
myData.count
for _ in myData {
let data: NSManagedObject = myData[row]
lat = (data.valueForKey("latitude") as? String)!
lon = (data.valueForKey("longitude") as? String)!
let latNumb = (lat as NSString).doubleValue
let longNumb = (lon as NSString).doubleValue
let signLocation = CLLocationCoordinate2DMake(latNumb, longNumb)
addAnnotaion(signLocation)
}
}
I am sure I am missing something simple but just keep missing it.
Your loop looks weird. You say myData[row], but you don't seem to increment the row. If the row does not increment, the data variable will always be the same.
You could do for example for data in myData { ...
This is the code I ended up with to fix the issue.
func fetch() {
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = appDel.managedObjectContext!
let freq = NSFetchRequest(entityName: "Mappoints")
let fetchResults = try! context.executeFetchRequest(freq) as! [NSManagedObject]
self.mapView.delegate = self
myData = fetchResults
let ct = myData.count // Add this line
// Then changed the for statement from for _ in myData
// To the line below and now all map points show up.
for row in 0...ct-1 {
let data: NSManagedObject = myData[row]
lat = (data.valueForKey("latitude") as? String)!
lon = (data.valueForKey("longitude") as? String)!
let latNumb = (lat as NSString).doubleValue
let longNumb = (lon as NSString).doubleValue
let signLocation = CLLocationCoordinate2DMake(latNumb, longNumb)
addAnnotaion(signLocation)
}