NSDate+Utilities.m 14 KB

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