GrandTime--操作iOS的時間更簡單

例行上圖

有一個多月沒有更新簡書了,因為工作確實比較忙,天天加班。現在APP已經上線,是時侯繼續我的寫作之旅了。這次項目里面會進行大量的日期時間操作。比如獲取某日期年月日,時分。兩個日期的比較。設置某個日期的時間等操作。總之這次開發過程中不友好NSDate和其相關類的API讓我感到不爽,感覺iOS原生的日期類非常不好用。于是我便萌生了自己寫一個關于操作NSDate的類的想法,因以我以前是用C#,感覺C#的日期時間類比較優雅,我便參考它寫了個iOS的DateTime,今天我便分享給大家。

iOS對日期和時間的操作的不足

NSDate是iOS表示日期時間的核心類。但是它也只能表示時間,如果需要格式化輸出,需要使用到NSDateFormatter類,而如果需要取出里面的年月日和時分秒,則需要用到NSDateComponentsNSCalendar。相信每一位iOS開發者都會掌握這些類的使用,這里就不寫示例代碼了。雖然職責分離是一種好的設計,但是需要你大量對日期時間的比較,格式化輸出等操作時,使用這些類來非常繁瑣,要寫很多的重復的代碼,影響了開發效率。GrandTime正是解決這個問題而生的。

GrandTime組成

GrandTime由三個類組成:DateTime,TimeSpanGrandTimerDateTime是最核心的類,封裝了NSDateNSDateComponents。把年月日時分秒的操作變得十分簡單方便。而TimeSpan是一段時間間隔,相當于NSTimeInterval,同時還封裝了很多功能。而GrandTimer是一個會自動停止的弱Timer,并且提供了Block來方便調用。下面我一個一個來介紹怎么使用。

DateTime

DateTime類封裝了常見的日期時間操作。它提供了如下8個構造函數

DateTime的構造函數

相信這8個構造函數可以滿足絕大部分的使用場景。里面有兩個需要說明一下,tick在里面是指毫秒,而timestampUnix時間戳。默認的無參構造函數和NSDate一樣,都是使用當前時間。
下面看看代碼

//正面看看構造函數
let a = DateTime() //直接初始化
print(a)
let c = DateTime(date: NSDate(timeInterval: 3600, sinceDate: NSDate())) //使用NSDate初始化
print(c)
let e = DateTime(tick: 1000000) //使用Tick初始化  從1970年開始
print(e)
let f = DateTime(tickSinceNow: 60000) //使用Tick初始化  從現在年開始
print(f)
let g = DateTime(timestamp: 100000)//使用Stamp初始化
print(g)
let h = DateTime(year: 2008, month: 2, day: 29) //使用年月日初始化
print(h)
let i = DateTime(year: 2016, month: 12, day: 12, hour: 11, minute: 44, second: 12, millisecond: 111)!//使用年月日時分秒毫秒初始化
print(i)
打印結果:
2016-07-18 15:04:37:779
2016-07-18 16:04:37:779
Optional(1970-01-01 08:16:40:000)//注意里面存在初始化失敗這種情況,我沒有直接拋出異常,而是返回可選值。
Optional(2016-07-18 15:05:37:780)
Optional(1970-01-02 11:46:40:000)
Optional(2008-02-29 00:00:00:000)
2016-12-12 11:44:12:000

我為DateTime提供了操作符重載

let timeSpanOneMinute = TimeSpan.fromMinuts(1)   //聲明一個一分鐘的TimeSpan
let dToOneMinuteBefore = a - timeSpanOneMinute      // 一分鐘前
print("一分鐘前\(dToOneMinuteBefore)")
let dToOneMinuteAfter = a + timeSpanOneMinute // 一分鐘后
print("一分鐘后\(dToOneMinuteAfter)")
        
  //兩個DateTime相減生成一個TimeSpan
let span = c - a
        
print("a和c相差一小時\(span)")
print("a>c:\(a>c)")
print("a<c:\(a<c)")
打印結果:
一分鐘前2016-07-18 15:14:10:274
一分鐘后2016-07-18 15:16:10:274
a和c相差一小時Optional(1:00:00:000)
a>c:false
a<c:true

DateTime也提供了一系列Add方法,可以對自身操作。改變自己的時間值。

DateTime的Add系列方法
a.addYears(1)   //加一年
print("add Years:\(a)")
a.addMonth(1)   // 加 一個月
print("add addMonth:\(a)")
a.addDays(1)    // 加一天
print("add addDays:\(a)")
a.addHours(1)   // 加一個小時
print("add addHours:\(a)")
a.addMinutes(1) // 加一分鐘
print("add addMinutes:\(a)")
a.addSeconds(1) // 加一秒
print("add addSeconds:\(a)")
打印結果:
add Years:2017-07-18 17:20:09:080
add addMonth:2017-08-18 17:20:09:080
add addDays:2017-08-19 17:20:09:080
add addHours:2017-08-19 18:20:09:080
add addMinutes:2017-08-19 18:21:09:080
add addSeconds:2017-08-19 18:21:10:080

