github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgRpc/kmgRpcSwift/tplGenerateCode.go (about) 1 package kmgRpcSwift 2 3 import ( 4 "bytes" 5 ) 6 7 func tplGenerateCode(config *tplConfig) string { 8 var _buf bytes.Buffer 9 _buf.WriteString(` 10 import Foundation 11 import CryptoSwift 12 import SwiftyJSON 13 class `) 14 _buf.WriteString(config.ClassName) 15 _buf.WriteString(` { 16 `) 17 for _, innerClass := range config.InnerClassList { 18 _buf.WriteString(` 19 `) 20 _buf.WriteString(innerClass.tplInnerClass()) 21 _buf.WriteString(` 22 `) 23 } 24 _buf.WriteString(` 25 class Client{ 26 // 所有Api列表 27 `) 28 for _, api := range config.ApiList { 29 _buf.WriteString(` 30 `) 31 _buf.WriteString(api.tplApiClient()) 32 _buf.WriteString(` 33 `) 34 } 35 _buf.WriteString(` 36 var RemoteUrl: String = "" 37 var Psk: [UInt8] = [] 38 func sendRequest(apiName:String,params:Dictionary<String, AnyObject>,callback:(JSON)->Void){ 39 if params.count != 0{//TODO:将有参数和无参数重构为一种 40 HttpSwift.rpcPost(self.RemoteUrl,apiName:apiName,psk:self.Psk, params:params,callback: {(data,response,error) in 41 if error != nil{ 42 print(error) 43 return 44 } 45 var inData = [] as [UInt8] 46 if self.Psk.count != 0{ 47 inData = DecryptBtyesDecode(self.Psk, data: data!).arrayOfBytes() 48 }else{ 49 inData = data!.arrayOfBytes() 50 } 51 let filterByte = inData.filter{value in 52 if value == 2{ 53 return false 54 } 55 return true 56 } 57 let filterData = NSData(bytes: filterByte as [UInt8], length: filterByte.count) 58 let outData = JSON(data:filterData) 59 callback(outData) 60 }) 61 }else{ 62 HttpSwift.rpcPost(self.RemoteUrl,apiName:apiName,psk: self.Psk, callback: {(data,response,error) in 63 if error != nil{ 64 print(error) 65 return 66 } 67 var inData = [] as [UInt8] 68 if self.Psk.count != 0{ 69 inData = DecryptBtyesDecode(self.Psk, data: data!).arrayOfBytes() 70 }else{ 71 inData = data.arrayOfBytes() 72 } 73 let filterByte = inData.filter{value in 74 if value == 2{ 75 return false 76 } 77 return true 78 } 79 let filterData = NSData(bytes: filterByte as [UInt8], length: filterByte.count) 80 let outData = JSON(data:filterData) 81 callback(outData) 82 }) 83 } 84 } 85 } 86 static func ConfigDefaultClient(RemoteUrl: String,pskStr: String?)->Client{ 87 let newclient = Client() 88 newclient.RemoteUrl = RemoteUrl 89 if pskStr != nil{ 90 newclient.Psk = Array((pskStr?.nsdata.sha512()?.arrayOfBytes())![0...31]) 91 } 92 return newclient 93 } 94 } 95 let magicCode4 = [167, 151, 109, 21] as [UInt8] 96 extension String { 97 var nsdata: NSData { 98 return self.dataUsingEncoding(NSUTF8StringEncoding)! 99 } 100 func replace(target: String, withString: String) -> String 101 { 102 return self.stringByReplacingOccurrencesOfString(target, withString: withString, options: NSStringCompareOptions.LiteralSearch, range: nil) 103 } 104 } 105 /* 106 //Swift2.0 网络请求封装 107 */ 108 class HttpSwift { 109 static func request(method: String, url: String, params: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void){ 110 let manager = HttpSwiftManager(url: url, method: method, params: params, callback: callback) 111 manager.fire() 112 } 113 /*get请求,不带参数*/ 114 static func get(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 115 let manager = HttpSwiftManager(url: url, method: "GET", callback: callback) 116 manager.fire() 117 } 118 /*get请求,带参数*/ 119 static func get(url: String, params: Dictionary<String, AnyObject>, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 120 let manager = HttpSwiftManager(url: url, method: "GET", params: params, callback: callback) 121 manager.fire() 122 } 123 /*POST请求,不带参数*/ 124 static func post(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 125 let manager = HttpSwiftManager(url: url, method: "POST", callback: callback) 126 manager.fire() 127 } 128 /*POST请求,带参数*/ 129 static func post(url: String, params: Dictionary<String, AnyObject>, callback: (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void) { 130 let manager = HttpSwiftManager(url: url, method: "POST", params: params, callback: callback) 131 manager.fire() 132 } 133 static func rpcPost(url: String, apiName: String,psk: [UInt8], callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 134 let manager = HttpSwiftManager(url: url, method: "POST", callback: callback) 135 manager.apiName = apiName 136 manager.psk = psk 137 manager.fire() 138 } 139 /*POST请求,带参数*/ 140 static func rpcPost(url: String, apiName: String, psk: [UInt8], params: Dictionary<String, AnyObject>, callback: (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void) { 141 let manager = HttpSwiftManager(url: url, method: "POST", params: params, callback: callback) 142 manager.apiName = apiName 143 manager.psk = psk 144 manager.fire() 145 } 146 /*PUT请求,不带参数*/ 147 static func put(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 148 let manager = HttpSwiftManager(url: url, method: "PUT", callback: callback) 149 manager.fire() 150 } 151 /*PUT请求,带参数*/ 152 static func put(url: String, params: Dictionary<String, AnyObject>, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 153 let manager = HttpSwiftManager(url: url, method: "PUT", params: params, callback: callback) 154 manager.fire() 155 } 156 /*DELETE请求,带参数*/ 157 static func delete(url: String, params: Dictionary<String, AnyObject>, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 158 let manager = HttpSwiftManager(url: url, method: "DELETE", params: params, callback: callback) 159 manager.fire() 160 } 161 } 162 /*扩展*/ 163 class HttpSwiftManager { 164 let method: String! 165 let params: Dictionary<String, AnyObject> 166 let callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void 167 var session = NSURLSession.sharedSession() 168 let url: String! 169 var request: NSMutableURLRequest! 170 var task: NSURLSessionTask! 171 var apiName: String! = "" 172 var psk = [] as [UInt8] 173 /*带参数 构造器*/ 174 init(url: String, method: String, params: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 175 self.url = url 176 self.request = NSMutableURLRequest(URL: NSURL(string: url)!) 177 self.method = method 178 self.params = params 179 self.callback = callback 180 } 181 func buildRequest() { 182 if self.method == "GET" && self.params.count > 0 { 183 self.request = NSMutableURLRequest(URL: NSURL(string: url + "?" + buildParams(self.params))!) 184 } 185 request.HTTPMethod = self.method 186 request.addValue("image/jpeg", forHTTPHeaderField: "Content-Type") 187 } 188 func buildBody() { 189 let apiName = self.apiName.dataUsingEncoding(NSUTF8StringEncoding)?.arrayOfBytes() 190 let apiNameLength = [UInt8.init((apiName?.count)!)] 191 var inData: [UInt8] 192 if self.params.count > 0 && self.method != "GET" { 193 inData = buildParams(self.params).nsdata.arrayOfBytes() 194 }else{ 195 inData = ("{}".dataUsingEncoding(NSUTF8StringEncoding)?.arrayOfBytes())! 196 } 197 let originData = NSData.withBytes( apiNameLength + apiName! + inData) 198 if self.psk.count != 0{ 199 request.HTTPBody = EncryptBtyesDecode(self.psk, data: originData) 200 }else{ 201 request.HTTPBody = originData 202 } 203 } 204 func fireTask() { 205 let semaphore = dispatch_semaphore_create(0) 206 task = session.dataTaskWithRequest(request,completionHandler: { (data, response, error) -> Void in 207 if response != nil{ 208 self.callback(data: data!, response: response, error: error) 209 dispatch_semaphore_signal(semaphore) 210 } 211 }) 212 task.resume() 213 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 214 } 215 func buildParams(parameters: [String: AnyObject]) -> String { 216 return JSONStringify(parameters, prettyPrinted: true) 217 } 218 func queryComponents(key: String, _ value: AnyObject) -> [(String, String)] { 219 var components: [(String, String)] = [] 220 if let dictionary = value as? [String: AnyObject] { 221 for (nestedKey, value) in dictionary { 222 components += queryComponents("\(key)[\(nestedKey)]", value) 223 } 224 } else if let array = value as? [AnyObject] { 225 for value in array { 226 components += queryComponents("\(key)", value) 227 } 228 } else { 229 components.appendContentsOf([(escape(key), escape("\(value)"))]) 230 } 231 return components 232 } 233 func escape(string: String) -> String { 234 return string 235 } 236 func fire() { 237 buildRequest() 238 buildBody() 239 fireTask() 240 } 241 func join(joinCode:String,var StringArray:[String])->String{ 242 var out = "" 243 while StringArray.last != nil{ 244 let str = StringArray.popLast() 245 out += str! + "&" 246 } 247 return out 248 } 249 } 250 //JSON 压缩 解压缩 加密 解密 251 func JSONStringify(value: AnyObject,prettyPrinted:Bool = false) -> String{ 252 let options = prettyPrinted ? NSJSONWritingOptions.PrettyPrinted : NSJSONWritingOptions(rawValue: 0) 253 if NSJSONSerialization.isValidJSONObject(value) { 254 do{ 255 let data = try NSJSONSerialization.dataWithJSONObject(value, options: options) 256 if let string = NSString(data: data, encoding: NSUTF8StringEncoding) { 257 return string as String 258 } 259 }catch { 260 print("error") 261 } 262 } 263 return "" 264 } 265 func DecryptBtyesDecode(key:[UInt8],data:NSData)->NSData{ 266 let inData = data.arrayOfBytes() 267 if inData.count<16+4+1{ 268 print("input data too small") 269 return data 270 } 271 var resultOut = NSData() 272 do { 273 var output = try AES(key: key, iv: Array(inData[0...15]), blockMode: .CTR)!.decrypt(Array(inData[16...(inData.count-1)])) 274 output = Array(output[0...(inData.count-1-16)]) 275 if magicCode4 != Array(output[(output.count-4)...(output.count-1)]){ 276 print("magicCode not match") 277 return resultOut 278 } 279 output = Array(output[0...(output.count-5)]) 280 let mark = output[0] 281 if mark == 0 { 282 if output[1] == 2{ 283 resultOut = NSData.withBytes(Array(output[1...(output.count-1)])) 284 } 285 }else{ 286 let outData = NSData.withBytes(Array(output[1...(output.count-1)])) 287 resultOut = outData.zlibInflate() 288 } 289 }catch{ 290 print("aes decrypt failed") 291 } 292 return resultOut 293 } 294 func EncryptBtyesDecode(key:[UInt8],data:NSData)->NSData{ 295 var inData = data.zlibDeflate().arrayOfBytes() 296 if inData.count>data.arrayOfBytes().count{ 297 inData = [0] + data.arrayOfBytes() 298 }else{ 299 inData = [1] + inData 300 } 301 let Iv = Cipher.randomIV(16) 302 var outData = NSData() 303 do { 304 let ss = Iv+inData+magicCode4 305 let inDataV2 = Array(ss[16...(ss.count-1)]) 306 var output = try Cipher.AES(key: key, iv: Iv, blockMode: .CTR).encrypt(inDataV2) 307 output = Iv+output 308 outData = NSData.withBytes(output) 309 }catch{ 310 print("aes encrypt failed") 311 } 312 return outData 313 } 314 public extension String { 315 316 /** 317 Create a new NSDate object with passed custom format string 318 319 :param: format format as string 320 321 :returns: a new NSDate instance with parsed date, or nil if it's fail 322 */ 323 func toDate(formatString formatString: String!) -> NSDate? { 324 return NSDate.date(fromString: self, format: DateFormat.Custom(formatString)) 325 } 326 327 /** 328 Create a new NSDate object with passed date format 329 330 :param: format format 331 332 :returns: a new NSDate instance with parsed date, or nil if it's fail 333 */ 334 func toDate(format format: DateFormat) -> NSDate? { 335 return NSDate.date(fromString: self, format: format) 336 } 337 } 338 339 //MARK: ACCESS TO DATE COMPONENTS 340 341 public extension NSDate { 342 343 // Use this as shortcuts for the most common formats for dates 344 class var commonFormats : [String] { 345 return [ 346 "yyyy-MM-ddTHH:mm:ssZ", // ISO8601 347 "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", 348 "yyyy-MM-dd", 349 "h:mm:ss A", 350 "h:mm A", 351 "MM/dd/yyyy", 352 "MMMM d, yyyy", 353 "MMMM d, yyyy LT", 354 "dddd, MMMM D, yyyy LT", 355 "yyyyyy-MM-dd", 356 "yyyy-MM-dd", 357 "GGGG-[W]WW-E", 358 "GGGG-[W]WW", 359 "yyyy-ddd", 360 "HH:mm:ss.SSSS", 361 "HH:mm:ss", 362 "HH:mm", 363 "HH" 364 ] 365 } 366 367 /// Get the year component of the date 368 var year : Int { return components.year } 369 /// Get the month component of the date 370 var month : Int { return components.month } 371 // Get the week of the month component of the date 372 var weekOfMonth: Int { return components.weekOfMonth } 373 // Get the week of the month component of the date 374 var weekOfYear: Int { return components.weekOfYear } 375 /// Get the weekday component of the date 376 var weekday: Int { return components.weekday } 377 /// Get the weekday ordinal component of the date 378 var weekdayOrdinal: Int { return components.weekdayOrdinal } 379 /// Get the day component of the date 380 var day: Int { return components.day } 381 /// Get the hour component of the date 382 var hour: Int { return components.hour } 383 /// Get the minute component of the date 384 var minute: Int { return components.minute } 385 // Get the second component of the date 386 var second: Int { return components.second } 387 // Get the era component of the date 388 var era: Int { return components.era } 389 // Get the current month name based upon current locale 390 var monthName: String { 391 let dateFormatter = NSDate.localThreadDateFormatter() 392 dateFormatter.locale = NSLocale.autoupdatingCurrentLocale() 393 return dateFormatter.monthSymbols[month - 1] as String 394 } 395 // Get the current weekday name 396 var weekdayName: String { 397 let dateFormatter = NSDate.localThreadDateFormatter() 398 dateFormatter.locale = NSLocale.autoupdatingCurrentLocale() 399 dateFormatter.dateFormat = "EEEE" 400 dateFormatter.timeZone = NSTimeZone.localTimeZone() 401 return dateFormatter.stringFromDate(self) 402 } 403 404 405 private func firstWeekDate()-> (date : NSDate!, interval: NSTimeInterval) { 406 // Sunday 1, Monday 2, Tuesday 3, Wednesday 4, Friday 5, Saturday 6 407 let calendar = NSCalendar.currentCalendar() 408 calendar.firstWeekday = NSCalendar.currentCalendar().firstWeekday 409 var startWeek: NSDate? = nil 410 var duration: NSTimeInterval = 0 411 412 calendar.rangeOfUnit(NSCalendarUnit.WeekOfYear, startDate: &startWeek, interval: &duration, forDate: self) 413 return (startWeek,duration) 414 } 415 416 /// Return the first day of the current date's week 417 var firstDayOfWeek : Int { 418 let (date,_) = self.firstWeekDate() 419 return date.day 420 } 421 422 /// Return the last day of the week 423 var lastDayOfWeek : Int { 424 let (startWeek,interval) = self.firstWeekDate() 425 let endWeek = startWeek?.dateByAddingTimeInterval(interval-1) 426 return endWeek!.day 427 } 428 429 /// Return the nearest hour of the date 430 var nearestHour:NSInteger{ 431 let aTimeInterval = NSDate.timeIntervalSinceReferenceDate() + Double(D_MINUTE) * Double(30); 432 433 let newDate = NSDate(timeIntervalSinceReferenceDate:aTimeInterval); 434 let components = NSCalendar.currentCalendar().components(NSCalendarUnit.Hour, fromDate: newDate); 435 return components.hour; 436 } 437 } 438 439 //MARK: CREATE AND MANIPULATE DATE COMPONENTS 440 441 public extension NSDate { 442 443 /** 444 Create a new NSDate instance from passed string with given format 445 446 :param: string date as string 447 :param: format parse formate. 448 449 :returns: a new instance of the string 450 */ 451 class func date(fromString string: String, format: DateFormat) -> NSDate? { 452 if string.isEmpty { 453 return nil 454 } 455 456 let dateFormatter = NSDate.localThreadDateFormatter() 457 switch format { 458 case .ISO8601: // 1972-07-16T08:15:30-05:00 459 dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") 460 dateFormatter.timeZone = NSTimeZone.localTimeZone() 461 dateFormatter.dateFormat = ISO8601Formatter(fromString: string) 462 return dateFormatter.dateFromString(string) 463 case .AltRSS: // 09 Sep 2011 15:26:08 +0200 464 var formattedString : NSString = string 465 if formattedString.hasSuffix("Z") { 466 formattedString = formattedString.substringToIndex(formattedString.length-1) + "GMT" 467 } 468 dateFormatter.dateFormat = "d MMM yyyy HH:mm:ss ZZZ" 469 return dateFormatter.dateFromString(formattedString as String) 470 case .RSS: // Fri, 09 Sep 2011 15:26:08 +0200 471 var formattedString : NSString = string 472 if formattedString.hasSuffix("Z") { 473 formattedString = formattedString.substringToIndex(formattedString.length-1) + "GMT" 474 } 475 dateFormatter.dateFormat = "EEE, d MMM yyyy HH:mm:ss ZZZ" 476 return dateFormatter.dateFromString(formattedString as String) 477 case .Custom(let dateFormat): 478 dateFormatter.dateFormat = dateFormat 479 return dateFormatter.dateFromString(string) 480 } 481 } 482 483 /** 484 Attempts to handle all different ISO8601 formatters 485 and returns correct date format for string 486 http://www.w3.org/TR/NOTE-datetime 487 */ 488 class func ISO8601Formatter(fromString string: String) -> String { 489 490 enum IS08601Format: Int { 491 // YYYY (eg 1997) 492 case Year = 4 493 494 // YYYY-MM (eg 1997-07) 495 case YearAndMonth = 7 496 497 // YYYY-MM-DD (eg 1997-07-16) 498 case CompleteDate = 10 499 500 // YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) 501 case CompleteDatePlusHoursAndMinutes = 22 502 503 // YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20Z) 504 case CompleteDatePlusHoursAndMinutesAndZ = 17 505 506 // YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) 507 case CompleteDatePlusHoursMinutesAndSeconds = 25 508 509 // YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30Z) 510 case CompleteDatePlusHoursAndMinutesAndSecondsAndZ = 20 511 512 // YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) 513 case CompleteDatePlusHoursMinutesSecondsAndDecimalFractionOfSecond = 28 514 515 // YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45Z) 516 case CompleteDatePlusHoursMinutesSecondsAndDecimalFractionOfSecondAndZ = 23 517 } 518 519 var dateFormatter = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 520 521 if let dateStringCount = IS08601Format(rawValue: string.characters.count) { 522 switch dateStringCount { 523 case .Year: 524 dateFormatter = "yyyy" 525 case .YearAndMonth: 526 dateFormatter = "yyyy-MM" 527 case .CompleteDate: 528 dateFormatter = "yyyy-MM-dd" 529 case .CompleteDatePlusHoursAndMinutes, .CompleteDatePlusHoursAndMinutesAndZ: 530 dateFormatter = "yyyy-MM-dd'T'HH:mmZ" 531 case .CompleteDatePlusHoursMinutesAndSeconds, .CompleteDatePlusHoursAndMinutesAndSecondsAndZ: 532 dateFormatter = "yyyy-MM-dd'T'HH:mm:ssZ" 533 case .CompleteDatePlusHoursMinutesSecondsAndDecimalFractionOfSecond, .CompleteDatePlusHoursMinutesSecondsAndDecimalFractionOfSecondAndZ: 534 dateFormatter = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 535 } 536 } 537 return dateFormatter 538 } 539 540 /** 541 Create a new NSDate instance based on refDate (if nil uses current date) and set components 542 543 :param: refDate reference date instance (nil to use NSDate()) 544 :param: year year component (nil to leave it untouched) 545 :param: month month component (nil to leave it untouched) 546 :param: day day component (nil to leave it untouched) 547 :param: tz time zone component (it's the abbreviation of NSTimeZone, like 'UTC' or 'GMT+2', nil to use current time zone) 548 549 :returns: a new NSDate with components changed according to passed params 550 */ 551 class func date(refDate refDate: NSDate?, year: Int?, month: Int?, day: Int?, tz: String?) -> NSDate { 552 let referenceDate = refDate ?? NSDate() 553 return referenceDate.set(year: year, month: month, day: day, hour: 0, minute: 0, second: 0, tz: tz) 554 } 555 556 /** 557 Create a new NSDate instance based on refDate (if nil uses current date) and set components 558 559 :param: refDate reference date instance (nil to use NSDate()) 560 :param: year year component (nil to leave it untouched) 561 :param: month month component (nil to leave it untouched) 562 :param: day day component (nil to leave it untouched) 563 :param: hour hour component (nil to leave it untouched) 564 :param: minute minute component (nil to leave it untouched) 565 :param: second second component (nil to leave it untouched) 566 :param: tz time zone component (it's the abbreviation of NSTimeZone, like 'UTC' or 'GMT+2', nil to use current time zone) 567 568 :returns: a new NSDate with components changed according to passed params 569 */ 570 class func date(refDate refDate: NSDate?, year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int, tz: String?) -> NSDate { 571 let referenceDate = refDate ?? NSDate() 572 return referenceDate.set(year: year, month: month, day: day, hour: hour, minute: minute, second: second, tz: tz) 573 } 574 575 /** 576 Return a new NSDate instance with the current date and time set to 00:00:00 577 578 :param: tz optional timezone abbreviation 579 580 :returns: a new NSDate instance of the today's date 581 */ 582 class func today(tz: String? = nil) -> NSDate! { 583 let nowDate = NSDate() 584 return NSDate.date(refDate: nowDate, year: nowDate.year, month: nowDate.month, day: nowDate.day, tz: tz) 585 } 586 587 /** 588 Return a new NSDate istance with the current date minus one day 589 590 :param: tz optional timezone abbreviation 591 592 :returns: a new NSDate instance which represent yesterday's date 593 */ 594 class func yesterday(tz: String? = nil) -> NSDate! { 595 return today(tz)-1.day 596 } 597 598 /** 599 Return a new NSDate istance with the current date plus one day 600 601 :param: tz optional timezone abbreviation 602 603 :returns: a new NSDate instance which represent tomorrow's date 604 */ 605 class func tomorrow(tz: String? = nil) -> NSDate! { 606 return today(tz)+1.day 607 } 608 609 /** 610 Individual set single component of the current date instance 611 612 :param: year a non-nil value to change the year component of the instance 613 :param: month a non-nil value to change the month component of the instance 614 :param: day a non-nil value to change the day component of the instance 615 :param: hour a non-nil value to change the hour component of the instance 616 :param: minute a non-nil value to change the minute component of the instance 617 :param: second a non-nil value to change the second component of the instance 618 :param: tz a non-nil value (timezone abbreviation string as for NSTimeZone) to change the timezone component of the instance 619 620 :returns: a new NSDate instance with changed values 621 */ 622 func set(year year: Int?=nil, month: Int?=nil, day: Int?=nil, hour: Int?=nil, minute: Int?=nil, second: Int?=nil, tz: String?=nil) -> NSDate! { 623 let components = self.components 624 components.year = year ?? self.year 625 components.month = month ?? self.month 626 components.day = day ?? self.day 627 components.hour = hour ?? self.hour 628 components.minute = minute ?? self.minute 629 components.second = second ?? self.second 630 components.timeZone = (tz != nil ? NSTimeZone(abbreviation: tz!) : NSTimeZone.defaultTimeZone()) 631 return NSCalendar.currentCalendar().dateFromComponents(components) 632 } 633 634 /** 635 Allows you to set individual date components by passing an array of components name and associated values 636 637 :param: componentsDict components dict. Accepted keys are year,month,day,hour,minute,second 638 639 :returns: a new date instance with altered components according to passed dictionary 640 */ 641 func set(componentsDict componentsDict: [String:Int]!) -> NSDate? { 642 if componentsDict.count == 0 { 643 return self 644 } 645 let components = self.components 646 for (thisComponent,value) in componentsDict { 647 let unit : NSCalendarUnit = thisComponent._sdToCalendarUnit() 648 components.setValue(value, forComponent: unit); 649 } 650 return NSCalendar.currentCalendar().dateFromComponents(components) 651 } 652 653 /** 654 Allows you to set a single component by passing it's name (year,month,day,hour,minute,second are accepted). 655 Please note: this method return a new immutable NSDate instance (NSDate are immutable, damn!). So while you 656 can chain multiple set calls, if you need to alter more than one component see the method above which accept 657 different params. 658 659 :param: name the name of the component to alter (year,month,day,hour,minute,second are accepted) 660 :param: value the value of the component 661 662 :returns: a new date instance 663 */ 664 func set(name : String!, value : Int!) -> NSDate? { 665 let unit : NSCalendarUnit = name._sdToCalendarUnit() 666 if unit == [] { 667 return nil 668 } 669 let components = self.components 670 components.setValue(value, forComponent: unit); 671 return NSCalendar.currentCalendar().dateFromComponents(components) 672 } 673 674 /** 675 Add or subtract (via negative values) components from current date instance 676 677 :param: years nil or +/- years to add or subtract from date 678 :param: months nil or +/- months to add or subtract from date 679 :param: weeks nil or +/- weeks to add or subtract from date 680 :param: days nil or +/- days to add or subtract from date 681 :param: hours nil or +/- hours to add or subtract from date 682 :param: minutes nil or +/- minutes to add or subtract from date 683 :param: seconds nil or +/- seconds to add or subtract from date 684 685 :returns: a new NSDate instance with changed values 686 */ 687 func add(years years: Int=0, months: Int=0, weeks: Int=0, days: Int=0,hours: Int=0,minutes: Int=0,seconds: Int=0) -> NSDate { 688 let components = NSDateComponents() 689 components.year = years 690 components.month = months 691 components.weekOfYear = weeks 692 components.day = days 693 components.hour = hours 694 components.minute = minutes 695 components.second = seconds 696 return self.addComponents(components) 697 } 698 699 /** 700 Add/substract (based on sign) specified component with value 701 702 :param: name component name (year,month,day,hour,minute,second) 703 :param: value value of the component 704 705 :returns: new date with altered component 706 */ 707 func add(name : String!, value : Int!) -> NSDate? { 708 let unit : NSCalendarUnit = name._sdToCalendarUnit() 709 if unit == [] { 710 return nil 711 } 712 let components = NSDateComponents() 713 components.setValue(value, forComponent: unit); 714 return self.addComponents(components) 715 } 716 717 /** 718 Add value specified by components in passed dictionary to the current date 719 720 :param: componentsDict dictionary of the component to alter with value (year,month,day,hour,minute,second) 721 722 :returns: new date with altered components 723 */ 724 func add(componentsDict componentsDict: [String:Int]!) -> NSDate? { 725 if componentsDict.count == 0 { 726 return self 727 } 728 let components = NSDateComponents() 729 for (thisComponent,value) in componentsDict { 730 let unit : NSCalendarUnit = thisComponent._sdToCalendarUnit() 731 components.setValue(value, forComponent: unit); 732 } 733 return self.addComponents(components) 734 } 735 } 736 737 //MARK: TIMEZONE UTILITIES 738 739 public extension NSDate { 740 /** 741 Return a new NSDate in UTC format from the current system timezone 742 743 :returns: a new NSDate instance 744 */ 745 func toUTC() -> NSDate { 746 let tz : NSTimeZone = NSTimeZone.localTimeZone() 747 let secs : Int = tz.secondsFromGMTForDate(self) 748 return NSDate(timeInterval: NSTimeInterval(secs), sinceDate: self) 749 } 750 751 /** 752 Convert an UTC NSDate instance to a local time NSDate (note: NSDate object does not contains info about the timezone!) 753 754 :returns: a new NSDate instance 755 */ 756 func toLocalTime() -> NSDate { 757 let tz : NSTimeZone = NSTimeZone.localTimeZone() 758 let secs : Int = -tz.secondsFromGMTForDate(self) 759 return NSDate(timeInterval: NSTimeInterval(secs), sinceDate: self) 760 } 761 762 /** 763 Convert an UTC NSDate instance to passed timezone (note: NSDate object does not contains info about the timezone!) 764 765 :param: abbreviation abbreviation of the time zone 766 767 :returns: a new NSDate instance 768 */ 769 func toTimezone(abbreviation : String!) -> NSDate? { 770 let tz : NSTimeZone? = NSTimeZone(abbreviation: abbreviation) 771 if tz == nil { 772 return nil 773 } 774 let secs : Int = tz!.secondsFromGMTForDate(self) 775 return NSDate(timeInterval: NSTimeInterval(secs), sinceDate: self) 776 } 777 } 778 779 //MARK: COMPARE DATES 780 781 public extension NSDate { 782 783 /** 784 Return the difference in terms of NSDateComponents between two dates. 785 786 - parameter toDate: other date to compare 787 - parameter unitFlags: components to compare 788 789 - returns: result of comparision as NSDateComponents 790 */ 791 func difference(toDate: NSDate, unitFlags: NSCalendarUnit) -> NSDateComponents { 792 let calendar = NSCalendar.currentCalendar() 793 let components = calendar.components(unitFlags, fromDate: self, toDate: toDate, options: NSCalendarOptions(rawValue: 0)) 794 return components 795 } 796 797 /** 798 * This function is deprecated. See -difference 799 */ 800 @available(*, deprecated=1.2, obsoleted=1.4, renamed="difference") 801 func secondsAfterDate(date: NSDate) -> Int { 802 let interval = self.timeIntervalSinceDate(date) 803 return Int(interval) 804 } 805 806 /** 807 * This function is deprecated. See -difference 808 */ 809 @available(*, deprecated=1.2, obsoleted=1.4, renamed="difference") 810 func secondsBeforeDate(date: NSDate) -> Int { 811 let interval = date.timeIntervalSinceDate(self) 812 return Int(interval) 813 } 814 815 /** 816 * This function is deprecated. See -difference 817 */ 818 @available(*, deprecated=1.2, obsoleted=1.4, renamed="difference") 819 func minutesAfterDate(date: NSDate) -> Int { 820 let interval = self.timeIntervalSinceDate(date) 821 return Int(interval / NSTimeInterval(D_MINUTE)) 822 } 823 824 /** 825 * This function is deprecated. See -difference 826 */ 827 @available(*, deprecated=1.2, obsoleted=1.4, renamed="difference") 828 func minutesBeforeDate(date: NSDate) -> Int { 829 let interval = date.timeIntervalSinceDate(self) 830 return Int(interval / NSTimeInterval(D_MINUTE)) 831 } 832 833 /** 834 * This function is deprecated. See -difference 835 */ 836 @available(*, deprecated=1.2, obsoleted=1.4, renamed="difference") 837 func hoursAfterDate(date: NSDate) -> Int { 838 let interval = self.timeIntervalSinceDate(date) 839 return Int(interval / NSTimeInterval(D_HOUR)) 840 } 841 842 /** 843 * This function is deprecated. See -difference 844 */ 845 @available(*, deprecated=1.2, obsoleted=1.4, renamed="difference") 846 func hoursBeforeDate(date: NSDate) -> Int { 847 let interval = date.timeIntervalSinceDate(self) 848 return Int(interval / NSTimeInterval(D_HOUR)) 849 } 850 851 /** 852 * This function is deprecated. See -difference 853 */ 854 @available(*, deprecated=1.2, obsoleted=1.4, renamed="difference") 855 func daysAfterDate(date: NSDate) -> Int { 856 let interval = self.timeIntervalSinceDate(date) 857 return Int(interval / NSTimeInterval(D_DAY)) 858 } 859 860 /** 861 * This function is deprecated. See -difference 862 */ 863 @available(*, deprecated=1.2, obsoleted=1.4, renamed="difference") 864 func daysBeforeDate(date: NSDate) -> Int { 865 let interval = date.timeIntervalSinceDate(self) 866 return Int(interval / NSTimeInterval(D_DAY)) 867 } 868 869 /** 870 Compare two dates and return true if they are equals 871 872 :param: date date to compare with 873 :param: ignoreTime true to ignore time of the date 874 875 :returns: true if two dates are equals 876 */ 877 func isEqualToDate(date: NSDate, ignoreTime: Bool) -> Bool { 878 if ignoreTime { 879 let comp1 = NSDate.components(fromDate: self) 880 let comp2 = NSDate.components(fromDate: date) 881 return ((comp1.era == comp2.era) && (comp1.year == comp2.year) && (comp1.month == comp2.month) && (comp1.day == comp2.day)) 882 } else { 883 return self.isEqualToDate(date) 884 } 885 } 886 887 /** 888 Return true if given date's time in passed range 889 890 :param: minTime min time interval (by default format is "HH:mm", but you can specify your own format in format parameter) 891 :param: maxTime max time interval (by default format is "HH:mm", but you can specify your own format in format parameter) 892 :param: format nil or a valid format string used to parse minTime and maxTime from their string representation (when nil HH:mm is used) 893 894 :returns: true if date's time component falls into given range 895 */ 896 func isInTimeRange(minTime: String!, maxTime: String!, format: String?) -> Bool { 897 let dateFormatter = NSDate.localThreadDateFormatter() 898 dateFormatter.dateFormat = format ?? "HH:mm" 899 dateFormatter.timeZone = NSTimeZone(abbreviation: "UTC") 900 let minTimeDate = dateFormatter.dateFromString(minTime) 901 let maxTimeDate = dateFormatter.dateFromString(maxTime) 902 if minTimeDate == nil || maxTimeDate == nil { 903 return false 904 } 905 let inBetween = (self.compare(minTimeDate!) == NSComparisonResult.OrderedDescending && 906 self.compare(maxTimeDate!) == NSComparisonResult.OrderedAscending) 907 return inBetween 908 } 909 910 /** 911 Return true if the date's year is a leap year 912 913 :returns: true if date's year is a leap year 914 */ 915 func isLeapYear() -> Bool { 916 let year = self.year 917 return year % 400 == 0 ? true : ((year % 4 == 0) && (year % 100 != 0)) 918 } 919 920 /** 921 Return the number of days in current date's month 922 923 :returns: number of days of the month 924 */ 925 func monthDays () -> Int { 926 return NSCalendar.currentCalendar().rangeOfUnit(NSCalendarUnit.Day, inUnit: NSCalendarUnit.Month, forDate: self).length 927 } 928 929 /** 930 True if the date is the current date 931 932 :returns: true if date is today 933 */ 934 func isToday() -> Bool { 935 return self.isEqualToDate(NSDate(), ignoreTime: true) 936 } 937 938 /** 939 True if the date is the current date plus one day (tomorrow) 940 941 :returns: true if date is tomorrow 942 */ 943 func isTomorrow() -> Bool { 944 return self.isEqualToDate(NSDate()+1.day, ignoreTime:true) 945 } 946 947 /** 948 True if the date is the current date minus one day (yesterday) 949 950 :returns: true if date is yesterday 951 */ 952 func isYesterday() -> Bool { 953 return self.isEqualToDate(NSDate()-1.day, ignoreTime:true) 954 } 955 956 /** 957 Return true if the date falls into the current week 958 959 :returns: true if date is inside the current week days range 960 */ 961 func isThisWeek() -> Bool { 962 return self.isSameWeekOf(NSDate()) 963 } 964 965 /** 966 Return true if the date falls into the current month 967 968 :returns: true if date is inside the current month 969 */ 970 func isThisMonth() -> Bool { 971 return self.isSameMonthOf(NSDate()) 972 } 973 974 /** 975 Return true if the date falls into the current year 976 977 :returns: true if date is inside the current year 978 */ 979 func isThisYear() -> Bool { 980 return self.isSameYearOf(NSDate()) 981 } 982 983 /** 984 Return true if the date is in the same week of passed date 985 986 :param: date date to compare with 987 988 :returns: true if both dates falls in the same week 989 */ 990 func isSameWeekOf(date: NSDate) -> Bool { 991 let comp1 = NSDate.components(fromDate: self) 992 let comp2 = NSDate.components(fromDate: date) 993 // Must be same week. 12/31 and 1/1 will both be week "1" if they are in the same week 994 if comp1.weekOfYear != comp2.weekOfYear { 995 return false 996 } 997 // Must have a time interval under 1 week 998 let weekInSeconds = NSTimeInterval(D_WEEK) 999 return abs(self.timeIntervalSinceDate(date)) < weekInSeconds 1000 } 1001 1002 /** 1003 Return the first day of the passed date's week (Sunday) 1004 1005 :returns: NSDate with the date of the first day of the week 1006 */ 1007 func dateAtWeekStart() -> NSDate { 1008 let flags : NSCalendarUnit = [NSCalendarUnit.Year,NSCalendarUnit.Month , 1009 NSCalendarUnit.WeekOfYear, 1010 NSCalendarUnit.Weekday] 1011 let components = NSCalendar.currentCalendar().components(flags, fromDate: self) 1012 components.weekday = 1 // Sunday 1013 components.hour = 0 1014 components.minute = 0 1015 components.second = 0 1016 return NSCalendar.currentCalendar().dateFromComponents(components)! 1017 } 1018 1019 /// Return a date which represent the beginning of the current day (at 00:00:00) 1020 var beginningOfDay: NSDate { 1021 return set(hour: 0, minute: 0, second: 0) 1022 } 1023 1024 /// Return a date which represent the end of the current day (at 23:59:59) 1025 var endOfDay: NSDate { 1026 return set(hour: 23, minute: 59, second: 59) 1027 } 1028 1029 /// Return the first day of the month of the current date 1030 var beginningOfMonth: NSDate { 1031 return set(day: 1, hour: 0, minute: 0, second: 0) 1032 } 1033 1034 /// Return the last day of the month of the current date 1035 var endOfMonth: NSDate { 1036 let lastDay = NSCalendar.currentCalendar().rangeOfUnit(.Day, inUnit: .Month, forDate: self).length 1037 return set(day: lastDay, hour: 23, minute: 59, second: 59) 1038 } 1039 1040 /// Returns true if the date is in the same month of passed date 1041 func isSameMonthOf(date: NSDate) -> Bool { 1042 return self >= date.beginningOfMonth && self <= date.endOfMonth 1043 } 1044 1045 /// Return the first day of the year of the current date 1046 var beginningOfYear: NSDate { 1047 return set(month: 1, day: 1, hour: 0, minute: 0, second: 0) 1048 } 1049 1050 /// Return the last day of the year of the current date 1051 var endOfYear: NSDate { 1052 return set(month: 12, day: 31, hour: 23, minute: 59, second: 59) 1053 } 1054 1055 /// Returns true if the date is in the same year of passed date 1056 func isSameYearOf(date: NSDate) -> Bool { 1057 return self >= date.beginningOfYear && self <= date.endOfYear 1058 } 1059 1060 /** 1061 Return true if current date's day is not a weekend day 1062 1063 :returns: true if date's day is a week day, not a weekend day 1064 */ 1065 func isWeekday() -> Bool { 1066 return !self.isWeekend() 1067 } 1068 1069 /** 1070 Return true if the date is the weekend 1071 1072 :returns: true or false 1073 */ 1074 func isWeekend() -> Bool { 1075 let range = NSCalendar.currentCalendar().maximumRangeOfUnit(NSCalendarUnit.Weekday) 1076 return (self.weekday == range.location || self.weekday == range.length) 1077 } 1078 1079 } 1080 1081 //MARK: CONVERTING DATE TO STRING 1082 1083 public extension NSDate { 1084 1085 /** 1086 Return a formatted string with passed style for date and time 1087 1088 :param: dateStyle style of the date component into the output string 1089 :param: timeStyle style of the time component into the output string 1090 :param: relativeDate true to use relative date style 1091 1092 :returns: string representation of the date 1093 */ 1094 public func toString(dateStyle dateStyle: NSDateFormatterStyle, timeStyle: NSDateFormatterStyle, relativeDate: Bool = false) -> String { 1095 let dateFormatter = NSDate.localThreadDateFormatter() 1096 dateFormatter.dateStyle = dateStyle 1097 dateFormatter.timeStyle = timeStyle 1098 dateFormatter.doesRelativeDateFormatting = relativeDate 1099 return dateFormatter.stringFromDate(self) 1100 } 1101 1102 /** 1103 Return a new string which represent the NSDate into passed format 1104 1105 :param: format format of the output string. Choose one of the available format or use a custom string 1106 1107 :returns: a string with formatted date 1108 */ 1109 public func toString(format format: DateFormat) -> String { 1110 var dateFormat: String 1111 switch format { 1112 case .ISO8601: 1113 dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" 1114 case .RSS: 1115 dateFormat = "EEE, d MMM yyyy HH:mm:ss ZZZ" 1116 case .AltRSS: 1117 dateFormat = "d MMM yyyy HH:mm:ss ZZZ" 1118 case .Custom(let string): 1119 dateFormat = string 1120 } 1121 let dateFormatter = NSDate.localThreadDateFormatter() 1122 dateFormatter.dateFormat = dateFormat 1123 return dateFormatter.stringFromDate(self) 1124 } 1125 1126 /** 1127 Return an ISO8601 formatted string from the current date instance 1128 1129 :returns: string with date in ISO8601 format 1130 */ 1131 public func toISOString() -> String { 1132 let dateFormatter = NSDate.localThreadDateFormatter() 1133 dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") 1134 dateFormatter.timeZone = NSTimeZone(abbreviation: "UTC") 1135 dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS" 1136 return dateFormatter.stringFromDate(self).stringByAppendingString("Z") 1137 } 1138 1139 /** 1140 Return a relative string which represent the date instance 1141 1142 :param: fromDate comparison date (by default is the current NSDate()) 1143 :param: abbreviated true to use abbreviated unit forms (ie. "ys" instead of "years") 1144 :param: maxUnits max detail units to print (ie. "1 hour 47 minutes" is maxUnit=2, "1 hour" is maxUnit=1) 1145 1146 :returns: formatted string 1147 */ 1148 public func toRelativeString(fromDate: NSDate = NSDate(), abbreviated : Bool = false, maxUnits: Int = 1) -> String { 1149 let seconds = fromDate.timeIntervalSinceDate(self) 1150 if fabs(seconds) < 1 { 1151 return "just now"._sdLocalize 1152 } 1153 1154 let significantFlags : NSCalendarUnit = NSDate.componentFlags() 1155 let components = NSCalendar.currentCalendar().components(significantFlags, fromDate: fromDate, toDate: self, options: []) 1156 1157 var string = String() 1158 //var isApproximate:Bool = false 1159 var numberOfUnits:Int = 0 1160 let unitList : [String] = ["year", "month", "weekOfYear", "day", "hour", "minute", "second"] 1161 for unitName in unitList { 1162 let unit : NSCalendarUnit = unitName._sdToCalendarUnit() 1163 if ((significantFlags.rawValue & unit.rawValue) != 0) && 1164 (_sdCompareCalendarUnit(NSCalendarUnit.Second, other: unit) != .OrderedDescending) { 1165 let number:NSNumber = NSNumber(float: fabsf(components.valueForKey(unitName)!.floatValue)) 1166 if Bool(number.integerValue) { 1167 let singular = (number.unsignedIntegerValue == 1) 1168 let suffix = String(format: "%@ %@", arguments: [number, _sdLocalizeStringForValue(singular, unit: unit, abbreviated: abbreviated)]) 1169 if string.isEmpty { 1170 string = suffix 1171 } else if numberOfUnits < maxUnits { 1172 string += String(format: " %@", arguments: [suffix]) 1173 } else { 1174 // isApproximate = true 1175 } 1176 numberOfUnits += 1 1177 } 1178 } 1179 } 1180 1181 /*if string.isEmpty == false { 1182 if seconds > 0 { 1183 string = String(format: "%@ %@", arguments: [string, "ago"._sdLocalize]) 1184 } else { 1185 string = String(format: "%@ %@", arguments: [string, "from now"._sdLocalize]) 1186 } 1187 1188 if (isApproximate) { 1189 string = String(format: "about %@", arguments: [string]) 1190 } 1191 }*/ 1192 return string 1193 } 1194 1195 /** 1196 Return a string representation of the date where both date and time are in short style format 1197 1198 :returns: date's string representation 1199 */ 1200 public func toShortString() -> String { 1201 return toString(dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.ShortStyle) 1202 } 1203 1204 /** 1205 Return a string representation of the date where both date and time are in medium style format 1206 1207 :returns: date's string representation 1208 */ 1209 public func toMediumString() -> String { 1210 return toString(dateStyle: NSDateFormatterStyle.MediumStyle, timeStyle: NSDateFormatterStyle.MediumStyle) 1211 } 1212 1213 /** 1214 Return a string representation of the date where both date and time are in long style format 1215 1216 :returns: date's string representation 1217 */ 1218 public func toLongString() -> String { 1219 return toString(dateStyle: NSDateFormatterStyle.LongStyle, timeStyle: NSDateFormatterStyle.LongStyle) 1220 } 1221 1222 /** 1223 Return a string representation of the date with only the date in short style format (no time) 1224 1225 :returns: date's string representation 1226 */ 1227 public func toShortDateString() -> String { 1228 return toString(dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.NoStyle) 1229 } 1230 1231 /** 1232 Return a string representation of the date with only the time in short style format (no date) 1233 1234 :returns: date's string representation 1235 */ 1236 public func toShortTimeString() -> String { 1237 return toString(dateStyle: NSDateFormatterStyle.NoStyle, timeStyle: NSDateFormatterStyle.ShortStyle) 1238 } 1239 1240 /** 1241 Return a string representation of the date with only the date in medium style format (no date) 1242 1243 :returns: date's string representation 1244 */ 1245 public func toMediumDateString() -> String { 1246 return toString(dateStyle: NSDateFormatterStyle.MediumStyle, timeStyle: NSDateFormatterStyle.NoStyle) 1247 } 1248 1249 /** 1250 Return a string representation of the date with only the time in medium style format (no date) 1251 1252 :returns: date's string representation 1253 */ 1254 public func toMediumTimeString() -> String { 1255 return toString(dateStyle: NSDateFormatterStyle.NoStyle, timeStyle: NSDateFormatterStyle.MediumStyle) 1256 } 1257 1258 /** 1259 Return a string representation of the date with only the date in long style format (no date) 1260 1261 :returns: date's string representation 1262 */ 1263 public func toLongDateString() -> String { 1264 return toString(dateStyle: NSDateFormatterStyle.LongStyle, timeStyle: NSDateFormatterStyle.NoStyle) 1265 } 1266 1267 /** 1268 Return a string representation of the date with only the time in long style format (no date) 1269 1270 :returns: date's string representation 1271 */ 1272 public func toLongTimeString() -> String { 1273 return toString(dateStyle: NSDateFormatterStyle.NoStyle, timeStyle: NSDateFormatterStyle.LongStyle) 1274 } 1275 1276 } 1277 1278 //MARK: PRIVATE ACCESSORY METHODS 1279 1280 private extension NSDate { 1281 1282 private class func components(fromDate fromDate: NSDate) -> NSDateComponents! { 1283 return NSCalendar.currentCalendar().components(NSDate.componentFlags(), fromDate: fromDate) 1284 } 1285 1286 private func addComponents(components: NSDateComponents) -> NSDate { 1287 let cal = NSCalendar.currentCalendar() 1288 return cal.dateByAddingComponents(components, toDate: self, options: [])! 1289 } 1290 1291 private class func componentFlags() -> NSCalendarUnit { 1292 return [NSCalendarUnit.Era , 1293 NSCalendarUnit.Year , 1294 NSCalendarUnit.Month , 1295 NSCalendarUnit.Day, 1296 NSCalendarUnit.WeekOfYear, 1297 NSCalendarUnit.Hour , 1298 NSCalendarUnit.Minute , 1299 NSCalendarUnit.Second , 1300 NSCalendarUnit.Weekday , 1301 NSCalendarUnit.WeekdayOrdinal, 1302 NSCalendarUnit.WeekOfYear] 1303 } 1304 1305 /// Return the NSDateComponents which represent current date 1306 private var components: NSDateComponents { 1307 return NSCalendar.currentCalendar().components(NSDate.componentFlags(), fromDate: self) 1308 } 1309 1310 /** 1311 This function uses NSThread dictionary to store and retrive a thread-local object, creating it if it has not already been created 1312 1313 :param: key identifier of the object context 1314 :param: create create closure that will be invoked to create the object 1315 1316 :returns: a cached instance of the object 1317 */ 1318 private class func cachedObjectInCurrentThread<T: AnyObject>(key: String, create: () -> T) -> T { 1319 if let threadDictionary = NSThread.currentThread().threadDictionary as NSMutableDictionary? { 1320 if let cachedObject = threadDictionary[key] as! T? { 1321 return cachedObject 1322 } else { 1323 let newObject = create() 1324 threadDictionary[key] = newObject 1325 return newObject 1326 } 1327 } else { 1328 assert(false, "Current NSThread dictionary is nil. This should never happens, we will return a new instance of the object on each call") 1329 return create() 1330 } 1331 } 1332 1333 /** 1334 Return a thread-cached NSDateFormatter instance 1335 1336 :returns: instance of NSDateFormatter 1337 */ 1338 private class func localThreadDateFormatter() -> NSDateFormatter { 1339 return NSDate.cachedObjectInCurrentThread("com.library.swiftdate.dateformatter") { 1340 let dateFormatter = NSDateFormatter() 1341 dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" 1342 return dateFormatter 1343 } 1344 } 1345 } 1346 1347 //MARK: RELATIVE NSDATE CONVERSION PRIVATE METHODS 1348 1349 private extension NSDate { 1350 func _sdCompareCalendarUnit(unit:NSCalendarUnit, other:NSCalendarUnit) -> NSComparisonResult { 1351 let nUnit = _sdNormalizedCalendarUnit(unit) 1352 let nOther = _sdNormalizedCalendarUnit(other) 1353 1354 if (nUnit == NSCalendarUnit.WeekOfYear) != (nOther == NSCalendarUnit.WeekOfYear) { 1355 if nUnit == NSCalendarUnit.WeekOfYear { 1356 switch nUnit { 1357 case NSCalendarUnit.Year, NSCalendarUnit.Month: 1358 return .OrderedAscending 1359 default: 1360 return .OrderedDescending 1361 } 1362 } else { 1363 switch nOther { 1364 case NSCalendarUnit.Year, NSCalendarUnit.Month: 1365 return .OrderedDescending 1366 default: 1367 return .OrderedAscending 1368 } 1369 } 1370 } else { 1371 if nUnit.rawValue > nOther.rawValue { 1372 return .OrderedAscending 1373 } else if (nUnit.rawValue < nOther.rawValue) { 1374 return .OrderedDescending 1375 } else { 1376 return .OrderedSame 1377 } 1378 } 1379 } 1380 1381 private func _sdNormalizedCalendarUnit(unit:NSCalendarUnit) -> NSCalendarUnit { 1382 switch unit { 1383 case NSCalendarUnit.WeekOfMonth, NSCalendarUnit.WeekOfYear: 1384 return NSCalendarUnit.WeekOfYear 1385 case NSCalendarUnit.Weekday, NSCalendarUnit.WeekdayOrdinal: 1386 return NSCalendarUnit.Day 1387 default: 1388 return unit; 1389 } 1390 } 1391 1392 1393 func _sdLocalizeStringForValue(singular : Bool, unit: NSCalendarUnit, abbreviated: Bool = false) -> String { 1394 var toTranslate : String = "" 1395 switch unit { 1396 1397 case NSCalendarUnit.Year where singular: toTranslate = (abbreviated ? "yr" : "year") 1398 case NSCalendarUnit.Year where !singular: toTranslate = (abbreviated ? "yrs" : "years") 1399 1400 case NSCalendarUnit.Month where singular: toTranslate = (abbreviated ? "mo" : "month") 1401 case NSCalendarUnit.Month where !singular: toTranslate = (abbreviated ? "mos" : "months") 1402 1403 case NSCalendarUnit.WeekOfYear where singular: toTranslate = (abbreviated ? "wk" : "week") 1404 case NSCalendarUnit.WeekOfYear where !singular: toTranslate = (abbreviated ? "wks" : "weeks") 1405 1406 case NSCalendarUnit.Day where singular: toTranslate = "day" 1407 case NSCalendarUnit.Day where !singular: toTranslate = "days" 1408 1409 case NSCalendarUnit.Hour where singular: toTranslate = (abbreviated ? "hr" : "hour") 1410 case NSCalendarUnit.Hour where !singular: toTranslate = (abbreviated ? "hrs" : "hours") 1411 1412 case NSCalendarUnit.Minute where singular: toTranslate = (abbreviated ? "min" : "minute") 1413 case NSCalendarUnit.Minute where !singular: toTranslate = (abbreviated ? "mins" : "minutes") 1414 1415 case NSCalendarUnit.Second where singular: toTranslate = (abbreviated ? "s" : "second") 1416 case NSCalendarUnit.Second where !singular: toTranslate = (abbreviated ? "s" : "seconds") 1417 1418 default: toTranslate = "" 1419 } 1420 return toTranslate._sdLocalize 1421 } 1422 1423 func localizedSimpleStringForComponents(components:NSDateComponents) -> String { 1424 if (components.year == -1) { 1425 return "last year"._sdLocalize 1426 } else if (components.month == -1 && components.year == 0) { 1427 return "last month"._sdLocalize 1428 } else if (components.weekOfYear == -1 && components.year == 0 && components.month == 0) { 1429 return "last week"._sdLocalize 1430 } else if (components.day == -1 && components.year == 0 && components.month == 0 && components.weekOfYear == 0) { 1431 return "yesterday"._sdLocalize 1432 } else if (components == 1) { 1433 return "next year"._sdLocalize 1434 } else if (components.month == 1 && components.year == 0) { 1435 return "next month"._sdLocalize 1436 } else if (components.weekOfYear == 1 && components.year == 0 && components.month == 0) { 1437 return "next week"._sdLocalize 1438 } else if (components.day == 1 && components.year == 0 && components.month == 0 && components.weekOfYear == 0) { 1439 return "tomorrow"._sdLocalize 1440 } 1441 return "" 1442 } 1443 } 1444 1445 //MARK: OPERATIONS WITH DATES (==,!=,<,>,<=,>=) 1446 1447 extension NSDate : Comparable {} 1448 1449 public func == (left: NSDate, right: NSDate) -> Bool { 1450 return (left.compare(right) == NSComparisonResult.OrderedSame) 1451 } 1452 1453 public func != (left: NSDate, right: NSDate) -> Bool { 1454 return !(left == right) 1455 } 1456 1457 public func < (left: NSDate, right: NSDate) -> Bool { 1458 return (left.compare(right) == NSComparisonResult.OrderedAscending) 1459 } 1460 1461 public func > (left: NSDate, right: NSDate) -> Bool { 1462 return (left.compare(right) == NSComparisonResult.OrderedDescending) 1463 } 1464 1465 public func <= (left: NSDate, right: NSDate) -> Bool { 1466 return !(left > right) 1467 } 1468 1469 public func >= (left: NSDate, right: NSDate) -> Bool { 1470 return !(left < right) 1471 } 1472 1473 //MARK: ARITHMETIC OPERATIONS WITH DATES (-,-=,+,+=) 1474 1475 public func - (left : NSDate, right: NSTimeInterval) -> NSDate { 1476 return left.dateByAddingTimeInterval(-right) 1477 } 1478 1479 public func -= (inout left: NSDate, right: NSTimeInterval) { 1480 left = left.dateByAddingTimeInterval(-right) 1481 } 1482 1483 public func + (left: NSDate, right: NSTimeInterval) -> NSDate { 1484 return left.dateByAddingTimeInterval(right) 1485 } 1486 1487 public func += (inout left: NSDate, right: NSTimeInterval) { 1488 left = left.dateByAddingTimeInterval(right) 1489 } 1490 1491 public func - (left: NSDate, right: CalendarType) -> NSDate { 1492 let calendarType = right.copy() 1493 calendarType.amount = -calendarType.amount 1494 let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! 1495 let dateComponents = calendarType.dateComponents() 1496 let finalDate = calendar.dateByAddingComponents(dateComponents, toDate: left, options: [])! 1497 return finalDate 1498 } 1499 1500 public func -= (inout left: NSDate, right: CalendarType) { 1501 left = left - right 1502 } 1503 1504 public func + (left: NSDate, right: CalendarType) -> NSDate { 1505 let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! 1506 return calendar.dateByAddingComponents(right.dateComponents(), toDate: left, options: [])! 1507 } 1508 1509 public func += (inout left: NSDate, right: CalendarType) { 1510 left = left + right 1511 } 1512 1513 public func - (left: NSDate, right: NSDate) -> NSTimeInterval { 1514 return left.timeIntervalSinceDate(right) 1515 } 1516 1517 //MARK: SUPPORTING STRUCTURES 1518 1519 public class CalendarType { 1520 var calendarUnit : NSCalendarUnit 1521 var amount : Int 1522 1523 init(amount : Int) { 1524 self.calendarUnit = [] 1525 self.amount = amount 1526 } 1527 1528 init(amount: Int, calendarUnit: NSCalendarUnit) { 1529 self.calendarUnit = calendarUnit 1530 self.amount = amount 1531 } 1532 1533 func dateComponents() -> NSDateComponents { 1534 return NSDateComponents() 1535 } 1536 1537 func copy() -> CalendarType { 1538 return CalendarType(amount: self.amount, calendarUnit: self.calendarUnit) 1539 } 1540 } 1541 1542 public class MonthCalendarType : CalendarType { 1543 1544 override init(amount : Int) { 1545 super.init(amount: amount) 1546 self.calendarUnit = NSCalendarUnit.Month 1547 } 1548 1549 override func dateComponents() -> NSDateComponents { 1550 let components = super.dateComponents() 1551 components.month = self.amount 1552 return components 1553 } 1554 1555 override func copy() -> MonthCalendarType { 1556 let objCopy = MonthCalendarType(amount: self.amount) 1557 objCopy.calendarUnit = self.calendarUnit 1558 return objCopy; 1559 } 1560 } 1561 1562 public class YearCalendarType : CalendarType { 1563 1564 override init(amount : Int) { 1565 super.init(amount: amount, calendarUnit: NSCalendarUnit.Year) 1566 } 1567 1568 override func dateComponents() -> NSDateComponents { 1569 let components = super.dateComponents() 1570 components.year = self.amount 1571 return components 1572 } 1573 1574 override func copy() -> YearCalendarType { 1575 let objCopy = YearCalendarType(amount: self.amount) 1576 objCopy.calendarUnit = self.calendarUnit 1577 return objCopy 1578 } 1579 } 1580 1581 public extension Int { 1582 var seconds : NSTimeInterval { 1583 return NSTimeInterval(self) 1584 } 1585 var second : NSTimeInterval { 1586 return (self.seconds) 1587 } 1588 var minutes : NSTimeInterval { 1589 return (self.seconds*60) 1590 } 1591 var minute : NSTimeInterval { 1592 return self.minutes 1593 } 1594 var hours : NSTimeInterval { 1595 return (self.minutes*60) 1596 } 1597 var hour : NSTimeInterval { 1598 return self.hours 1599 } 1600 var days : NSTimeInterval { 1601 return (self.hours*24) 1602 } 1603 var day : NSTimeInterval { 1604 return self.days 1605 } 1606 var weeks : NSTimeInterval { 1607 return (self.days*7) 1608 } 1609 var week : NSTimeInterval { 1610 return self.weeks 1611 } 1612 var workWeeks : NSTimeInterval { 1613 return (self.days*5) 1614 } 1615 var workWeek : NSTimeInterval { 1616 return self.workWeeks 1617 } 1618 var months : MonthCalendarType { 1619 return MonthCalendarType(amount: self) 1620 } 1621 var month : MonthCalendarType { 1622 return self.months 1623 } 1624 var years : YearCalendarType { 1625 return YearCalendarType(amount: self) 1626 } 1627 var year : YearCalendarType { 1628 return self.years 1629 } 1630 } 1631 1632 //MARK: PRIVATE STRING EXTENSION 1633 1634 private extension String { 1635 1636 var _sdLocalize: String { 1637 return NSBundle.mainBundle().localizedStringForKey(self, value: nil, table: "SwiftDates") 1638 } 1639 1640 func _sdToCalendarUnit() -> NSCalendarUnit { 1641 switch self { 1642 case "year": 1643 return NSCalendarUnit.Year 1644 case "month": 1645 return NSCalendarUnit.Month 1646 case "weekOfYear": 1647 return NSCalendarUnit.WeekOfYear 1648 case "day": 1649 return NSCalendarUnit.Day 1650 case "hour": 1651 return NSCalendarUnit.Hour 1652 case "minute": 1653 return NSCalendarUnit.Minute 1654 case "second": 1655 return NSCalendarUnit.Second 1656 default: 1657 return [] 1658 } 1659 } 1660 } 1661 1662 public enum DateFormat { 1663 case ISO8601, RSS, AltRSS 1664 case Custom(String) 1665 } 1666 1667 let D_SECOND = 1 1668 let D_MINUTE = 60 1669 let D_HOUR = 3600 1670 let D_DAY = 86400 1671 let D_WEEK = 604800 1672 let D_YEAR = 31556926 1673 `) 1674 return _buf.String() 1675 }