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