Get Data from CoreData by given date using Predicate

Jakir Hossain
5 min readFeb 12, 2024

Using Predicate, we can filter or search from a data collection. In this tutorial, I am going to show how to use Predicate with core data to filter data by date.

First, create a iOS project in Xcode. From Storage selection, select Core Data.

Xcode will create a template for us. We can add data to core data by pressing Add icon.

In home view of the app, we will get list of all data. If we want to get only Today’s entity, we can use Predicate and query only today’s data like this:

We have to get start & end time of given date. For that, we can make an extension for Date:

extension Date {

var startOfDay : Date {
let calendar = Calendar.current
let unitFlags = Set<Calendar.Component>([.year, .month, .day])
let components = calendar.dateComponents(unitFlags, from: self)
return calendar.date(from: components)!
}

var endOfDay : Date {
var components = DateComponents()
components.day = 1
let date = Calendar.current.date(byAdding: components, to: self.startOfDay)
return (date?.addingTimeInterval(-1))!
}
}

And then we can use predicate like this:

predicate: NSPredicate(format: "timestamp >= %@ && timestamp <= %@", Date().startOfDay  as NSDate, Date().endOfDay  as NSDate),

That’s it. Now, we will get only today’s entity. Here is the full ContentView.swift:

import SwiftUI
import CoreData

struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext

@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
predicate: NSPredicate(format: "timestamp >= %@ && timestamp <= %@", Date().startOfDay as NSDate, Date().endOfDay as NSDate),
animation: .default)

private var items: FetchedResults<Item>

var body: some View {
NavigationView {
List {
ForEach(items) { item in
NavigationLink {
Text("Item at \(item.timestamp!, formatter: itemFormatter)")
} label: {
Text(item.timestamp!, formatter: itemFormatter)
}
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
Text("Select an item")
}
}

private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()

do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}

private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)

do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}

private let itemFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter
}()

extension Date {

var startOfDay : Date {
let calendar = Calendar.current
let unitFlags = Set<Calendar.Component>([.year, .month, .day])
let components = calendar.dateComponents(unitFlags, from: self)
return calendar.date(from: components)!
}

var endOfDay : Date {
var components = DateComponents()
components.day = 1
let date = Calendar.current.date(byAdding: components, to: self.startOfDay)
return (date?.addingTimeInterval(-1))!
}
}


#Preview {
ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}

You can pass any other date too. We have to customise the program a bit to do so. To select date, we have to use a Date picker. After selectcing date, we will fetch data of selected date. Here is the complete code:

import SwiftUI
import CoreData

struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext

@State private var selectedTime = Date.now

@State var items:[Item]!

var body: some View {
NavigationView {
VStack{

DatePicker("Please select a date", selection: $selectedTime)
.padding()
.onChange(of: selectedTime) { oldValue, newValue in
fetchData()
}


List {
if items != nil {
ForEach(items) { item in
NavigationLink {
Text("Item at \(item.timestamp!, formatter: itemFormatter)")
} label: {
Text(item.timestamp!, formatter: itemFormatter)
}
}
.onDelete(perform: deleteItems)
}

}
.onAppear(){
fetchData()
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
Text("Select an item")
}
}
}

private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.timestamp = selectedTime

do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}

private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)

do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}

private func fetchData(){
let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "timestamp >= %@ && timestamp <= %@", selectedTime.startOfDay as NSDate, selectedTime.endOfDay as NSDate)
do {
items = try viewContext.fetch(fetchRequest)
}catch {
// Handle error
print("Error saving data: \(error.localizedDescription)")
}
}
}

private let itemFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter
}()

extension Date {

var startOfDay : Date {
let calendar = Calendar.current
let unitFlags = Set<Calendar.Component>([.year, .month, .day])
let components = calendar.dateComponents(unitFlags, from: self)
return calendar.date(from: components)!
}

var endOfDay : Date {
var components = DateComponents()
components.day = 1
let date = Calendar.current.date(byAdding: components, to: self.startOfDay)
return (date?.addingTimeInterval(-1))!
}
}


#Preview {
ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}

Here is the output:

If you have data in selected date, it will show the data.

--

--