obj-C, why does this give me yesterdays date? - iphone

I've been struggling with my function to return todays date, at as close to zero seconds, minutes and hours as possible. So I'm able to re-use the same date with various transactions.
However, I've now discovered that my function returns yesterdays date?
+ (NSDate *)makeAbsoluteNSDate:(NSDate*)datSource {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:
NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents *dateComponents = [calendar components:NSYearCalendarUnit |
NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:datSource];
[dateComponents setHour:0];
[dateComponents setMinute:0];
[dateComponents setSecond:0];
NSDate *today = [calendar dateFromComponents:dateComponents];
[calendar release];
return today;
}

If you're trying to get today's or yesterday's midnight in your time zone, you should get NSDate that points to adequate time in GMT. In my case -2 hours as my timezone is +0200, so for midnight of 2011-08-26 I'll get 2011-08-25 22:00.
You have to make sure that you're setting the right timezone for the NSCalendar, which is [NSTimeZone systemTimeZone].
My routine for getting the midnight in my time zone is:
+ (NSDate *)midnightOfDate:(NSDate *)date {
NSCalendar *cal = [NSCalendar currentCalendar];
[cal setTimeZone:[NSTimeZone systemTimeZone]];
NSDateComponents *components = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date];
[components setTimeZone:[cal timeZone]];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
return [cal dateFromComponents:components];
}
So, after a long discussion in comments, here's a midday function:
+ (NSDate *)middayOfDate:(NSDate *)date {
NSCalendar *cal = [NSCalendar currentCalendar];
[cal setTimeZone:[NSTimeZone systemTimeZone]];
NSDateComponents *components = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date];
[components setTimeZone:[cal timeZone]];
[components setHour:12];
[components setMinute:0];
[components setSecond:0];
return [cal dateFromComponents:components];
}

Use below function to get date for yesterday :
- (NSDate *)getDate:(NSDate *)date days:(NSInteger)days hours:(NSInteger)hours mins:(NSInteger)mins seconds:(NSInteger)seconds
{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:[[NSDate alloc] init]];
days = (days*24) + hours;
[components setHour:days];
[components setMinute:mins];
[components setSecond:seconds];
NSDate *returnDate = [cal dateByAddingComponents:components toDate:date options:0];
return returnDate;
}
To get yesterday date pass date = [NSDate date], day = -1, hours = 0 and mins = 0 as parameters in method calling.

All you need is [NSDate date] for the current date & time.

Related

NSDateComponents don't change hour component correctly

