NSDate+JKExtension.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. //
  2. // NSDate+Extension.m
  3. // JKCategories (https://github.com/shaojiankui/JKCategories)
  4. //
  5. // Created by Jakey on 15/4/25.
  6. // Copyright (c) 2015年 www.skyfox.org. All rights reserved.
  7. // https://github.com/632840804/HYBNSDateExtension
  8. #import "NSDate+JKExtension.h"
  9. @implementation NSDate (JKExtension)
  10. - (NSUInteger)jk_day {
  11. return [NSDate jk_day:self];
  12. }
  13. - (NSUInteger)jk_month {
  14. return [NSDate jk_month:self];
  15. }
  16. - (NSUInteger)jk_year {
  17. return [NSDate jk_year:self];
  18. }
  19. - (NSUInteger)jk_hour {
  20. return [NSDate jk_hour:self];
  21. }
  22. - (NSUInteger)jk_minute {
  23. return [NSDate jk_minute:self];
  24. }
  25. - (NSUInteger)jk_second {
  26. return [NSDate jk_second:self];
  27. }
  28. + (NSUInteger)jk_day:(NSDate *)date {
  29. NSCalendar *calendar = [NSCalendar currentCalendar];
  30. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  31. // NSDayCalendarUnit
  32. NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitDay) fromDate:date];
  33. #else
  34. NSDateComponents *dayComponents = [calendar components:(NSDayCalendarUnit) fromDate:date];
  35. #endif
  36. return [dayComponents day];
  37. }
  38. + (NSUInteger)jk_month:(NSDate *)date {
  39. NSCalendar *calendar = [NSCalendar currentCalendar];
  40. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  41. // NSDayCalendarUnit
  42. NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitMonth) fromDate:date];
  43. #else
  44. NSDateComponents *dayComponents = [calendar components:(NSMonthCalendarUnit) fromDate:date];
  45. #endif
  46. return [dayComponents month];
  47. }
  48. + (NSUInteger)jk_year:(NSDate *)date {
  49. NSCalendar *calendar = [NSCalendar currentCalendar];
  50. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  51. // NSDayCalendarUnit
  52. NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitYear) fromDate:date];
  53. #else
  54. NSDateComponents *dayComponents = [calendar components:(NSYearCalendarUnit) fromDate:date];
  55. #endif
  56. return [dayComponents year];
  57. }
  58. + (NSUInteger)jk_hour:(NSDate *)date {
  59. NSCalendar *calendar = [NSCalendar currentCalendar];
  60. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  61. // NSDayCalendarUnit
  62. NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitHour) fromDate:date];
  63. #else
  64. NSDateComponents *dayComponents = [calendar components:(NSHourCalendarUnit) fromDate:date];
  65. #endif
  66. return [dayComponents hour];
  67. }
  68. + (NSUInteger)jk_minute:(NSDate *)date {
  69. NSCalendar *calendar = [NSCalendar currentCalendar];
  70. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  71. // NSDayCalendarUnit
  72. NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitMinute) fromDate:date];
  73. #else
  74. NSDateComponents *dayComponents = [calendar components:(NSMinuteCalendarUnit) fromDate:date];
  75. #endif
  76. return [dayComponents minute];
  77. }
  78. + (NSUInteger)jk_second:(NSDate *)date {
  79. NSCalendar *calendar = [NSCalendar currentCalendar];
  80. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  81. // NSDayCalendarUnit
  82. NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitSecond) fromDate:date];
  83. #else
  84. NSDateComponents *dayComponents = [calendar components:(NSSecondCalendarUnit) fromDate:date];
  85. #endif
  86. return [dayComponents second];
  87. }
  88. - (NSUInteger)jk_daysInYear {
  89. return [NSDate jk_daysInYear:self];
  90. }
  91. + (NSUInteger)jk_daysInYear:(NSDate *)date {
  92. return [self jk_isLeapYear:date] ? 366 : 365;
  93. }
  94. - (NSTimeInterval)by_timeIntervalWithDate:(NSDate *)date{
  95. return [self timeIntervalSinceDate:date];
  96. }
  97. - (BOOL)jk_isLeapYear {
  98. return [NSDate jk_isLeapYear:self];
  99. }
  100. + (BOOL)jk_isLeapYear:(NSDate *)date {
  101. NSUInteger year = [date jk_year];
  102. if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
  103. return YES;
  104. }
  105. return NO;
  106. }
  107. - (NSString *)jk_formatYMD {
  108. return [NSDate jk_formatYMD:self];
  109. }
  110. + (NSString *)jk_formatYMD:(NSDate *)date {
  111. return [NSString stringWithFormat:@"%lu-%02lu-%02lu",(unsigned long)[date jk_year],(unsigned long)[date jk_month], (unsigned long)[date jk_day]];
  112. }
  113. - (NSUInteger)jk_weeksOfMonth {
  114. return [NSDate jk_weeksOfMonth:self];
  115. }
  116. + (NSUInteger)jk_weeksOfMonth:(NSDate *)date {
  117. return [[date jk_lastdayOfMonth] jk_weekOfYear] - [[date jk_begindayOfMonth] jk_weekOfYear] + 1;
  118. }
  119. - (NSUInteger)jk_weekOfYear {
  120. return [NSDate jk_weekOfYear:self];
  121. }
  122. + (NSUInteger)jk_weekOfYear:(NSDate *)date {
  123. NSUInteger i;
  124. NSUInteger year = [date jk_year];
  125. NSDate *lastdate = [date jk_lastdayOfMonth];
  126. for (i = 1;[[lastdate jk_dateAfterDay:-7 * i] jk_year] == year; i++) {
  127. }
  128. return i;
  129. }
  130. - (NSDate *)jk_dateAfterDay:(NSUInteger)day {
  131. return [NSDate jk_dateAfterDate:self day:day];
  132. }
  133. + (NSDate *)jk_dateAfterDate:(NSDate *)date day:(NSInteger)day {
  134. NSCalendar *calendar = [NSCalendar currentCalendar];
  135. NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
  136. [componentsToAdd setDay:day];
  137. NSDate *dateAfterDay = [calendar dateByAddingComponents:componentsToAdd toDate:date options:0];
  138. return dateAfterDay;
  139. }
  140. - (NSDate *)jk_dateAfterMonth:(NSUInteger)month {
  141. return [NSDate jk_dateAfterDate:self month:month];
  142. }
  143. + (NSDate *)jk_dateAfterDate:(NSDate *)date month:(NSInteger)month {
  144. NSCalendar *calendar = [NSCalendar currentCalendar];
  145. NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
  146. [componentsToAdd setMonth:month];
  147. NSDate *dateAfterMonth = [calendar dateByAddingComponents:componentsToAdd toDate:date options:0];
  148. return dateAfterMonth;
  149. }
  150. - (NSDate *)jk_begindayOfMonth {
  151. return [NSDate jk_begindayOfMonth:self];
  152. }
  153. + (NSDate *)jk_begindayOfMonth:(NSDate *)date {
  154. return [self jk_dateAfterDate:date day:-[date jk_day] + 1];
  155. }
  156. - (NSDate *)jk_lastdayOfMonth {
  157. return [NSDate jk_lastdayOfMonth:self];
  158. }
  159. + (NSDate *)jk_lastdayOfMonth:(NSDate *)date {
  160. NSDate *lastDate = [self jk_begindayOfMonth:date];
  161. return [[lastDate jk_dateAfterMonth:1] jk_dateAfterDay:-1];
  162. }
  163. - (NSUInteger)jk_daysAgo {
  164. return [NSDate jk_daysAgo:self];
  165. }
  166. + (NSUInteger)jk_daysAgo:(NSDate *)date {
  167. NSCalendar *calendar = [NSCalendar currentCalendar];
  168. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  169. NSDateComponents *components = [calendar components:(NSCalendarUnitDay)
  170. fromDate:date
  171. toDate:[NSDate date]
  172. options:0];
  173. #else
  174. NSDateComponents *components = [calendar components:(NSDayCalendarUnit)
  175. fromDate:date
  176. toDate:[NSDate date]
  177. options:0];
  178. #endif
  179. return [components day];
  180. }
  181. - (NSInteger)jk_weekday {
  182. return [NSDate jk_weekday:self];
  183. }
  184. + (NSInteger)jk_weekday:(NSDate *)date {
  185. NSCalendar *gregorian = [[NSCalendar alloc]
  186. initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  187. NSDateComponents *comps = [gregorian components:(NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear | NSCalendarUnitWeekday) fromDate:date];
  188. NSInteger weekday = [comps weekday];
  189. return weekday;
  190. }
  191. - (NSString *)jk_dayFromWeekday {
  192. return [NSDate jk_dayFromWeekday:self];
  193. }
  194. + (NSString *)jk_dayFromWeekday:(NSDate *)date {
  195. switch([date jk_weekday]) {
  196. case 1:
  197. return @"星期天";
  198. break;
  199. case 2:
  200. return @"星期一";
  201. break;
  202. case 3:
  203. return @"星期二";
  204. break;
  205. case 4:
  206. return @"星期三";
  207. break;
  208. case 5:
  209. return @"星期四";
  210. break;
  211. case 6:
  212. return @"星期五";
  213. break;
  214. case 7:
  215. return @"星期六";
  216. break;
  217. default:
  218. break;
  219. }
  220. return @"";
  221. }
  222. - (BOOL)jk_isSameDay:(NSDate *)anotherDate {
  223. NSCalendar *calendar = [NSCalendar currentCalendar];
  224. NSDateComponents *components1 = [calendar components:(NSCalendarUnitYear
  225. | NSCalendarUnitMonth
  226. | NSCalendarUnitDay)
  227. fromDate:self];
  228. NSDateComponents *components2 = [calendar components:(NSCalendarUnitYear
  229. | NSCalendarUnitMonth
  230. | NSCalendarUnitDay)
  231. fromDate:anotherDate];
  232. return ([components1 year] == [components2 year]
  233. && [components1 month] == [components2 month]
  234. && [components1 day] == [components2 day]);
  235. }
  236. - (BOOL)jk_isToday {
  237. return [self jk_isSameDay:[NSDate date]];
  238. }
  239. - (NSDate *)jk_dateByAddingDays:(NSUInteger)days {
  240. NSDateComponents *c = [[NSDateComponents alloc] init];
  241. c.day = days;
  242. return [[NSCalendar currentCalendar] dateByAddingComponents:c toDate:self options:0];
  243. }
  244. /**
  245. * Get the month as a localized string from the given month number
  246. *
  247. * @param month The month to be converted in string
  248. * [1 - January]
  249. * [2 - February]
  250. * [3 - March]
  251. * [4 - April]
  252. * [5 - May]
  253. * [6 - June]
  254. * [7 - July]
  255. * [8 - August]
  256. * [9 - September]
  257. * [10 - October]
  258. * [11 - November]
  259. * [12 - December]
  260. *
  261. * @return Return the given month as a localized string
  262. */
  263. + (NSString *)jk_monthWithMonthNumber:(NSInteger)month {
  264. switch(month) {
  265. case 1:
  266. return @"January";
  267. break;
  268. case 2:
  269. return @"February";
  270. break;
  271. case 3:
  272. return @"March";
  273. break;
  274. case 4:
  275. return @"April";
  276. break;
  277. case 5:
  278. return @"May";
  279. break;
  280. case 6:
  281. return @"June";
  282. break;
  283. case 7:
  284. return @"July";
  285. break;
  286. case 8:
  287. return @"August";
  288. break;
  289. case 9:
  290. return @"September";
  291. break;
  292. case 10:
  293. return @"October";
  294. break;
  295. case 11:
  296. return @"November";
  297. break;
  298. case 12:
  299. return @"December";
  300. break;
  301. default:
  302. break;
  303. }
  304. return @"";
  305. }
  306. + (NSString *)jk_stringWithDate:(NSDate *)date format:(NSString *)format {
  307. return [date jk_stringWithFormat:format];
  308. }
  309. - (NSString *)jk_stringWithFormat:(NSString *)format {
  310. NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
  311. [outputFormatter setDateFormat:format];
  312. [outputFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8*3600]];
  313. NSString *retStr = [outputFormatter stringFromDate:self];
  314. return retStr;
  315. }
  316. + (NSDate *)jk_dateWithString:(NSString *)string format:(NSString *)format {
  317. NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
  318. [inputFormatter setDateFormat:format];
  319. NSDate *date = [inputFormatter dateFromString:string];
  320. return date;
  321. }
  322. - (NSUInteger)jk_daysInMonth:(NSUInteger)month {
  323. return [NSDate jk_daysInMonth:self month:month];
  324. }
  325. + (NSUInteger)jk_daysInMonth:(NSDate *)date month:(NSUInteger)month {
  326. switch (month) {
  327. case 1: case 3: case 5: case 7: case 8: case 10: case 12:
  328. return 31;
  329. case 2:
  330. return [date jk_isLeapYear] ? 29 : 28;
  331. }
  332. return 30;
  333. }
  334. - (NSUInteger)jk_daysInMonth {
  335. return [NSDate jk_daysInMonth:self];
  336. }
  337. + (NSUInteger)jk_daysInMonth:(NSDate *)date {
  338. return [self jk_daysInMonth:date month:[date jk_month]];
  339. }
  340. - (NSString *)jk_timeInfo {
  341. return [NSDate jk_timeInfoWithDate:self];
  342. }
  343. + (NSString *)jk_timeInfoWithDate:(NSDate *)date {
  344. return [self jk_timeInfoWithDateString:[self jk_stringWithDate:date format:[self jk_ymdHmsFormat]]];
  345. }
  346. + (NSString *)jk_timeInfoWithDateString:(NSString *)dateString {
  347. NSDate *date = [self jk_dateWithString:dateString format:[self jk_ymdHmsFormat]];
  348. NSDate *curDate = [NSDate date];
  349. NSTimeInterval time = -[date timeIntervalSinceDate:curDate];
  350. int month = (int)([curDate jk_month] - [date jk_month]);
  351. int year = (int)([curDate jk_year] - [date jk_year]);
  352. int day = (int)([curDate jk_day] - [date jk_day]);
  353. NSTimeInterval retTime = 1.0;
  354. if (time < 3600) { // 小于一小时
  355. retTime = time / 60;
  356. retTime = retTime <= 0.0 ? 1.0 : retTime;
  357. return [NSString stringWithFormat:@"%.0f分钟前", retTime];
  358. } else if (time < 3600 * 24) { // 小于一天,也就是今天
  359. retTime = time / 3600;
  360. retTime = retTime <= 0.0 ? 1.0 : retTime;
  361. return [NSString stringWithFormat:@"%.0f小时前", retTime];
  362. } else if (time < 3600 * 24 * 2) {
  363. return @"昨天";
  364. }
  365. // 第一个条件是同年,且相隔时间在一个月内
  366. // 第二个条件是隔年,对于隔年,只能是去年12月与今年1月这种情况
  367. else if ((abs(year) == 0 && abs(month) <= 1)
  368. || (abs(year) == 1 && [curDate jk_month] == 1 && [date jk_month] == 12)) {
  369. int retDay = 0;
  370. if (year == 0) { // 同年
  371. if (month == 0) { // 同月
  372. retDay = day;
  373. }
  374. }
  375. if (retDay <= 0) {
  376. // 获取发布日期中,该月有多少天
  377. int totalDays = (int)[self jk_daysInMonth:date month:[date jk_month]];
  378. // 当前天数 + (发布日期月中的总天数-发布日期月中发布日,即等于距离今天的天数)
  379. retDay = (int)[curDate jk_day] + (totalDays - (int)[date jk_day]);
  380. }
  381. return [NSString stringWithFormat:@"%d天前", (abs)(retDay)];
  382. } else {
  383. if (abs(year) <= 1) {
  384. if (year == 0) { // 同年
  385. return [NSString stringWithFormat:@"%d个月前", abs(month)];
  386. }
  387. // 隔年
  388. int month = (int)[curDate jk_month];
  389. int preMonth = (int)[date jk_month];
  390. if (month == 12 && preMonth == 12) {// 隔年,但同月,就作为满一年来计算
  391. return @"1年前";
  392. }
  393. return [NSString stringWithFormat:@"%d个月前", (abs)(12 - preMonth + month)];
  394. }
  395. return [NSString stringWithFormat:@"%d年前", abs(year)];
  396. }
  397. return @"1小时前";
  398. }
  399. - (NSString *)jk_ymdFormat {
  400. return [NSDate jk_ymdFormat];
  401. }
  402. - (NSString *)jk_hmsFormat {
  403. return [NSDate jk_hmsFormat];
  404. }
  405. - (NSString *)jk_ymdHmsFormat {
  406. return [NSDate jk_ymdHmsFormat];
  407. }
  408. + (NSString *)jk_ymdFormat {
  409. return @"yyyy-MM-dd";
  410. }
  411. + (NSString *)jk_hmsFormat {
  412. return @"HH:mm:ss";
  413. }
  414. + (NSString *)jk_ymdHmsFormat {
  415. return [NSString stringWithFormat:@"%@ %@", [self jk_ymdFormat], [self jk_hmsFormat]];
  416. }
  417. - (NSDate *)jk_offsetYears:(int)numYears {
  418. return [NSDate jk_offsetYears:numYears fromDate:self];
  419. }
  420. + (NSDate *)jk_offsetYears:(int)numYears fromDate:(NSDate *)fromDate {
  421. if (fromDate == nil) {
  422. return nil;
  423. }
  424. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  425. // NSDayCalendarUnit
  426. NSCalendar *gregorian = [[NSCalendar alloc]
  427. initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  428. #else
  429. NSCalendar *gregorian = [[NSCalendar alloc]
  430. initWithCalendarIdentifier:NSGregorianCalendar];
  431. #endif
  432. NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
  433. [offsetComponents setYear:numYears];
  434. return [gregorian dateByAddingComponents:offsetComponents
  435. toDate:fromDate
  436. options:0];
  437. }
  438. - (NSDate *)jk_offsetMonths:(int)numMonths {
  439. return [NSDate jk_offsetMonths:numMonths fromDate:self];
  440. }
  441. + (NSDate *)jk_offsetMonths:(int)numMonths fromDate:(NSDate *)fromDate {
  442. if (fromDate == nil) {
  443. return nil;
  444. }
  445. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  446. // NSDayCalendarUnit
  447. NSCalendar *gregorian = [[NSCalendar alloc]
  448. initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  449. #else
  450. NSCalendar *gregorian = [[NSCalendar alloc]
  451. initWithCalendarIdentifier:NSGregorianCalendar];
  452. #endif
  453. NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
  454. [offsetComponents setMonth:numMonths];
  455. return [gregorian dateByAddingComponents:offsetComponents
  456. toDate:fromDate
  457. options:0];
  458. }
  459. - (NSDate *)jk_offsetDays:(int)numDays {
  460. return [NSDate jk_offsetDays:numDays fromDate:self];
  461. }
  462. + (NSDate *)jk_offsetDays:(int)numDays fromDate:(NSDate *)fromDate {
  463. if (fromDate == nil) {
  464. return nil;
  465. }
  466. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  467. // NSDayCalendarUnit
  468. NSCalendar *gregorian = [[NSCalendar alloc]
  469. initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  470. #else
  471. NSCalendar *gregorian = [[NSCalendar alloc]
  472. initWithCalendarIdentifier:NSGregorianCalendar];
  473. #endif
  474. NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
  475. [offsetComponents setDay:numDays];
  476. return [gregorian dateByAddingComponents:offsetComponents
  477. toDate:fromDate
  478. options:0];
  479. }
  480. - (NSDate *)jk_offsetHours:(int)hours {
  481. return [NSDate jk_offsetHours:hours fromDate:self];
  482. }
  483. + (NSDate *)jk_offsetHours:(int)numHours fromDate:(NSDate *)fromDate {
  484. if (fromDate == nil) {
  485. return nil;
  486. }
  487. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
  488. // NSDayCalendarUnit
  489. NSCalendar *gregorian = [[NSCalendar alloc]
  490. initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  491. #else
  492. NSCalendar *gregorian = [[NSCalendar alloc]
  493. initWithCalendarIdentifier:NSGregorianCalendar];
  494. #endif
  495. NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
  496. [offsetComponents setHour:numHours];
  497. return [gregorian dateByAddingComponents:offsetComponents
  498. toDate:fromDate
  499. options:0];
  500. }
  501. @end