I have start date and a duration (period). For example startDate = '2014-02-12' period = 2. I desired dates 2014-02-12, 2014-02-14, 2014-02-16, .... I need to determine the current date is flagged during.
To check if the difference between the start date and the current date is an even
number of days, use NSDateComponents:
NSDate *startDate = ...;
NSDate *currentDate = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *diff = [cal components:NSDayCalendarUnit fromDate:startDate
toDate:currentDate options:0];
NSInteger days = diff.day;
if (days % 2 == 0) {
// even number of days between start date and current date
}
You can get the desired dates using
- (id)dateByAddingTimeInterval:(NSTimeInterval)seconds
with seconds = period*3600*24
Calc the days from startDate to givenData, check the result whether it can be divisible by the period.
+ (NSInteger)daysWithinEraFromDate:(NSDate *)startDate toDate:(NSDate *)endDate {
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
// for timezone issue
NSDate *newDate1 = [startDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSDate *newDate2 = [endDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSInteger startDay = [gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate1];
NSInteger endDay = [gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate2];
return endDay - startDay;
}
Related
Here's an example of what I want. The user may set up an alarm in my app for 1 minute in the future, so they can test it out. The time might be 19:23, so they'll set the alarm to 19:24, in which case I want it to be triggered on the next occurrence of 19:24 - in 1 minute's time.
If they set the alarm for 8am, I don't want it to set to 8am on the current day, but on the next occurrence of 8am - on following day.
How can I get it to aim for the next occurrence of the time chosen?
Assuming that the alarm time is given as "hour" and "minute", the following code
should produce the desired result:
NSDate *now = [NSDate date];
// Example values for testing:
NSUInteger alarmHour = 10;
NSUInteger alarmMinute = 5;
// Compute alarm time by replacing hour/minute of the current time
// with the given values:
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *comp = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit
fromDate:now];
[comp setHour:alarmHour];
[comp setMinute:alarmMinute];
NSDate *alarm = [cal dateFromComponents:comp];
// If alarm <= now ...
if ([alarm compare:now] != NSOrderedDescending) {
// ... add one day:
NSDateComponents *oneDay = [[NSDateComponents alloc] init];
[oneDay setDay:1];
alarm = [cal dateByAddingComponents:oneDay toDate:alarm options:0];
}
More tersely, what #HotLicks suggests:
NSDate *userEnteredDate;
NSDate *now = [NSDate date];
if (now == [now laterDate:userEnteredDate]) {
NSDateComponents *components = [[NSCalendar currentCalendar] components:255 fromDate:userEnteredDate]; // 255= the important component masks or'd together
components.day += 1;
userEnteredDate = [[NSCalendar currentCalendar] dateFromComponents:components];
}
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
NSDateFormatter *formatter_ = [[NSDateFormatter alloc]init];
NSDate *alarmDate = [formatter dateFromString:#"enter your users alarm time-examle(2345)"];
NSDate *currentDate = [NSDate date];
[formatter setDateFormat:#"HHmm"];
NSDate *finalDate;
if ([[formatter stringFromDate:currentDate] intValue] > [[formatter stringFromDate:alarmDate] intValue]) {
[formatter setDateFormat:#"HH:mm"];
[formatter_ setDateFormat:#"dd MM yyyy"];
NSDate *date = [currentDate dateByAddingTimeInterval:60*60*24*1];
finalDate = [formatter_ dateFromString:[NSString stringWithFormat:#"%# %#",[formatter stringFromDate:alarmDate],[formatter_ stringFromDate:date]]];
}else{
finalDate = [formatter_ dateFromString:[NSString stringWithFormat:#"%# %#",[formatter stringFromDate:alarmDate],[formatter_ stringFromDate:currentDate]]];
}
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)
I am new to iPhone.
I want to find out the next date from given date based on repeat period.
For example :
I want function as follows ...
given date : 31'May 2011 and Repeat : Monthly given as argument then the next date should be returned 31'July 2011 (as June don't have 31st day)
And function should be smart enough to to calculate next leap year day also, if given date : 29'Feb 2008 and Repeat : Yearly given as argument then the next date should be returned 29'Feb 2012 (The next leap year day)
And so on repeat option can be one of these : Daily, Weekly(On selected day of week), Monthly, Yearly, None(No repeat at all)
// start by retrieving day, weekday, month and year components for yourDate
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *todayComponents = [gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) yourDate];
NSInteger theDay = [todayComponents day];
NSInteger theMonth = [todayComponents month];
NSInteger theYear = [todayComponents year];
// now build a NSDate object for yourDate using these components
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:theDay];
[components setMonth:theMonth];
[components setYear:theYear];
NSDate *thisDate = [gregorian dateFromComponents:components];
[components release];
// now build a NSDate object for the next day
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setDay:1];
NSDate *nextDate = [gregorian dateByAddingComponents:offsetComponents toDate: yourDate options:0];
[offsetComponents release];
[gregorian release];
This is copied from How can i get next date using NSDate? and the credit goes to #Massimo Cafaro for this answer.
To get tomorrow's date use the dateByAddingTimeInterval method.
// Start with today
NSDate *today = [NSDate date];
// Add on the number of seconds in a day
NSTimeInterval oneDay = 60 * 60 * 24;
NSDate *tomorrow = [today dateByAddingTimeInterval:oneDay];
It's pretty simple to extend that to a week etc
NSTimeInterval oneWeek = oneDay * 7;
NSDate *nextWeek = [today dateByAddingTimeInterval:oneWeek];
try this :-
- (NSDate *)dateFromDaysOffset:(NSInteger)daysOffset
{
// start by retrieving day, weekday, month and year components for yourDate
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setDay:daysOffset];
NSDate *offsetDate = [gregorian dateByAddingComponents:offsetComponents toDate:self options:0];
[offsetComponents release];
[gregorian release];
return offsetDate;
}
I have a class that holds an start date and an end date, normally initialised to the firt and last second of the month.
The following function works correctly going from Nov 2010 forwards into December and back again however going backwards from November ends up with startDate set to
2010-09-30 23:00:00 GMT
Ie. a month and an hour ago.
Strangely the endDate is still correctly set to
2010-11-01 00:00:00 GMT
And going forward a month from this incorrect date also results in the correct time and date.
Is this a bug or am I doing something I shouldn't be ?
-(void) moveMonth:(NSInteger)byAmount { // Positive or negative number of months
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
// Update the start date
[components setMonth:byAmount];
NSDate *newStartDate = [cal dateByAddingComponents:components toDate:[self startDate] options:0];
[self setStartDate:newStartDate];
// And the end date
[components setMonth:1];
NSDate *newEndDate = [cal dateByAddingComponents:components toDate:[self startDate] options:0 ];
[self setEndDate:newEndDate];
}
SOLUTION: Answer correctly pointed out this is a DST issue
If you want to deal in absolute times and date then using the following avoids any DST being involved.
NSCalendar *cal = [[NSCalendar alloc ] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSTimeZone *zone = [NSTimeZone timeZoneWithName:#"GMT"];
[cal setTimeZone:zone];
It is probably not a bug but something related to DST changes in October-November period.
It would be easier to just grab the month and year of the current date, add/subtract the number of months difference, then generate a date from those new values. No need to worry about Daylight Saving changes, leap years, etc. Something like this ought to work:
-(void) moveMonth:(NSInteger)byAmount {
NSDate *now = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
// we're just interested in the month and year components
NSDateComponents *nowComps = [cal components:(NSYearCalendarUnit|NSMonthCalendarUnit)
fromDate:now];
NSInteger month = [nowComps month];
NSInteger year = [nowComps year];
// now calculate the new month and year values
NSInteger newMonth = month + byAmount;
// deal with overflow/underflow
NSInteger newYear = year + newMonth / 12;
newMonth = newMonth % 12;
// month is 1-based, so if we've ended up with the 0th month,
// make it the 12th month of the previous year
if (newMonth == 0) {
newMonth = 12;
newYear = newYear - 1;
}
NSDateComponents *newStartDateComps = [[NSDateComponents alloc] init];
[newStartDateComps setYear: year];
[newStartDateComps setMonth: month];
[self setStartDate:[cal dateFromComponents:newDateComps]];
[newDateComps release];
// Calculate newEndDate in a similar fashion, calling setMinutes:59,
// setHour:23, setSeconds:59 on the NSDateComponents object if you
// want the last second of the day
}
Here is a way to do it properly. This method returns a new NSDate after adding/subtracting month "byAmount".
-(NSDate*) moveMonth:(NSInteger)byAmount {
NSDate *now = [NSDate date];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setMonth:byAmount];
NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:now options:0];
return newDate;
}
I'm writing a GTD app for the iPhone. For the due tasks, I want to display something like "Due tomorrow" or "Due yesterday" or "Due July 18th". Obviously, I need to display "Tomorrow" even if the task is less than 24 hours away (e.g. the user checks at 11pm on Saturday and sees there's a task on Sunday at 8am). So, I wrote a method to get the number of days in between two dates. Here's the code...
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd-HH-mm"];
NSDate *nowDate = [dateFormatter dateFromString:#"2010-01-01-15-00"];
NSDate *dueDate = [dateFormatter dateFromString:#"2010-01-02-14-00"];
NSLog(#"NSDate *nowDate = %#", nowDate);
NSLog(#"NSDate *dueDate = %#", dueDate);
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *differenceComponents = [calendar components:(NSDayCalendarUnit)
fromDate:nowDate
toDate:dueDate
options:0];
NSLog(#"Days between dates: %d", [differenceComponents day]);
... and here's the output:
NSDate *nowDate = 2010-01-01 15:00:00 -0700
NSDate *dueDate = 2010-01-02 14:00:00 -0700
Days between dates: 0
As you can see, the method returns incorrect results. It should have returned 1 as the number of days between the two days. What am I doing wrong here?
EDIT: I wrote another method. I haven't done extensive unit tests, but so far it seems to work:
+ (NSInteger)daysFromDate:(NSDate *)fromDate inTimeZone:(NSTimeZone *)fromTimeZone untilDate:(NSDate *)toDate inTimeZone:(NSTimeZone *)toTimeZone {
NSCalendar *calendar = [NSCalendar currentCalendar];
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
[calendar setTimeZone:fromTimeZone];
NSDateComponents *fromDateComponents = [calendar components:unitFlags fromDate:fromDate];
[calendar setTimeZone:toTimeZone];
NSDateComponents *toDateComponents = [calendar components:unitFlags fromDate:toDate];
[calendar setTimeZone:[NSTimeZone defaultTimeZone]];
NSDate *adjustedFromDate = [calendar dateFromComponents:fromDateComponents];
NSDate *adjustedToDate = [calendar dateFromComponents:toDateComponents];
NSTimeInterval timeIntervalBetweenDates = [adjustedToDate timeIntervalSinceDate:adjustedFromDate];
NSInteger daysBetweenDates = (NSInteger)(timeIntervalBetweenDates / (60.0 * 60.0 * 24.0));
NSDateComponents *midnightBeforeFromDateComponents = [[NSDateComponents alloc] init];
[midnightBeforeFromDateComponents setYear:[fromDateComponents year]];
[midnightBeforeFromDateComponents setMonth:[fromDateComponents month]];
[midnightBeforeFromDateComponents setDay:[fromDateComponents day]];
NSDate *midnightBeforeFromDate = [calendar dateFromComponents:midnightBeforeFromDateComponents];
[midnightBeforeFromDateComponents release];
NSDate *midnightAfterFromDate = [[NSDate alloc] initWithTimeInterval:(60.0 * 60.0 * 24.0)
sinceDate:midnightBeforeFromDate];
NSTimeInterval timeIntervalBetweenToDateAndMidnightBeforeFromDate = [adjustedToDate timeIntervalSinceDate:midnightBeforeFromDate];
NSTimeInterval timeIntervalBetweenToDateAndMidnightAfterFromDate = [adjustedToDate timeIntervalSinceDate:midnightAfterFromDate];
if (timeIntervalBetweenToDateAndMidnightBeforeFromDate < 0.0) {
// toDate is before the midnight before fromDate
timeIntervalBetweenToDateAndMidnightBeforeFromDate -= daysBetweenDates * 60.0 * 60.0 * 24.0;
if (timeIntervalBetweenToDateAndMidnightBeforeFromDate < 0.0)
daysBetweenDates -= 1;
}
else if (timeIntervalBetweenToDateAndMidnightAfterFromDate >= 0.0) {
// toDate is after the midnight after fromDate
timeIntervalBetweenToDateAndMidnightAfterFromDate -= daysBetweenDates * 60.0 * 60.0 * 24.0;
if (timeIntervalBetweenToDateAndMidnightAfterFromDate >= 0.0)
daysBetweenDates += 1;
}
[midnightAfterFromDate release];
return daysBetweenDates;
}
From the docs for components:fromDate:toDate:options::
The result is lossy if there is not a small enough unit requested to hold the full precision of the difference.
Since the difference is less than a full day, it correctly returns a result of 0 days.
If all you care about is tomorrow or yesterday vs. a specific date, then you can save yourself a lot of work and just test whether the dates are only one calendar day apart.
To do that, compare the dates to find which is earlier and which is later (and if they compare equal, bail out with that result), then test whether 1 day after the earlier date produces a date with the same year, month, and day-of-month as the later date.
If you really do want to know exactly how many calendar days there are from one date to the other:
Send the calendar a components:fromDate: message to get the year, month, and day-of-the-month of the first date.
Same as #1, but for the second date.
If the two dates are in the same year and month, subtract one day-of-month from the other and pass to abs (see abs(3)) to take the absolute value.
If they are not in the same year and month, test whether they are in adjacent months (e.g., December 2010 to January 2011, or June 2010 to July 2010). If they are, add the number of days in the earlier date's month (which you can obtain by sending the calendar a rangeOfUnit:inUnit:forDate: message, passing NSDayCalendarUnit and NSMonthCalendarUnit, respectively) to the day-of-month of the later date, then compare that result to the earlier date's day-of-month.
For example, when comparing 2010-12-31 to 2011-01-01, you would first determine that these are in adjacent months, then add 31 (number of days in 2010-12) to 1 (day-of-month of 2011-01-01), then subtract 31 (day-of-month of 2010-12-31) from that sum. Since the difference is 1, the earlier date is one day before the later date.
When comparing 2010-12-30 to 2011-01-02, you would determine that they are in adjacent months, then add 31 (days in 2010-12) to 2 (day-of-month of 2011-01-02), then subtract 30 (day-of-month of 2010-12-30) from that sum. 33 minus 30 is 3, so these dates are three calendar days apart.
Either way, I strongly suggest writing unit tests at least for this code. I've found that date-handling code is among the most likely to have subtle bugs that only manifest, say, twice a year.
One thing you might try is using rangeOfUnit: to zero out hours, minutes and seconds from the start and end dates.
NSCalendar *calendar = [NSCalendar currentCalendar];
NSCalendarUnit range = NSDayCalendarUnit;
NSDateComponents *comps = [[NSDateComponents alloc] init];
NSDate *start = [NSDate date];
NSDate *end;
[comps setDay:1];
[calendar rangeOfUnit:range startDate:&start interval:nil forDate:start];
end = [calendar dateByAddingComponents:comps toDate:start options:0];
In this example start will be 2010-06-19 00:00:00 -0400, end will be 2010-06-20 00:00:00 -0400. I'd imagine this would work better with NSCalendar's comparison methods, although I haven't tested it myself.
I am using this piece of code, it is working very well:
- (NSInteger)daysToDate:(NSDate*)date
{
if(date == nil) {
return NSNotFound;
}
NSUInteger otherDay = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date];
NSUInteger currentDay = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:self];
return (otherDay-currentDay);
}
Here is the function I've used in the past
its defined in a category on NSDate
- (int) daysToDate:(NSDate*) endDate
{
//dates needed to be reset to represent only yyyy-mm-dd to get correct number of days between two days.
NSDateFormatter *temp = [[NSDateFormatter alloc] init];
[temp setDateFormat:#"yyyy-MM-dd"];
NSDate *stDt = [temp dateFromString:[temp stringFromDate:self]];
NSDate *endDt = [temp dateFromString:[temp stringFromDate:endDate]];
[temp release];
unsigned int unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [gregorian components:unitFlags fromDate:stDt toDate:endDt options:0];
int days = [comps day];
[gregorian release];
return days;
}
-(NSInteger)daysBetweenTwoDates:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime
{
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&fromDate
interval:NULL forDate:fromDateTime];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&toDate
interval:NULL forDate:toDateTime];
NSDateComponents *difference = [calendar components:NSDayCalendarUnit
fromDate:fromDate toDate:toDate options:0];
return [difference day];
}