i can't understand why i can't change the hour of a NSDate correctly, using NSDateComponents, i'll do it in this way:
NSDateComponent components = [calendar components: (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:today];
[components setMinute:myMinute];
[components setHour:7];
NSDate *myNewDate = [calendar dateFromComponents:components];
NSLog(#"%#",myNewDate);
but the NSLog is this:
2012-12-08 06:00:00 +0000
there is one hour of difference, i have set 7 but is 6 anyone can help me?
its the timezone - the NSDate is printed with GMT time as it has no notion of timezones
use
[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
to make the components GMT and reflect your time set
working example
int main(int argc, char *argv[]) {
#autoreleasepool {
NSDate *today = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components: (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:today];
[components setMinute:50];
[components setHour:7];
[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSDate *myNewDate = [calendar dateFromComponents:components];
NSLog(#"%#",myNewDate);
}
}

How do I get the day of the week with NSCalendar?

I want to get the day of the week, preferable in an integer from 1 to 7... is this possible?
This is what I currently have to get the current hour, minute and second....
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [gregorian components:(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:[NSDate date]];
NSInteger hour = [dateComponents hour];
NSInteger minute = [dateComponents minute];
NSInteger second = [dateComponents second];
You can use this:
NSDateComponents *weekdayComponents =[gregorian components:NSWeekdayCalendarUnit fromDate:myDate];
NSInteger weekday = [weekdayComponents weekday];
Or to integrate with the code you already have:
NSDateComponents *dateComponents = [gregorian components:(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate:[NSDate date]];
NSInteger weekday = [dateComponents weekday];
That will get you values 1 .. 7 where 1 is Sunday.
Hope that helps.

Forming a predicate to filter between dates

Say I have two dates:
minDate:2012-08-29 12:22:17 +0000
maxDate:2011-12-01 18:14:38 +0000
I have a Core Data object called MBDate which has an NSDate property. I want to get all MBDate's with days including and in between the days above. So it should disregard the hours, seconds, and minutes, and just get all days in between and including 8/29 - 12/01.
Something like:
predicate = [NSPredicate predicateWithFormat:#"date < %# AND date > %#", maxDate, minDate];
But I'm not sure how I would tell it to disregard the hours and minutes and just look at the days. Any ideas?
You could use NSDateComponents to set a 'low' and 'high' date and use these in your predicate.
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
gregorian.timeZone = [NSTimeZone timeZoneWithAbbreviation"#"UTC"];
NSDateComponents *dateComponents = [gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:minDate];
[dateComponents setHour:0];
[dateComponents setMinute:0];
[dateComponents setSecond:0];
NSDate *lowDate = [gregorian dateFromComponents:dateComponents];
dateComponents = [gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:maxDate];
[dateComponents setHour:23];
[dateComponents setMinute:59];
[dateComponents setSecond:59];
NSDate *highDate = [gregorian dateFromComponents:dateComponents];

How to get NSDate for 00:00 on the day of [NSDate date]?

I need to get an NSDate object for 00:00(beginning of the day) from [NSDate date], let's say if currently it is 11:30am(returned by [NSDate date]), on 01/06/2012, now I need to have an NSDate for 00:00am on 01/06/2012.
I haven't tried this, but what is in my mind is:
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:now];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
NSDate *morningStart = [calendar dateFromComponents:components];
So I first get current date(say it is 01/06/2012), and construct a NSDateComponent for the date, then I set hour/minute/second to 0 and the year/month/day should not be changed(ie. 01/06/2012) then I create an NSDate for this component setting and can I get a date of 00:00:00 01/06/2012?
What you doing is correct, but when you NSLog morningStart the date will be displayed in GMT time zone
If you wanna make sure that the date is correct, convert it to NSString
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MMM-dd HH:mm:ss"];
NSString *strFromDate = [formatter stringFromDate:morningStart]; // this will return 2012-Jun-21 00:00:00
Converting NSDate to NSString can be helpful but if you need to keep a NSDate object for further processing, here is your solution to have your real morningStart NSDate object set at 00:00:00 time, with care of the timezone as well... As you will see you were not so far from the solution :
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now];
NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
int timeZoneOffset = [destinationTimeZone secondsFromGMTForDate:now] / 3600;
[components setHour:timeZoneOffset];
[components setMinute:0];
[components setSecond:0];
NSDate *morningStart = [calendar dateFromComponents:components];
It's very easy to do this in iOS8 using startOfDayForDate:
let date = NSDate()
let calendar = NSCalendar.currentCalendar(calendarIdentifier: NSGregorianCalendar)
let dateAtStartOfDay = calendar.startOfDayForDate(date)
OR you may do it in the traditional way in Swift as follows:
let date = NSDate()
let calendar = NSCalendar.currentCalendar(calendarIdentifier: NSGregorianCalendar)
// Use a mask to extract the required components from today's date
let components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: date)
let dateAtStartOfDay = calendar.dateFromComponents(components)!
print(dateAtStartOfDay)
(Note: NSDates are stored relative to GMT. So print will display the relative local time. A clear understanding of TimeZone's is essential to using NSDates properly.)

NSDate get a specific day of the week?

I hope this is just a learning curve I'm going through.
I create an arbitrary date. I want to find the Saturday following the third Friday.
NSLog(#"Date: %#", [date description]);
NSCalendar *calendar = [NSCalendar currentCalendar];
NSTimeZone *zone = [NSTimeZone timeZoneWithName:#"EST"];
[calendar setTimeZone:zone];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date];
[components setWeekday:6]; // 1 = Sunday ... 7 = Saturday
[components setWeekdayOrdinal:3]; // 3rd Friday
resultDate = [calendar dateFromComponents:components];
NSLog(#"Date: %#", [resultDate description]);
And the output:
Date: 2010-11-01 05:00:00 GMT
Date: 2010-11-01 05:00:00 GMT
Why? How can I fix this?
// Sunday = 1, Saturday = 7
int weekday = [[[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate: date] weekday];
Change the components to:
(NSWeekdayCalendarUnit | NSYearCalendarUnit)
This works:
NSDate *today = [[NSDate alloc] init];
NSLog([today description]);
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents = [gregorian components:(NSWeekdayCalendarUnit | NSWeekdayOrdinalCalendarUnit) fromDate:today];
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
[componentsToSubtract setDay: 0 - ([weekdayComponents weekday])];
[componentsToSubtract setWeekdayOrdinal:([weekdayComponents weekday] <= 6) ? 3 : 4];
//[componentsToSubtract setWeekdayOrdinal:3]; //old way - not perfect
NSDate *saturday = [gregorian dateByAddingComponents:componentsToSubtract toDate:today options:0];
NSDateComponents *components =
[gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate: saturday];
saturday = [gregorian dateFromComponents:components];
NSLog([saturday description]);
Hope this helps.