Realm date range query in Objective-C - objective-c

I'm working with Realm and I have an array sorted by dates for all the entries of a specific card. I need to create a NSPredicate (or some other way) that will give me all the dates for that card in order for a specific month. My trouble is some months have different amounts of days in them.
Here is what I have so far.
// Filter specific card, create date and string for x axis
NSString *filteredName = [NSString stringWithFormat:#"%#", self.cardType];
NSDate *dateElement = [[NSDate alloc]init];
NSString *datedString = [[NSString alloc]initWithFormat:#""];
//Formatting datedString
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateFormat = #"MM/dd/YYYY";
NSSortDescriptor *dateSort = [[NSSortDescriptor alloc]initWithKey:#"date" ascending:YES];
NSArray *sortedArray = #[dateSort];
//self.orderHistory is all of the cards from the Realm database filtered down to a specific type of card.
for (Order *uniqueOrder in [self.orderHistory objectsWhere:#"name = [c] %#", filteredName]) {
// [self.uniqueCardArray addObject:uniqueOrder];
dateElement = uniqueOrder.date;
datedString = [df stringFromDate:dateElement];
[self.uniqueDatesForCardArray addObject:datedString];
}
[self.uniqueCardArray sortUsingDescriptor:sortedArray];
Code above gives me all the dates for a specific card I need the dates for a given month so I have tried this tacky solution but I would think there is something more elegant to say the least.
NSDate *todaysDate = [NSDate date];
NSTimeInterval secondsInMonth =- (60 * 60 * 24 * 365) / 12;
NSDate *dateOneMonthBack = [todaysDate dateByAddingTimeInterval:secondsInMonth];
NSPredicate *backDatesPred = [NSPredicate predicateWithFormat: #"date BETWEEN {%#, %#}", dateOneMonthBack, todaysDate];
Besides it being nasty code it will also take me back a month from the current date and not only back to the start of the month. Been looking at the Realm documentation, NSCalendar stuff, and NSPredicate guide and now my head is swimming trying to count for all the possible problems that can go wrong with this. Any advice or code snippets would be a great help.

I'm not sure whether I understand your question correctly, the following code is what you want?
To determine the date of the previous month, add NSDateComponet that has minus month to the date.
Realm supports BETWEEN query. So you can just query by two days.
NSDate *todaysDate = [NSDate date];
NSDateComponents *comps = [NSDateComponents new];
comps.month = -1;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *dateOneMonthBack = [calendar dateByAddingComponents:comps toDate:todaysDate options:kNilOptions];
RLMResults *filteredHistory = [self.orderHistory objectsWhere:#"name = [c] %#", filteredName];
RLMResults *rangedHistory = [filteredHistory objectsWhere:#"date BETWEEN {%#, %#}", dateOneMonthBack, todaysDate];

Related

How to get all the date of last one month

i want to get all the dates from yesterday date to one month..
like today is 19 may, so i need all the date from 18 may to 18 April.
please help.
You can use this code.It works.
NSDate *currentDate = [NSDate date];
NSLog(#"Current Date = %#", currentDate);
NSDateComponents *dateComponents = [NSDateComponents new];
dateComponents.month = -1;
NSDate *currentDatePlus1Month = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:currentDate options:0];
NSLog(#"Date = %#", currentDatePlus1Month );
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];
NSDateComponents *days = [[NSDateComponents alloc] init];
NSMutableArray* arr =[[NSMutableArray alloc]init];
NSInteger dayCount = 0;
while ( TRUE ) {
[days setDay: ++dayCount];
NSDate *date = [gregorianCalendar dateByAddingComponents: days toDate: currentDatePlus1Month options: 0];
if ( [date compare: currentDate] == NSOrderedAscending ){
[arr addObject:date];
}
if([[arr lastObject] isEqual:[currentDate dateByAddingTimeInterval:-60*60*24*1]])
{
NSLog(#"%lu",(unsigned long)arr.count);
break;
}
// Do something with date like add it to an array, etc.
}
if you find all dates you can remove count and get all dates in array.
To achieve this, I think you should have an Array holding all those dates. I'll write pseudocode about the logic here.
INIT dateArray
NSDate pastDate = (today).yesterday
NSDate lastMonth = pastDate.lastMonth()
WHILE pastDate > lastMonth // pastDate is after lastMonth
dateArray.add(pastDate)
pastDate = pastDate.yesterday
END WHILE
About how to turn this pseudocode into real code is another story (this would be quite long). Hope this help.
PS: If you'd like Objective-C solution, please comment. I'll take my time write it for you ;)

Generate consecutive sequence of NSDates

Given some startDate, I would like to degenerate x number of consecutive days after this startDate. I'm attempting to use the following code:
// Generate dates
self.days = [[NSMutableArray alloc] init];
NSDate *startDate = [NSDate date];
NSCalendar *theCalendar = [NSCalendar currentCalendar];
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = 1;
for (int i = 1; i < self.mygoal.goalDays; i++) {
[self.days addObject:startDate];
startDate = [theCalendar dateByAddingComponents:dayComponent toDate:startDate options:0];
}
Question: Is the reassignment of startDate ok, given that I'm adding the same object to self.days?
Creating a sequence of dates is not as trivial as it sounds. Actually it is covered in the great WWDC2011 video «Performing Calendar Calculations».
You are adding in every loop a day to the last date. But actually this will fail in timezones with DST if the time is in the hour that is changed for the day of switching and for any following days as the dates will be nil.
If you instead change the date components i the loop and add it to the original satrtdate, it will only effect the day of DST-switching.
To also handle that you can set the hour of the start date to something safe — as noon — as all switches are performed at night hours.
With all this in mind I would use something like this to create a sequence of days with times set to start of day:
NSUInteger numberOfDays = 10;
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *startDate = [cal dateFromComponents:({
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.year = 2015;
comps.month = 1;
comps.day = 2;
comps.hour = 12; // for DST-safety
comps;
})];
NSMutableArray *dates = [#[] mutableCopy];
for (NSUInteger i =0 ; i < numberOfDays; ++i) {
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = i;
NSDate *date = [cal dateByAddingComponents:comps
toDate:startDate
options:0];
// set date to beginning of day
[cal rangeOfUnit:NSCalendarUnitDay
startDate:&date
interval:NULL
forDate:date];
[dates addObject:date];
}
So, yes, reassignment is technically OK, but in this particular case it is might cause unexpected trouble.
It's fine because you're not actually adding the same object. dateByAddingComponents: returns a new object, so when you assign it to startDate you are replacing the reference to your old object to a reference to the new one

Core Data Predicate Date Comparison

Im trying to fetch all the objects in an entity matching a user selectedDate (it's an NSDate).
The Core Data code is fine but my predicate keeps returning 0 results, the dates are the same in the database as the user is selecting.
How should the selectedDate be compared with a date from an entity using a predicate?
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(eDate = %#)", selectedDate];
Your predicate looks to be fine.
The reason you're finding zero result are returned however may be that the dates aren't entirely the same.
For example:
05/04/2012 13:37:00 will not match with 05/04/2012 13:37:01 as these two values are not exactly the same.
Do you want to check the date (day, month, year) as well as the time?
If you only want to check the date, you should create a start date and end date and compare them using the user selected date as a frame of reference.
Something similar to this should create a date and time for 00:00:00.
//gather current calendar
NSCalendar *calendar = [NSCalendar currentCalendar];
//gather date components from date
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]];
//set date components
[dateComponents setHour:0];
[dateComponents setMinute:0];
[dateComponents setSecond:0];
//return date relative from date
return [calendar dateFromComponents:dateComponents];
Create another date by setting the hours, minutes and seconds to 23:59:59 and check that your user selected date falls between these ranges.
[NSPredicate predicateWithFormat:#"date BETWEEN %#", [NSArray arrayWithObjects:startOfDay, endOfDay, nil]]
While in human communication date often is equal with day, it is not the same with NSDate objects: A NSDate represents a single moment in time. Dates that are different just in seconds aren't equal. And actually they dont represent days, month, year at all, as this is different from calendar system to calendar system
you must define for yourself if dates in the same minute, hour, day … are equal. So basically you must teach the program to allow some fuzziness.
here for minute resolution
NSDate *startDate = ....;
NSTimeInterval length;
[[NSCalendar currentCalendar] rangeOfUnit:NSMinuteCalendarUnit
startDate:&startDate
interval:&length
forDate:startDate];
NSDate *endDate = [startDate dateByAddingTimeInterval:length];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(eDate >= %#) AND (eDate < %#)", startDate, endDate];
For dates on the same day (aware of Timezones and Daylight Saving Times) you just would change this:
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit
startDate:&startDate
interval:&length
forDate:startDate];
I can get working with some modifications to the accepted answer and using the iOS 8 API for create dates with time offset. The code:
NSCalendar *calendar = [[FFSharedCalendar singleton] getGregorianCalendar];
NSDate *startOfDay = [calendar dateBySettingHour:0 minute:0 second:0 ofDate:[NSDate date] options:0];
NSDate *endOfDay = [calendar dateBySettingHour:23 minute:59 second:59 ofDate:[NSDate date] options:0];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"createdAt > %# AND createdAt < %#", startOfDay, endOfDay];
NSArray* plans = [Plan MR_findAllWithPredicate:predicate];
Hope it helps someone
I've recently spent some time attempting to solve this same problem and have resolved the following, now updated for iOS 8 and above...
NSDate *dateDay = nil;
NSDate *dateDayStart = nil;
NSDate *dateDayNext = nil;
dateDay = <<USER_INPUT>>; //for example - selectedDate
dateDayStart = [[NSCalendar currentCalendar] startOfDayForDate:dateDay];
// dateDayNext EITHER
dateDayNext = [dateDayStart dateByAddingTimeInterval:(24 * 60 * 60)];
// dateDayNext OR
NSDateComponents *dateComponentDay = nil;
dateComponentDay = [[NSDateComponents alloc] init];
[dateComponentDay setDay:1];
dateDayNext = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponentDay
toDate:dateDayStart
options:NSCalendarMatchNextTime];
...and the NSPredicate for the Core Data NSFetchRequest (as already shown above in other answers)...
[NSPredicate predicateWithFormat:#"(dateAttribute >= %#) AND (dateAttribute < %#)", dateDayStart, dateDayNext]]
I query in between 1 second above and below my actual Date. In my case its ok to add and subtract 1 second as I query for the restaurant orders so I know that it takes some time to punch a new order, for safe side I have 1 more orderNo field too.
let fetchRequest: NSFetchRequest = Order.fetchRequest()
let date_formatter = DateFormatter()
date_formatter.dateFormat = "yyyy-MM-dd-HH-mm-ss"
date_formatter.timeZone = TimeZone(abbreviation: "UTC")
let createdDate = date_formatter.date(from: clientCreatedStr)
let calendar = NSCalendar.current
//as matching exact same datetime doesnt return anything
let onesecondafter = calendar.date(byAdding: .second, value: 1, to: createdDate!)
let onesecondbefore = calendar.date(byAdding: .second, value: -1, to: createdDate!)
let predicate = NSPredicate(format: "offlineUniqueId == %# AND (clientCreatedDate >= %# AND clientCreatedDate <= %#)", offlineUniqueId, onesecondbefore! as NSDate, onesecondafter! as NSDate)
fetchRequest.predicate = predicate

Struggling to store a date for later use

Hi I'm very new to iOS programming and am playing around with dates (todays date and a date 1 year from now).
Here's the code i'm dabbling with.
NSCalendar * calendar = [NSCalendar currentCalendar];//Create a calendar
NSDate *todaysDate = [[NSDate alloc]init]; //get todays date
NSString *dateToday = [NSString stringWithFormat:#"%#",todaysDate];//convert it to a string
NSDateFormatter *df = [[NSDateFormatter alloc] init];// create a formatter
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss ZZZ" ];//input how the date looks as a string
myDate = [df dateFromString: dateToday];// change it back to a proper NSDate
NSDateComponents *components = [[NSDateComponents alloc] init]; // create the components
[components setYear:1];//add 1 year
nextYear = [calendar dateByAddingComponents:components toDate:todaysDate options:0]; // build the year from component into a variable
dateNextYear = [NSString stringWithFormat:#"%#",nextYear];//convert it to a string
NSDateFormatter *yearFormat = [[NSDateFormatter alloc] init];// create a formatter
[yearFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss ZZZ" ];//input how the date looks as a string
myDateInTheFuture = [yearFormat dateFromString: dateNextYear];// change it back to a proper NSDate
NSLog(#" next years date is %# ", myDateInTheFuture);
[yearFormat release];
[components release];
[todaysDate release];
I can get the current date and the future date 1 year from now, but i'm unsure how i would store the future date for comparison, i know i can use the "compare" item for NSDate to check, but when i set the future date to a variable every time it runs it stays relative 1 year apart from what i'm checking it against which is todays date.
Its 3am where i am and my brain is mush so apologises in advance if this is the simplest thing ever and i just can't see it.
Its my first post so go easy on me please.
Thanks
I am not entirely sure what you are trying to do, but this is what I gather:
You want to take the current date, add a year to it, and manipulate the resulting date.
Please notify me if this is not correct.
For this, try the following:
NSDate *todayDate = [NSDate date]; //Create a date that is set to today
NSDate *resultingDate = [calendar dateByAddingTimeInterval:31556926; //Take the current date and add the amount of seconds in a year to it
If you want to store this permanently, use the NSUserDefaults:
to set:
[userDefaults setObject:resultingDate forKey:#"storedDate"];
Hope this helps,
HBhargava
to get:
NSDate *returnedDate = [userDefaults dateForKey:#"storedDate"];

Objective C - How can i get the weekday from NSDate?

I need to be able to get the weekday from nsdate, i have the following code and it always return 1. I tried to change the month, i tried everything from 1 to 12 but the result of the week day is always 1.
NSDate *date2 = [[NSDate alloc] initWithString:[NSString stringWithFormat:#"%d-%d-%d", 2010, 6, 1]];
unsigned units2 = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekdayCalendarUnit;
NSCalendar *calendar2 = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components2 = [calendar2 components:units2 fromDate:date2];
int startWeekDay = [components2 weekday];
[date2 release];
[calendar2 release];
Creating an NSDateFormatter that only contains the weekday will do what you want.
NSDate *now = [NSDate date];
NSDateFormatter *weekday = [[[NSDateFormatter alloc] init] autorelease];
[weekday setDateFormat: #"EEEE"];
NSLog(#"The day of the week is: %#", [weekday stringFromDate:now]);
If you need internationalization, the NSDateFormatter can be sent a locale, which will give the proper translation.
The date formatters are controlled through this standard: Unicode Date Formats
Edit for Mac:
The format of the string has to be —YYYY-MM-DD HH:MM:SS ±HHMM according to the docs, all fields mandatory
Old answer (for iPhone and tested on simulator):
There is no (public) -initWithString: method in NSDate, and what you get returned is not what you expect.
Use a properly configured (you need to give the input format) NSDateFormatter and -dateFromString:.
I solved the problem, The problem was that the format of my date string was wrong:
NSDate *date = [[NSDate alloc] initWithString:[NSString stringWithFormat:#"%d-%d-%d 10:45:32 +0600", selectedYear, selectedMonth, selectedDay]];
and since i don't care about the time i randomly pass a time to the end of the string
I'm using Xcode 6.4
There are many ways to setup an NSDate. I won't go over that here. You've done it one way, using a string (A method I avoid due to it being very vulnerable to error), and I'm setting it another way. Regardless, access your components weekday or setDay methods.
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
[calendar setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en-US"]];
NSDateComponents *components = [calendar components:(NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekday|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond) fromDate:[NSDate date]];
NSDate *date = [calendar dateFromComponents:components];
this way, you can get or set any of these components like this:
[components weekday] //to get, then doSomething
[components setDay:6]; //to set
and, of course, set NSDate *date = [calendar dateFromComponents:components];only after you've changed the components.
I added in the extra local and other components for context in case you'd like to set those too.
It's free code, don't knock it.
Anyone coming here looking for a more recent Swift 4 solution:
extension Date {
func getDayOfWeek() -> String {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone.current
dateFormatter.locale = Locale(identifier: "en_US")
dateFormatter.setLocalizedDateFormatFromTemplate("EEEE")
return dateFormatter.string(from: self)
}
}
let inputString = "2018-04-16T15:47:39.000Z"
let result = inputString.getDayOfWeek()
result = Monday
Most upvoting answer in Swift 3.
let formatter = DateFormatter()
formatter.dateFormat = "EEEE"
print("The day of the week is \(formatter.string(from: Date()))")
I used the following website which helped with setting up the string to retrieve the format I wanted on my date
Coder Wall - Guide to objective c date formatting