0

Giving an example, I have 2 NSDate in the same timezone UTC

NSDate *date1 = [NSDate dateWithString:@"2019-05-31 22:00:00 +0000"];
NSDate *date2 = [NSDate dateWithString:@"2019-06-01 01:00:00 +0000"];

I want to make a function to calculate difference between them in Year, month, day ignore time part. Expect result above

Year: 0

Month: 1

Day: 1

Or another example with

NSDate *date1 = [NSDate dateWithString:@"2019-02-28 22:00:00 +0000"];
NSDate *date2 = [NSDate dateWithString:@"2020-03-01 01:00:00 +0000"];

Will get result

Year: 1

Month: 13

Day: 367

I have tried answers in this question How can I calculate the difference between two dates?

But those approach using NSTimeInterval seems not reliable because of 365 or 366 days of year and does not ignore time. Answer like

NSDateComponents *components;
NSInteger days;

components = [[NSCalendar currentCalendar] components: NSDayCalendarUnit 
    fromDate: date1 toDate: date2 options: 0];
days = [components day];

Give wrong result too.

Community
  • 1
  • 1
Bùi Đức Khánh
  • 3,975
  • 6
  • 27
  • 43
  • The difference of the first example is 3 hours that means 0 month and 0 day. The result of the second example is 1 year 0 month 1 day. You will never get month > 12 if unit year is specified and day > 365 if unit month is specified. And `dateWithString` API is deprecated for a long time. – vadian Jun 30 '19 at 09:10
  • @Vadian I want to compare based on calendar value. On the first example date1 is on May and date2 is on June so result I want is 1. Same with day – Bùi Đức Khánh Jun 30 '19 at 09:13
  • Don't care about `dateWithString` too, I use it to demonstrate for `NSDate` value only – Bùi Đức Khánh Jun 30 '19 at 09:17
  • 1
    You can compare two dates [to unit granularity](https://developer.apple.com/documentation/foundation/nscalendar/1415661-compare). But you can only specify one unit and the result is greater, same of less. – vadian Jun 30 '19 at 09:20
  • @Vadian thank, but I want to get difference by number – Bùi Đức Khánh Jun 30 '19 at 09:22
  • Then you have to write your own algorithm. All (NS)Calendar based calculations will return 2 years 1 month rather than 1 year 13 months – vadian Jun 30 '19 at 09:27

1 Answers1

1

You could convert each NSDate value to an NSDateComponents value using NSCalendar's componentsInTimeZone:fromDate: method. This will give you the year, month and day values for your two dates, now implement your difference algorithm, which might be:

  • subtract the earlier date from the larger one - you can determine that based on comparing the two NSDate values
  • the year difference is just simple subtraction of the year components of the NSDateComponents values
  • the month difference is the difference between the month components, if this is negative add 12
  • the day difference is similar but in the negative case you have to add the length of month, which is 28, 29, 30 or 31 - figuring which is left as an exercise :-) (NSCalendar/NSDate Methods should help here)

While this guess at your required algorithm might be wrong, whatever your algorithm you should be able to implement it based on the year, month and day components. HTH

Update

So my first guess at your algorithm was wrong, my second guess is that your three differences; years, months, days; are all meant to be independent approximations of the difference in the corresponding unit. So the year difference ignores the months, days and time; the month difference ignores the days and time; and the days difference ignores the time. This is why 31 May and 1 June are "1 month" apart - the day is ignored. This guess may also be wrong of course but here is how to do it:

  • order you two dates so the difference is going to be positive.
  • get just the year, month and day components (or get them all and then discard the others) – this will discard the time component. Use one of NSCalendar's methods to do this.
  • your year difference is just the difference between the year components
  • your month difference is the difference between your month components (which could be negative) plus 12 times your year difference
  • your day difference can be found using components:fromDateComponents:toDateComponents:options: requesting only the day component

[Note: be careful to use the same timezone as the original dates – this is a bit fiddly as you may need to extract it from the date strings yourself (extract the +hhmm and make a time zone). You must remember that an NSDate does not store the time zone, its just an absolute point in time (so equivalent times in different times zones produce the same NSDate value) and for your calculations you want them based on the original time zone as two times one the same day in one timezone can be on different days in a different time zone...). You can set the timezone of an NSCalendar instance or use methods which take timezones when converting from NSDate to NSDateComponents]

CRD
  • 52,522
  • 5
  • 70
  • 86
  • Thank you. I'm trying to do like your suggestion but I post this question here and hope for handful way – Bùi Đức Khánh Jun 30 '19 at 15:33
  • 1
    @BùiĐứcKhánh – I've had another *guess* at what you're after, the algorithm produces the same results as your two examples. Of course you should really specify the definition of "difference" you want rather than give a couple of examples so people have to try and guess to help you. Hope this one helps. – CRD Jun 30 '19 at 18:04