使用DateTime來獲取日期時間的每個部分也是非常簡單,同時也支持單獨設值

print("獲取i的各部分:year:\(i.year),   month:\(i.month),   day:\(i.day),   hour:\(i.hour),   minute:\(i.minute),   second:\(i.second),   minute:\(i.minute),   ticks:\(i.ticks),   ")
        
//還可以直接設置各部分
i.year = 2015
i.month = 1
i.day = 12
i.hour = 12
i.minute = 23
i.second = 12
i.millisecond = 555
print("再次獲取i的各部分:year:\(i.year),   month:\(i.month),   day:\(i.day),   hour:\(i.hour),   minute:\(i.minute),   second:\(i.second),   minute:\(i.minute),   ticks:\(i.ticks),   ")
//打印結果
獲取i的各部分:year:2016,   month:12,   day:12,   hour:11,   minute:44,   second:12,   minute:44,   ticks:1481514252000,   
再次獲取i的各部分:year:2015,   month:1,   day:12,   hour:12,   minute:23,   second:12,   minute:23,   ticks:1421036592555,   


//獲取季度和星期相關數據
print("星期幾:\(i.weekDay)")
print("第幾季度:\(i.quarter)")
print("一年的第幾周:\(i.weekOfYear)")
print("一個月的第幾周:\(i.weekOfMonth)")
print("一年的第幾天:\(i.dayOfYear)")
//打印結果
星期幾:Wendesday
第幾季度:0
一年的第幾周:3
一個月的第幾周:3
一年的第幾天:43

最后就是格式化輸出了,DateTime使用了一個單例的NSDateFormatter,這樣可以防止不必要的頻繁實例化NSDateFormatter。下面看看輸出

