天生不是作曲家iOS专题iOS小功能点

GrandTime--操作iOS的时间更简单

2016-07-19  本文已影响733人  黑暗中的孤影
例行上图

有一个多月没有更新简书了,因为工作确实比较忙,天天加班。现在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。

上一篇下一篇

猜你喜欢

热点阅读