I want to check if the current NSDate is 2 Weeks ahead of the another NSDate. I have can do somethings as below code but was wondering if there is any proper way to do.
[calendar rangeOfUnit:NSCalendarUnitDay startDate:¤tDate interval:NULL forDate:currentDate];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&previousDate interval:NULL forDate:previousDate];
NSDateComponents *difference = [calendar components:NSCalendarUnitDay fromDate:previousDate toDate:currentDate options:0];
if(diiference >= 14) {
}
You can use one trick here. First calculate number of days between 2 dates and then calculate number of weeks between them. You can do it like
-(NSInteger)weeksBetweenDate:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime {
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
interval:NULL forDate:fromDateTime];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
interval:NULL forDate:toDateTime];
NSDateComponents *difference = [calendar components:NSCalendarUnitDay
fromDate:fromDate toDate:toDate options:0];
return [difference day] / 7;
}
You can use CGFloat if you want to get week value like 1.5 and keep as it is if you want week count like 1,2,3,etc
Try this
objective C
+ (NSInteger)daysBetweenDate:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime
{
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
interval:NULL forDate:fromDateTime];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
interval:NULL forDate:toDateTime];
NSDateComponents *difference = [calendar components:NSCalendarUnitDay
fromDate:fromDate toDate:toDate options:0];
return [difference day];
}
Swift
extension NSDate {
func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int {
let calendar = NSCalendar.currentCalendar()
if let timeZone = timeZone {
calendar.timeZone = timeZone
}
var fromDate: NSDate?, toDate: NSDate?
calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self)
calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime)
let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: [])
return difference.day
}
}
Related
I have written like this to calculate hour difference.
+ (NSInteger)hoursBetweenDate:(NSDate*)fromDateTime andDate:(NSDate *)toDateTime
{
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[calendar rangeOfUnit:NSHourCalendarUnit startDate:&fromDate
interval:NULL forDate:fromDateTime];
[calendar rangeOfUnit:NSHourCalendarUnit startDate:&toDate
interval:NULL forDate:toDateTime];
NSDateComponents *difference = [calendar components:NSHourCalendarUnit
fromDate:fromDate toDate:toDate options:0];
return [difference hour];
}
Problem is that if input is like this,
2016-03-09 07:58:39 +0000 (fromDateTime)
2016-03-09 09:07:44 +0000 (toDateTime),
difference is always 2 hours. Actually, it should be 1 hour and 10 minute. As a result, I only want to show 1 hour. Is there a way to round up or down?
If you are just interested in the "unformatted" number of hours between to dates, you can use NSTimeInterval and calculate it easily.
+(int)fullHoursBetweenDate:(NSDate *)date1 andDate:(NSDate *)date2 {
NSTimeInterval interval = [date2 timeIntervalSinceDate:date1];
return (int)interval / 3600;
}
You extracted out only the hour component (NSHourCalendarUnit) before you compare, that's why it's always 2 (9 - 7). Added NSMinuteCalendarUnit the result would be 1:
+ (NSInteger)hoursBetweenDate:(NSDate*)fromDateTime andDate:(NSDate *)toDateTime
{
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[calendar rangeOfUnit:NSHourCalendarUnit|NSMinuteCalendarUnit startDate:&fromDate
interval:NULL forDate:fromDateTime];
[calendar rangeOfUnit:NSHourCalendarUnit|NSMinuteCalendarUnit startDate:&toDate
interval:NULL forDate:toDateTime];
NSDateComponents *difference = [calendar components:NSHourCalendarUnit
fromDate:fromDate toDate:toDate options:0];
return [difference hour];
}
Also, if you are targeting iOS 8+, you should use NSCalendarUnitHour and NSCalendarUnitMinute instead as NSHourCalendarUnit and NSMinuteCalendarUnit were deprecated.
This small NSCalendar extension should do a trick for you.
extension NSCalendar {
func hoursBetweenDates(startDate: NSDate, endDate: NSDate) -> Int {
let days = differenceInDates(startDate, endDate: endDate, unit: .Hour)
return days
}
func differenceInDates(startDate: NSDate, endDate: NSDate, unit: NSCalendarUnit) -> Int {
let startUnit = ordinalityOfUnit(unit, inUnit: .Era, forDate:startDate)
let endUnit = ordinalityOfUnit(unit, inUnit: .Era, forDate:endDate)
let difference = endUnit-startUnit
return difference
}
}
And Obj-C version can be written as follow:
#interface NSCalendar (Duration)
-(NSNumber *)hoursBetweenStartDate:(NSDate*)startDate andEndDate:(NSDate*) endDate;
#end
#implementation NSCalendar (Duration)
-(NSNumber *)hoursBetweenStartDate:(NSDate*)startDate andEndDate:(NSDate*) endDate {
NSUInteger startUnit = [self ordinalityOfUnit:NSCalendarUnitHour inUnit:NSCalendarUnitEra forDate:startDate];
NSUInteger endUnit = [self ordinalityOfUnit:NSCalendarUnitHour inUnit:NSCalendarUnitEra forDate:endDate];
return [NSNumber numberWithUnsignedInteger: (endUnit - startUnit)];
}
#end
Modify this function as per your requirement
+(NSString*)timeDifference:(NSDate*)startDate endDate:(NSDate*)endDate{
NSDateComponents *components;
NSInteger days;
NSInteger hour;
NSInteger minutes;
NSString *strDuration;
components = [[NSCalendar currentCalendar] components: NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute
fromDate: startDate toDate: endDate options: 0];
days = [components day];
hour=[components hour];
minutes=[components minute];
if(days>0){
if(days>1){
strDuration=[NSString stringWithFormat:#"%d days",days];
}
else{
strDuration=[NSString stringWithFormat:#"%d day",days];
}
return strDuration;
}
if(hour>0){
if(hour>1){
strDuration=[NSString stringWithFormat:#"%d hours",hour];
}
else{
strDuration=[NSString stringWithFormat:#"%d hour",hour];
}
return strDuration;
}
if(minutes>0){
if(minutes>1){
strDuration=[NSString stringWithFormat:#"%d minutes",minutes];
}
else{
strDuration=[NSString stringWithFormat:#"%d minute",minutes];
}
return strDuration;
}
return #"";
}
I have the following method which helps me determine if the current day is 3 days or less from the end of the month:
- (BOOL) checkMonthEnd {
NSDate *now = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *startOfToday;
[cal rangeOfUnit:NSCalendarUnitDay startDate:&startOfToday interval:NULL forDate:now];
NSDate *startOfNextMonth = ({
NSDate *startOfThisMonth;
NSTimeInterval lengthOfThisMonth;
[cal rangeOfUnit:NSCalendarUnitMonth startDate:&startOfThisMonth interval:&lengthOfThisMonth forDate:now];
[startOfThisMonth dateByAddingTimeInterval:lengthOfThisMonth];
});
NSDateComponents *comp = [cal components:NSCalendarUnitDay fromDate:startOfToday toDate:startOfNextMonth options:0];
if (comp.day < 4) {
return YES;
} else {
return NO;
}
}
What I would like to do is now modify it so that it shows me if the current date is within the first three days of the BEGINNING of the current month. How can I do this?
To determine if it's one of the first three days of the month, just retrieve NSCalendarUnitDay and see if it's less than 4:
- (BOOL) checkMonthStart {
NSDate *now = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:NSCalendarUnitDay fromDate:now];
return components.day < 4;
}
By the way, if checking whether you're within three days of the end of the month, I might suggest:
- (BOOL) checkMonthEnd {
NSDate *now = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:NSCalendarUnitDay fromDate:now];
NSRange range = [cal rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:now];
return (range.length - components.day) < 3;
}
How to get the first day of a week for a date
this seems more easy at it is, since :
when the week starts with sunday, i need to get back the sunday date
if it starts on monday, i need to get the monday date
the input date is any date in week with time... i tried several approaches, but the edge case make it difficould
i made a function, which however doesn't work in 100% (not sure about the [components setDay: -weekday + 2];)
- (NSDate *)firstDateOfWeek {
NSCalendar * calendar = [NSCalendar currentCalendar];
NSDateComponents *weekdayComponents = [calendar components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:self];
// because sunday is 0, we need it to be 6
NSInteger weekday = (([weekdayComponents weekday] + 6) % 7);
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:self];
[components setDay: -weekday + 2];
return [calendar dateFromComponents:components];
}
It is easier to use the rangeOfUnit calendar method, which handles "start of the week" correctly according to the current locale:
NSDate *date = your date;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *startOfWeek;
[calendar rangeOfUnit:NSWeekOfYearCalendarUnit
startDate:&startOfWeek
interval:NULL
forDate:date];
Using NSDateComponents, it would work as follows (assuming that a week has 7 days):
NSDate *date = your date;
NSDateComponents *comp = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit
fromDate:date];
NSDate *startOfDay = [calendar dateFromComponents:comp];
NSInteger diff = (NSInteger)[calendar firstWeekday] - (NSInteger)[comp weekday];
if (diff > 0)
diff -= 7;
NSDateComponents *subtract = [[NSDateComponents alloc] init];
[subtract setDay:diff];
NSDate *startOfWeek = [calendar dateByAddingComponents:subtract toDate:startOfDay options:0];
I'm struggling to figure out how to dynamically create a date object for the most previous sunday at 12:00 AM
I was thinking I could get today's date and then subtract the current day of the week + 1 at which point I could just subtract the time of the day do get down to 12AM.
so far I have the current day of the week:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [gregorian components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
int weekday = [comps weekday];
at which point I can get today's date and subtract the difference of weekday * seconds in a day. However, how can I get today's time in seconds ??
No need to manually calculate seconds (which is dangerous anyway because of daylight saving etc.). The following should do exactly what you want:
NSDate *today = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en-US"]]; // force US locale, because other countries (e.g. the rest of the world) might use different weekday numbering
NSDateComponents *nowComponents = [calendar components:NSYearCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:today];
[nowComponents setWeekday:1]; //Sunday
[nowComponents setHour:0]; // 12:00 AM = midnight (12:00 PM would be 12)
[nowComponents setMinute:0];
[nowComponents setSecond:0];
NSDate *previousSunday = [calendar dateFromComponents:nowComponents];
I'll leave worrying about transitions between daylight savings time to you:
NSCalendar *gregorian = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [NSDate date];
NSLog(#"date %#", date);
NSDateComponents *componentsToday = [gregorian components:NSWeekdayCalendarUnit fromDate:date]; // NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit |
NSInteger days = componentsToday.weekday - 1;
NSLog(#"Days=%d", days);
NSDate *lastSunday = [date dateByAddingTimeInterval:-days*60*60*24];
NSLog(#"lastSunday %#", lastSunday);
NSDateComponents *componentsSunday = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:lastSunday];
[componentsSunday setHour:0];
[componentsSunday setMinute:0];
[componentsSunday setSecond:0];
NSDate *targetDate = [gregorian dateFromComponents:componentsSunday];
NSLog(#"TargetDate %#", targetDate);
#AndreasLey solution in Swift 2.0:
func getLastSunday() -> NSDate?
{
let today = NSDate();
let calendar : NSCalendar! = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
calendar.locale = NSLocale(localeIdentifier: "en-US") // force US locale, because other countries (e.g. the rest of the world) might use different weekday numbering
let flags : NSCalendarUnit = [.Year , .Month, .Weekday, .WeekOfMonth, .Minute , .Second]
let nowComponents = calendar.components(flags, fromDate: today)
nowComponents.weekday = 1 //Sunday
nowComponents.hour = 0 // 12:00 AM = midnight (12:00 PM would be 12)
nowComponents.minute = 0
nowComponents.second = 0;
let previousSunday = calendar.dateFromComponents(nowComponents);
return previousSunday
}
This code is setting 12:00 am in your selected date from UIDatePicker.
NSDate *oldDateSelected = datePicker.date;
unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *comps = [calendar components:unitFlags fromDate:oldDateSelected];
comps.hour = 00;
comps.minute = 00;
comps.second = 44;
NSDate *newDate = [calendar dateFromComponents:comps];
return newDate;
I have a calendar application in which I want to get the next year from the current date (NSDate).
How can I do this?
You can make NSDateComponents do all the hard work of calculating leap years and leap seconds:
NSDate *today = [[NSDate alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setYear:1];
NSDate *nextYear = [gregorian dateByAddingComponents:offsetComponents toDate:today options:0];
As VdesmedT mentioned, you can use dateByAddingTimeInterval and add the seconds of one year. But to be more precise, you can do the following:
NSDate *today = [NSDate date]; // get the current date
NSCalendar* cal = [NSCalendar currentCalendar]; // get current calender
NSDateComponents* dateOnlyToday = [cal components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate:today];
[dateOnlyToday setYear:([dateOnlyToday year] + 1)];
NSDate *nextYear = [cal dateFromComponents:dateOnlyToday];
Hope this helps.
Swift 4:
let calendar = Calendar.current
let newDate = calendar.date(byAdding: .year, value: 1, to: Date())
This is my version: in swift.
let calendar = NSCalendar.currentCalendar()
let newDate = calendar.dateByAddingUnit(.Year, value: 1, toDate: NSDate(), options: NSCalendarOptions.MatchNextTime)