处理日期的常见情景
-
NSDate -> String & String -> NSDate
-
日期比较
-
日期计算(基于参考日期 +/- 一定时间)
-
计算日期间的差异
-
拆解NSDate对象(分解成year/month/day/hour/minute/second 等)
NSDate相关类
-
NSDate
-
DateFormatter
-
DateComponents
-
DateComponentFormatter
-
Calendar
-
Date structure: Swift3.0中引入了Date structure, 和NSDate提供的功能相似, 并且Date结构体和NSDate类可以在Swift中交替使用以此达到和Objective-C APIs的交互. Date结构体的引入和Swift中引入了String, Array等类型一样, 都是为了让对应的类桥接Foundation中对应的类(String -> NSString, Array -> NSArray)
注: 在下面的代码片段中, NSDate和Date会交替使用,功能都是相同的.
基本概念
NSDate和String之间的转换
DateComponents
-
在很多情景中,你可能需要将日期的值进行拆解,进而提取其中特定的值.比如你可能需要得到一个日期中天数和月份的值,或者从时间里面得到小时和分钟的值,这部分将会介绍DateComponents类以此来解决这个问题. 需要注意的是,DateComponents类会经常和Calendar搭配使用,具体来讲,Calendar类的方法是真正实现了Date到DateComponents的转换,以及逆转换.记住这一点之后,首先先得到currentCalendar对象,并且将它赋值给常量以便于后面的使用.
let calendar = Calendar.current()
-
下面的代码通过一个典型的例子演示一遍Date -> DateComponents的过程.
let dateComponents = calendar.components([Calendar.Unit.era, Calendar.Unit.year, Calendar.Unit.month, Calendar.Unit.day, Calendar.Unit.hour, Calendar.Unit.minute, Calendar.Unit.second], from: currentDate)
print("era:(dateComponents.era) year:(dateComponents.year) month:(dateComponents.month) day: (dateComponents.day) hour:(dateComponents.hour) minute:(dateComponents.minute) second: (dateComponents.second)")
// era:Optional(1) year:Optional(2016) month:Optional(8) day:Optional(19) hour:Optional(15) minute:Optional(29) second:Optional(13)
-
上面用到了Calendar类中的components(_:from:) 方法. 这个方法接收两个参数, 第二个传入的参数是将要被拆解的日期对象,第一个参数比较有意思, 这个参数是一个数组,里面放入组成日期的各个成分单位(Calendar.Unit),比如月(Calendar.Unit.month), 日(Calendar.Unit.day).
-
Calendar.Unit是一个结构体, 它里面的所有属性及说明可以在官方文档中查看.
-
还需要注意的一点就是在components(_:from:) 方法的第一个数组参数中,如果没有传入想要解析的单位名称,之后从DateComponents对象中是得不到这个单位的, 比如上面的方法中没有传入Calendar.Unit.month, 那么最后打印的时候如果也打印了该值, 得到的值会是nil.
dateComponents = calendar.components([Calendar.Unit.year], from: currentDate)
print("year:(dateComponents.year) month:(dateComponents.month)")
// Optional(2016) month:nil
-
DateComponents -> Date
-
DateComponents -> Date的转换也十分简单, 只需要初始化一个DateComponents对象, 然后指定特定的components, 最后调用Calendar类的dateFromComponents:方法完成转换
var components = DateComponents()
components.year = 1985
components.month = 02
components.day = 05
components.hour = 07
components.minute = 08
components.second = 44
let dateFromComponents = calendar.date(from: components)
print(dateFromComponents) // Optional(1985-02-04 23:08:44 +0000)
-
这里同样可以设置不同的时区来得到当地的时间:
components.timeZone = TimeZone(abbreviation: "GMT") // Greenwich Mean Time
components.timeZone = TimeZone(abbreviation: "CST") // China Standard Time
components.timeZone = TimeZone(abbreviation: "CET") // Central European Time
比较日期和时间
-
除了以上提到的应用场景, 另一个关于日期和时间常见的应用场景就是比较. 通过对两个Date对象的比较以此来判断哪个日期更早或者更迟,或者是否日期相同. 这里将会介绍3种方法来做比较, 方法不分好坏, 适合自己的需求最重要.
-
在开始进行比较之前, 先创建两个Date对象用于下面的比较:
dateFormatter.dateFormat = "MMM dd, yyyy zzz"
dateString = "May 08, 2016 GMT"
var date1 = dateFormatter.date(from: dateString)
dateString = "May 10, 2016 GMT"
var date2 = dateFormatter.date(from: dateString)
print("date1:(date1)----date2:(date2)")
// date1:Optional(2016-05-08 00:00:00 +0000)
// date2:Optional(2016-05-10 00:00:00 +0000)
方法1 (earlierDate: || laterDate:)
方法2 (compare: )
方法3 (timeIntervalSinceReferenceDate)
-
第三个方法有点不同, 原理是分别将date1 和 date2 与一个参考日期进行比对, 然后通过判断两个日期和参考日期的差距, 进而判断两个日期的差距.
-
举一个例子: 比较4和10两个数字, 先选取6作为一个参考数字, 4-6=-2;10-6=4,4-(-2)=6.
if date1?.timeIntervalSinceReferenceDate > date2?.timeIntervalSinceReferenceDate {
print("date1 is later")
} else if date1?.timeIntervalSinceReferenceDate < date2?.timeIntervalSinceReferenceDate {
print("date2 is later")
} else if date1?.timeIntervalSinceReferenceDate == date2?.timeIntervalSinceReferenceDate {
print("Same Date")
}
日期的计算
方法1
var calculatedDate = calendar.date(byAdding: Calendar.Unit.month, value: monthsToAdd, to: currentDate, options: Calendar.Options.init(rawValue: 0))
calculatedDate = calendar.date(byAdding: Calendar.Unit.day, value: daysToAdd, to: calculatedDate!, options: Calendar.Options.init(rawValue: 0))
print(calculatedDate) // Optional(2016-10-24 08:33:41 +0000)
-
如上面代码所示, 这里使用了dateByAddingUnit:value:toDate:options: 方法. 这个方法就是将特定的日期单位值加到现有的日期值上, 然后返回一个新的Date对象. 因为这里的例子要加两个值, 所以需要调用该方法两次.
方法2
-
方法1虽然可行, 但有缺点, 即每一个单位的计算都需要分别调用方法, 假如想给当前日期加上7年3个月4天8小时23分钟34秒, 那么就要调用dateByAddingUnit:value:toDate:options: 方法6次! 而方法2则可以对这个问题迎刃而解. 而方法2有一次使用到了DateComponents这个类.
-
下面我将首先初始化一个新的DateComponents对象, 然后设置月份和天数, 然后再调用Calendar类中名为dateByAddingComponents:toDate:options: 的方法, 该方法的返回值就是计算好的Date对象.
var newDateComponents = DateComponents()
newDateComponents.month = 2
newDateComponents.day = 5
calculatedDate = calendar.date(byAdding: newDateComponents, to: currentDate, options: Calendar.Options.init(rawValue: 0))
print(calculatedDate) // Optional(2016-10-24 08:47:57 +0000)
日期差值的计算
方法1
方法2
-
这里介绍的第二个方法将会第一次使用到DateComponentsFormatter类. DateComponentsFormatter类提供了很多不同的方法进行日期间自动的计算,并且返回值是格式化的字符串.
-
首先初始化一个DateComponentsFormatter对象, 然后先指定它的一个属性值.
let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.unitsStyle = DateComponentsFormatter.UnitsStyle.full
let interval = date2?.timeIntervalSince(date1!)
var diffString = dateComponentsFormatter.string(from: interval!)
print(diffString) // Optional("-31 years, 6 months, 0 weeks, 3 days, 10 hours, 39 minutes, 39 seconds")
-
UnitsStyle属性会指定最后结果输出的格式. 这里使用full,就代表结果输出的单位会全名显示,如Monday,June等.如果想用简写,就可以重新设置属性.官方文档中列出了所有的属性值。
方法3
dateComponentsFormatter.allowedUnits = [Calendar.Unit.year]
diffString = dateComponentsFormatter.string(from: date1!, to: date2!)
print(diffString) // Optional("-31 years")
-
最后一个方法调用了stringFrom:to: 方法来计算. 注意使用该方法之前, 必须至少在allowedUnits属性中设置一个calendar unit, 否则这个方法将会返回nil, 所以在使用该方法之前, 先指定想要怎么样看到输出, 然后再让执行输出的方法。
总结
就像我在摘要中说的, 处理日期很常见, 在日常代码中也不可避免, 这里我通过一些小的代码片段介绍了处理日期的一些常见方法. 不管是NSDate类,Date结构体还是与之相关联的类, 它们的目的只有一个, 就是能够快速的处理日期. 如果想深入掌握有关日期的处理, 还是要在日常编码过程中多多练习, 多多阅读官方文档。
学习收藏, 转自:
Swift3.0中关于日期类的使用指引
其他开发过程中遇到的问题,后续将进行补充。。。
|
请发表评论