print("獲取日期部分\(i.dateString)")  //獲取日期部分
print("獲取時間部分\(i.timeString)")     //獲取時間部分  
print("默認格式\(i.format())")
print("自定義格式\(i.format("yyyy年MM月dd日#EEEE"))")
print("各種輸出style的原生的一樣")
print("LongStyle: \(i.format(.ShortStyle, timeFormat: .ShortStyle))")
print("LongStyle: \(i.format(.MediumStyle, timeFormat: .MediumStyle))")
print("LongStyle: \(i.format(.LongStyle, timeFormat: .LongStyle))")
print("LongStyle: \(i.format(.FullStyle, timeFormat: .FullStyle))")

i.local = NSLocale(localeIdentifier: "en_US")

print("把地區設為US"),
print("LongStyle: \(i.format(.ShortStyle, timeFormat: .ShortStyle))")
print("LongStyle: \(i.format(.MediumStyle, timeFormat: .MediumStyle))")
print("LongStyle: \(i.format(.LongStyle, timeFormat: .LongStyle))")
print("LongStyle: \(i.format(.FullStyle, timeFormat: .FullStyle))")

//打印結果
獲取日期部分2015-01-12
獲取時間部分12:23:12
默認格式2015-01-12 12:23:12:555
自定義格式2015年01月12日#Monday
各種輸出style的原生的一樣
LongStyle: 15/1/12 下午12:23
LongStyle: 2015年1月12日 下午12:23:12
LongStyle: 2015年1月12日 GMT+8 下午12:23:12
LongStyle: 2015年1月12日 星期一 中國標準時間 下午12:23:12
把地區設為US
LongStyle: 1/12/15, 12:23 PM
LongStyle: Jan 12, 2015, 12:23:12 PM
LongStyle: January 12, 2015 at 12:23:12 PM GMT+8
LongStyle: Monday, January 12, 2015 at 12:23:12 PM China Standard Time

DateTime的用法在上面的代碼基本可以全部找到。更多的用法請參考原代碼或者API。可見,使用DateTime還操作時間還是很方便的。

TimeSpan

同樣,為了更好地使用時間間隔,我寫了TimeSpan來專門處理時間間隔。TimeSpan類比較簡單一點,下面直接上代碼


      //先看看構造函數
        
let o = TimeSpan()                                     //直接初始化
print(o)
let p = TimeSpan(days: 1, hours: 0, minutes: 11, seconds: 31)   //使用天,小時,分鐘,秒來初始化
print(p)
let q = TimeSpan(days: 20, hours: 11, minutes: 39, seconds: 21, milliseconds: 111)!   //使用天,小時,分鐘,秒還有來初始化
print(q)
let r = TimeSpan(ticks: 9826127)   //使用tick來初始化
print(r)
        
//打印結果
0:00:00:000 //全是0
Optional(1 0:11:31:000) //1天11分鐘31秒
20 11:39:21:111 //20天11小時39分鐘21秒111毫秒
2:43:46:127 //2小時43分鐘46秒127毫秒

TimeSpan的構造函數不多,也比較簡單。里面最大的時間間隔單位是天這個單位。因為天可以一直累加,所以也足夠用了。同樣,使用from系列靜態函數也可以自己想要的時間間隔,

From系列靜態函數

從圖中可以看出,很多函數所傳遞的變量是Double類型的, 也就是說,可以給它傳小數值。下面看看代碼吧

//使用from 函數
print("使用from函數")
var s = TimeSpan.fromDays(1) //一天
print(s)
s = TimeSpan.fromHours(2.5) //2.5小時
print(s)
s = TimeSpan.fromMinuts(89.2)//89.2分鐘
print(s)
s = TimeSpan.fromSeconds(134)//134秒
print(s)
s = TimeSpan.fromTicks(123123123)//123123123 tick
//打印結果
使用from函數
1 0:00:00:000
2:30:00:000
1:29:12:000
0:02:14:000
1 10:12:03:123

可以單獨取和設定某個屬性

//下面獲取部分
print("獲取i的各部分:  day:\(q.days),   hour:\(q.hours),   minute:\(q.minutes),   second:\(q.seconds),   minute:\(q.milliseconds),   ticks:\(q.ticks),   ")
//獲取計算的總體部分
print("獲取i的各部分:  totalDays:\(q.totalDays),   totalHours:\(q.totalHours),   totalMinutes:\(q.totalMinutes),   second:\(q.totalSeconds)")
//單獨設定屬性
q.days = 4
q.hours = 22
q.minutes = 12
q.seconds = 32
q.milliseconds = 343
print("獲取i的各部分:  day:\(q.days),   hour:\(q.hours),   minute:\(q.minutes),   second:\(q.seconds),   minute:\(q.milliseconds),   ticks:\(q.ticks),   ")
print("獲取i的各部分:  totalDays:\(q.totalDays),   totalHours:\(q.totalHours),   totalMinutes:\(q.totalMinutes),   second:\(q.totalSeconds)")

//打印結果
獲取i的各部分:  day:20,   hour:11,   minute:39,   second:21,   minute:111,   ticks:1769961111,   
獲取i的各部分:  totalDays:20.4856610069444,   totalHours:491.655864166667,   totalMinutes:29499.35185,   second:1769961.111
獲取i的各部分:  day:4,   hour:22,   minute:12,   second:32,   minute:343,   ticks:426239657,   
獲取i的各部分:  totalDays:4.93332936342593,   totalHours:118.399904722222,   totalMinutes:7103.99428333333,   second:426239.657

DateTime一樣,重載了運算符號來實現TimeSpan之間也的加減操作,

print("下面看加減")
s = s.add(r)  //可以用這個加
print(s)
        
s = s.subtract(r)  //可以用這個減
print(s)
print("運算符+ - 也一樣")
s = s + r
print(s)
s = s - r
print(s)
打印結果
下面看加減
1 12:55:49:250
1 10:12:03:123
運算符+ - 也一樣
1 12:55:49:250
1 10:12:03:123

OK, 上面就是DateTimeTimeSpan的各種用法,相信它們可以滿足大部分項目的需求,如果不夠,自己也可以寫擴展來實現。

GrandTime還提供了一個計時器GrandTimer。和NSTimer不一樣,GrandTimer不會強引用當前類。所以不會出現NSTimer那種只要不調用valifdate()方法就會在內存里一直運行這種情況。使用GrandTimer非常簡單,直接使用其靜態方法即可

weak var weakSelf = self
//使用者要注意,這個timer本身是weak的,所以需要一個外部變量來強引用, 不然出這代碼區域,就會被內存回收導致計時器不能運行
//如果要讓timer正確地釋放內存,那么要使用weakself
 timer =  GrandTimer.every(TimeSpan.fromSeconds(1)) {
      weakSelf!.seco2 = weakSelf!.seco2 + 1
      weakSelf!.lblTimer.text = "\(weakSelf!.seco2)"
 }
//如果要暫停
  timer?.invalidate()
// 重寫了該ViewController的deinit
    deinit{
        print("\(self.dynamicType)) the view deinit which means the timer release in the viewcontrollre")
    }
   //如果pop該ViewController出去,這個時侯會打印
TimerViewController) the view deinit which means the timer release in the viewcontrollre
//說明該View已經正確地被內存釋放了

GrandTimer也提供了一個selector版本,不過需要自己提供一個線程,這種用法用NSTimer很類似。

let dispatch = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT)
timer = GrandTimer.scheduleTimerWithTimeSpan(TimeSpan.fromSeconds(1), target: self, sel: #selector(TimerViewController.tick), userInfo: nil, repeats: true, dispatchQueue: dispatch)
        timer?.fire()

以上就是GrandTime的所有功能的展示的,我已經將這個項目加入了Cocoapods。 使用起來非常簡單,直接pod‘GrandTime’就可以啦,如果你不想用Cocoapods,那么也可以將里面的文件直接拖到項目里面。Git地址:GrandTime。 如果你們喜歡的話,麻煩給個Star。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容