NSDate+Utilities.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /*
  2. Erica Sadun, http://ericasadun.com
  3. iPhone Developer's Cookbook 3.x and beyond
  4. BSD License, Use at your own risk
  5. */
  6. /*
  7. #import <humor.h> : Not planning to implement: dateByAskingBoyOut and dateByGettingBabysitter
  8. ----
  9. General Thanks: sstreza, Scott Lawrence, Kevin Ballard, NoOneButMe, Avi`, August Joki. Emanuele Vulcano, jcromartiej, Blagovest Dachev, Matthias Plappert, Slava Bushtruk, Ali Servet Donmez, Ricardo1980, pip8786, Danny Thuerin, Dennis Madsen
  10. Include GMT and time zone utilities?
  11. */
  12. #import "NSDate+Utilities.h"
  13. // Thanks, AshFurrow
  14. static const unsigned componentFlags = (NSCalendarUnitYear |
  15. NSCalendarUnitMonth |
  16. NSCalendarUnitDay |
  17. NSCalendarUnitHour |
  18. NSCalendarUnitMinute|
  19. NSCalendarUnitSecond|
  20. NSCalendarUnitWeekday |
  21. NSCalendarUnitWeekdayOrdinal);
  22. @implementation NSDate (Utilities)
  23. // Courtesy of Lukasz Margielewski
  24. // Updated via Holger Haenisch
  25. + (NSCalendar *) currentCalendar
  26. {
  27. static NSCalendar *sharedCalendar = nil;
  28. if (!sharedCalendar)
  29. sharedCalendar = [NSCalendar autoupdatingCurrentCalendar];
  30. return sharedCalendar;
  31. }
  32. #pragma mark - Relative Dates
  33. + (NSDate *) dateWithDaysFromNow: (NSInteger) days
  34. {
  35. // Thanks, Jim Morrison
  36. return [[NSDate date] dateByAddingDays:days];
  37. }
  38. + (NSDate *) dateWithDaysBeforeNow: (NSInteger) days
  39. {
  40. // Thanks, Jim Morrison
  41. return [[NSDate date] dateBySubtractingDays:days];
  42. }
  43. + (NSDate *) dateTomorrow
  44. {
  45. return [NSDate dateWithDaysFromNow:1];
  46. }
  47. + (NSDate *) dateYesterday
  48. {
  49. return [NSDate dateWithDaysBeforeNow:1];
  50. }
  51. + (NSDate *) dateWithHoursFromNow: (NSInteger) dHours
  52. {
  53. NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_HOUR * dHours;
  54. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  55. return newDate;
  56. }
  57. + (NSDate *) dateWithHoursBeforeNow: (NSInteger) dHours
  58. {
  59. NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_HOUR * dHours;
  60. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  61. return newDate;
  62. }
  63. + (NSDate *) dateWithMinutesFromNow: (NSInteger) dMinutes
  64. {
  65. NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes;
  66. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  67. return newDate;
  68. }
  69. + (NSDate *) dateWithMinutesBeforeNow: (NSInteger) dMinutes
  70. {
  71. NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_MINUTE * dMinutes;
  72. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  73. return newDate;
  74. }
  75. #pragma mark - String Properties
  76. - (NSString *) stringWithFormat: (NSString *) format
  77. {
  78. NSDateFormatter *df = [NSDateFormatter new];
  79. // formatter.locale = [NSLocale currentLocale]; // Necessary?
  80. df.dateFormat = format;
  81. return [df stringFromDate:self];
  82. }
  83. - (NSString *) stringWithDateStyle: (NSDateFormatterStyle) dateStyle timeStyle: (NSDateFormatterStyle) timeStyle
  84. {
  85. NSDateFormatter *df = [NSDateFormatter new];
  86. df.dateStyle = dateStyle;
  87. df.timeStyle = timeStyle;
  88. // formatter.locale = [NSLocale currentLocale]; // Necessary?
  89. return [df stringFromDate:self];
  90. }
  91. - (NSString *) shortString
  92. {
  93. return [self stringWithDateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterShortStyle];
  94. }
  95. - (NSString *) shortTimeString
  96. {
  97. return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterShortStyle];
  98. }
  99. - (NSString *) shortDateString
  100. {
  101. return [self stringWithDateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterNoStyle];
  102. }
  103. - (NSString *) mediumString
  104. {
  105. return [self stringWithDateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle ];
  106. }
  107. - (NSString *) mediumTimeString
  108. {
  109. return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterMediumStyle ];
  110. }
  111. - (NSString *) mediumDateString
  112. {
  113. return [self stringWithDateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle];
  114. }
  115. - (NSString *) longString
  116. {
  117. return [self stringWithDateStyle:NSDateFormatterLongStyle timeStyle:NSDateFormatterLongStyle ];
  118. }
  119. - (NSString *) longTimeString
  120. {
  121. return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterLongStyle ];
  122. }
  123. - (NSString *) longDateString
  124. {
  125. return [self stringWithDateStyle:NSDateFormatterLongStyle timeStyle:NSDateFormatterNoStyle];
  126. }
  127. #pragma mark - Comparing Dates
  128. - (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate
  129. {
  130. NSDateComponents *components1 = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  131. NSDateComponents *components2 = [[NSDate currentCalendar] components:componentFlags fromDate:aDate];
  132. return ((components1.year == components2.year) &&
  133. (components1.month == components2.month) &&
  134. (components1.day == components2.day));
  135. }
  136. - (BOOL) isToday
  137. {
  138. return [self isEqualToDateIgnoringTime:[NSDate date]];
  139. }
  140. - (BOOL) isTomorrow
  141. {
  142. return [self isEqualToDateIgnoringTime:[NSDate dateTomorrow]];
  143. }
  144. - (BOOL) isYesterday
  145. {
  146. return [self isEqualToDateIgnoringTime:[NSDate dateYesterday]];
  147. }
  148. // This hard codes the assumption that a week is 7 days
  149. - (BOOL) isSameWeekAsDate: (NSDate *) aDate
  150. {
  151. NSDateComponents *components1 = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  152. NSDateComponents *components2 = [[NSDate currentCalendar] components:componentFlags fromDate:aDate];
  153. // Must be same week. 12/31 and 1/1 will both be week "1" if they are in the same week
  154. if (components1.weekOfMonth != components2.weekOfMonth) return NO;
  155. // Must have a time interval under 1 week. Thanks @aclark
  156. return (fabs([self timeIntervalSinceDate:aDate]) < D_WEEK);
  157. }
  158. - (BOOL) isThisWeek
  159. {
  160. return [self isSameWeekAsDate:[NSDate date]];
  161. }
  162. - (BOOL) isNextWeek
  163. {
  164. NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_WEEK;
  165. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  166. return [self isSameWeekAsDate:newDate];
  167. }
  168. - (BOOL) isLastWeek
  169. {
  170. NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_WEEK;
  171. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  172. return [self isSameWeekAsDate:newDate];
  173. }
  174. // Thanks, mspasov
  175. - (BOOL) isSameMonthAsDate: (NSDate *) aDate
  176. {
  177. NSDateComponents *components1 = [[NSDate currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth fromDate:self];
  178. NSDateComponents *components2 = [[NSDate currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth fromDate:aDate];
  179. return ((components1.month == components2.month) &&
  180. (components1.year == components2.year));
  181. }
  182. - (BOOL) isThisMonth
  183. {
  184. return [self isSameMonthAsDate:[NSDate date]];
  185. }
  186. // Thanks Marcin Krzyzanowski, also for adding/subtracting years and months
  187. - (BOOL) isLastMonth
  188. {
  189. return [self isSameMonthAsDate:[[NSDate date] dateBySubtractingMonths:1]];
  190. }
  191. - (BOOL) isNextMonth
  192. {
  193. return [self isSameMonthAsDate:[[NSDate date] dateByAddingMonths:1]];
  194. }
  195. - (BOOL) isSameYearAsDate: (NSDate *) aDate
  196. {
  197. NSDateComponents *components1 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:self];
  198. NSDateComponents *components2 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:aDate];
  199. return (components1.year == components2.year);
  200. }
  201. - (BOOL) isThisYear
  202. {
  203. // Thanks, baspellis
  204. return [self isSameYearAsDate:[NSDate date]];
  205. }
  206. - (BOOL) isNextYear
  207. {
  208. NSDateComponents *components1 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:self];
  209. NSDateComponents *components2 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:[NSDate date]];
  210. return (components1.year == (components2.year + 1));
  211. }
  212. - (BOOL) isLastYear
  213. {
  214. NSDateComponents *components1 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:self];
  215. NSDateComponents *components2 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:[NSDate date]];
  216. return (components1.year == (components2.year - 1));
  217. }
  218. - (BOOL) isEarlierThanDate: (NSDate *) aDate
  219. {
  220. return ([self compare:aDate] == NSOrderedAscending);
  221. }
  222. - (BOOL) isLaterThanDate: (NSDate *) aDate
  223. {
  224. return ([self compare:aDate] == NSOrderedDescending);
  225. }
  226. // Thanks, markrickert
  227. - (BOOL) isInFuture
  228. {
  229. return ([self isLaterThanDate:[NSDate date]]);
  230. }
  231. // Thanks, markrickert
  232. - (BOOL) isInPast
  233. {
  234. return ([self isEarlierThanDate:[NSDate date]]);
  235. }
  236. #pragma mark - Roles
  237. - (BOOL) isTypicallyWeekend
  238. {
  239. NSDateComponents *components = [[NSDate currentCalendar] components:NSCalendarUnitWeekday fromDate:self];
  240. if ((components.weekday == 1) ||
  241. (components.weekday == 7))
  242. return YES;
  243. return NO;
  244. }
  245. - (BOOL) isTypicallyWorkday
  246. {
  247. return ![self isTypicallyWeekend];
  248. }
  249. #pragma mark - Adjusting Dates
  250. // Thaks, rsjohnson
  251. - (NSDate *) dateByAddingYears: (NSInteger) dYears
  252. {
  253. NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
  254. [dateComponents setYear:dYears];
  255. NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0];
  256. return newDate;
  257. }
  258. - (NSDate *) dateBySubtractingYears: (NSInteger) dYears
  259. {
  260. return [self dateByAddingYears:-dYears];
  261. }
  262. - (NSDate *) dateByAddingMonths: (NSInteger) dMonths
  263. {
  264. NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
  265. [dateComponents setMonth:dMonths];
  266. NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0];
  267. return newDate;
  268. }
  269. - (NSDate *) dateBySubtractingMonths: (NSInteger) dMonths
  270. {
  271. return [self dateByAddingMonths:-dMonths];
  272. }
  273. // Courtesy of dedan who mentions issues with Daylight Savings
  274. - (NSDate *) dateByAddingDays: (NSInteger) dDays
  275. {
  276. NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
  277. [dateComponents setDay:dDays];
  278. NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0];
  279. return newDate;
  280. }
  281. - (NSDate *) dateBySubtractingDays: (NSInteger) dDays
  282. {
  283. return [self dateByAddingDays: (dDays * -1)];
  284. }
  285. - (NSDate *) dateByAddingHours: (NSInteger) dHours
  286. {
  287. NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_HOUR * dHours;
  288. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  289. return newDate;
  290. }
  291. - (NSDate *) dateBySubtractingHours: (NSInteger) dHours
  292. {
  293. return [self dateByAddingHours: (dHours * -1)];
  294. }
  295. - (NSDate *) dateByAddingMinutes: (NSInteger) dMinutes
  296. {
  297. NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes;
  298. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  299. return newDate;
  300. }
  301. - (NSDate *) dateBySubtractingMinutes: (NSInteger) dMinutes
  302. {
  303. return [self dateByAddingMinutes: (dMinutes * -1)];
  304. }
  305. - (NSDateComponents *) componentsWithOffsetFromDate: (NSDate *) aDate
  306. {
  307. NSDateComponents *dTime = [[NSDate currentCalendar] components:componentFlags fromDate:aDate toDate:self options:0];
  308. return dTime;
  309. }
  310. #pragma mark - Extremes
  311. - (NSDate *) dateAtStartOfDay
  312. {
  313. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  314. components.hour = 0;
  315. components.minute = 0;
  316. components.second = 0;
  317. return [[NSDate currentCalendar] dateFromComponents:components];
  318. }
  319. // Thanks gsempe & mteece
  320. - (NSDate *) dateAtEndOfDay
  321. {
  322. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  323. components.hour = 23; // Thanks Aleksey Kononov
  324. components.minute = 59;
  325. components.second = 59;
  326. return [[NSDate currentCalendar] dateFromComponents:components];
  327. }
  328. #pragma mark - Retrieving Intervals
  329. - (NSInteger) minutesAfterDate: (NSDate *) aDate
  330. {
  331. NSTimeInterval ti = [self timeIntervalSinceDate:aDate];
  332. return (NSInteger) (ti / D_MINUTE);
  333. }
  334. - (NSInteger) minutesBeforeDate: (NSDate *) aDate
  335. {
  336. NSTimeInterval ti = [aDate timeIntervalSinceDate:self];
  337. return (NSInteger) (ti / D_MINUTE);
  338. }
  339. - (NSInteger) hoursAfterDate: (NSDate *) aDate
  340. {
  341. NSTimeInterval ti = [self timeIntervalSinceDate:aDate];
  342. return (NSInteger) (ti / D_HOUR);
  343. }
  344. - (NSInteger) hoursBeforeDate: (NSDate *) aDate
  345. {
  346. NSTimeInterval ti = [aDate timeIntervalSinceDate:self];
  347. return (NSInteger) (ti / D_HOUR);
  348. }
  349. - (NSInteger) daysAfterDate: (NSDate *) aDate
  350. {
  351. NSTimeInterval ti = [self timeIntervalSinceDate:aDate];
  352. return (NSInteger) (ti / D_DAY);
  353. }
  354. - (NSInteger) daysBeforeDate: (NSDate *) aDate
  355. {
  356. NSTimeInterval ti = [aDate timeIntervalSinceDate:self];
  357. return (NSInteger) (ti / D_DAY);
  358. }
  359. // Thanks, dmitrydims
  360. // I have not yet thoroughly tested this
  361. - (NSInteger)distanceInDaysToDate:(NSDate *)anotherDate
  362. {
  363. NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  364. NSDateComponents *components = [gregorianCalendar components:NSCalendarUnitDay fromDate:self toDate:anotherDate options:0];
  365. return components.day;
  366. }
  367. #pragma mark - Decomposing Dates
  368. - (NSInteger) nearestHour
  369. {
  370. NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * 30;
  371. NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
  372. NSDateComponents *components = [[NSDate currentCalendar] components:NSCalendarUnitHour fromDate:newDate];
  373. return components.hour;
  374. }
  375. - (NSInteger) hour
  376. {
  377. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  378. return components.hour;
  379. }
  380. - (NSInteger) minute
  381. {
  382. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  383. return components.minute;
  384. }
  385. - (NSInteger) seconds
  386. {
  387. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  388. return components.second;
  389. }
  390. - (NSInteger) day
  391. {
  392. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  393. return components.day;
  394. }
  395. - (NSInteger) month
  396. {
  397. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  398. return components.month;
  399. }
  400. - (NSInteger) week
  401. {
  402. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  403. return components.weekOfYear;
  404. }
  405. - (NSInteger) weekday
  406. {
  407. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  408. return components.weekday;
  409. }
  410. - (NSInteger) nthWeekday // e.g. 2nd Tuesday of the month is 2
  411. {
  412. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  413. return components.weekdayOrdinal;
  414. }
  415. - (NSInteger) year
  416. {
  417. NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self];
  418. return components.year;
  419. }
  420. - (NSDateComponents*)dsDayWithCalendar:(NSCalendar*)calendar {
  421. return [calendar components:NSCalendarUnitCalendar | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekday fromDate:self];
  422. }
  423. - (NSDateComponents*)dsMonthWithCalendar:(NSCalendar*)calendar {
  424. return [calendar components:NSCalendarUnitCalendar | NSCalendarUnitYear | NSCalendarUnitMonth fromDate:self];
  425. }
  426. - (NSDateComponents*)dsMonth {
  427. return [self dsMonthWithCalendar:[NSCalendar currentCalendar]];
  428. }
  429. @end