github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgRpc/kmgRpcSwift/tplGenerateCode.go (about)

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