NSDate get a specific day of the week? - iphone

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.

Related

How to subtract 30 minutes from a date

I am getting date value date: 2013-06-07 18:30:00 +0000. I am trying to subtract 30 minutes from this, but it not giving proper time.
I've tried this
NSTimeInterval secondsPerHour = 60*30;
NSDate *newDate = [date dateByAddingTimeInterval:-secondsPerHour];
Reason : The negative of a unsigned int is a positive number. This should work:
NSDate *newDate = [date dateByAddingTimeInterval:-(NSTimeInterval)((u_int32_t)30*60)];
EDIT : Alternative use NSDateComponents.
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setMinute:-30];
NSDate *halfHourAgo = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:yourDateHere options:0];
NSLog(#"\ncurrentDate: %# \n halfHourAgo: %#", yourDateHere, halfHourAgo);
in Swift 5
let minus30Min = Date().addingTimeInterval(-30 * 60)
you can use:
NSDate *minusOneHr = [[NSDate date] dateByAddingTimeInterval:-30*60];
You could try NSDateComponents, something like that:
NSDate* yourDate = [NSDate dateWithTimeIntervalSinceNow:0]; // your date, to substract 30 mins
NSDateComponents *dc = [[NSCalendar currentCalendar] components:(NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:yourDate];
[dc setMinute:[dc minute] - 30];
NSDate* date = [[NSCalendar currentCalendar] dateFromComponents:dc]; // 30 mins before now
Or that:
NSDate* yourDate = [NSDate dateWithTimeIntervalSinceNow:0]; // your date, to substract 30 mins
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setMinute:-30];
NSDate* date = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:yourDate options:0]; // 30 mins before now
Copy paste this code in viewDidLoad and check the results first.
NSDate *today = [[NSDate alloc] init];
NSLog(#"Today %#", today);
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setMinute:-30]; // If you want to change Month,Year,Day,Hour etc. Just change the "setMinute" to setMonth,setYear,setDay,setHour
NSDate *dateComp = [gregorian dateByAddingComponents:offsetComponents toDate:today options:0];
NSLog(#"Desired Day %#", dateComp);
let dateMinusThirtyMinutes = Date().subtract(30.minutes)

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);
}
}

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];

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

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.

NSDate gurus: my calculation method fails to produce consistent dates. Why?

I created a method to find the third Friday of every month.
When I run it from Eastern time zone, all is well.
When I run it from Central, the dates are off.
My method:
-(NSDate*) getSaturdayAfterThirdFriday:(NSDate*)date {
NSDate* resultDate = nil;
if( date != nil ) {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
// start at the 1st of the month
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSTimeZone *zone = [NSTimeZone timeZoneWithName:#"EST"];
[calendar setTimeZone:zone];
NSDateComponents *comp = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date];
[comp setDay:1];
date= [calendar dateFromComponents:comp];
[calendar release];
// count number of 'fri' (including today)
BOOL foundFlag = NO;
NSString* dateString = nil;
NSInteger count = 0;
[df setDateFormat:#"EEE"];
while (foundFlag == NO) {
dateString = [df stringFromDate:date];
if( [dateString caseInsensitiveCompare:#"fri"] == 0 ) {
count++;
NSLog(#"Found Friday: %#", [date description]);
}
if( count >= 3 ) foundFlag = YES;
else date = [NSDate dateWithTimeInterval:86400 sinceDate:date];
}
// get the next day (Saturday)
resultDate = [NSDate dateWithTimeInterval:86400 sinceDate:date];
[df release];
}
return resultDate;
}
The date that is passed is created with this method:
-(NSDate*) getDateForEasternTime:(NSDate*)date {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSTimeZone *zone = [NSTimeZone timeZoneWithName:#"EST"];
[calendar setTimeZone:zone];
NSDateComponents *comp = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date];
date = [calendar dateFromComponents:comp];
[calendar release];
NSLog(#"getDateForEasternTime: %#", [date description]);
return date;
}
I need to calculate dates based on Eastern Time only.
Here's my log output for Eastern time zone:
getDateForEasternTime: 2010-11-14 05:00:00 GMT
Found Friday: 2010-11-05 05:00:00 GMT
Found Friday: 2010-11-12 05:00:00 GMT
Found Friday: 2010-11-19 05:00:00 GMT
And for Central Time:
getDateForEasternTime: 2010-11-14 05:00:00 GMT
Found Friday: 2010-11-05 05:00:00 GMT
Found Friday: 2010-11-13 05:00:00 GMT
Found Friday: 2010-11-20 05:00:00 GMT
What's even more strange is that if I go further West in time zones, there is the discrepancy. If I go East in time zones there is none.
Any NSDate guru's can help with this?
Edit:
When I refer to changing the time zone, I'm talking about changing the time zone on the device itself. The line:
NSTimeZone *zone = [NSTimeZone timeZoneWithName:#"EST"];
Remains unchanged.
All your code is unnecessary. Using the weekday and weekdayOrdinal properties of NSDateComponents you can directly query a NSCalendar for the 3rd Friday of a month:
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setWeekday:6]; // 1 = Sunday ... 7 = Saturday
[components setWeekdayOrdinal:3]; // 3rd Friday
[components setMonth:11];
[components setYear:2010];
NSCalendar *currentCalendar = [NSCalendar currentCalendar];
NSDate *date = [currentCalendar dateFromComponents:components];
Also, there is almost the same example for this in the Developer Documentation.