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  <?}?>