Swift 的 NSDate 初学者指南

Swift 的 NSDate 初学者指南

2015.12.14 22:43javascript

若是问我在作过的全部项目中作的最多的事情,那处理日期绝对是榜上有名(译注:本文中的「日期」是指代 NSDate 对象,同时包含「日(date)」 和「时(time)」这两个元素)。毋庸置疑,不管工做量是可能是少,开发者早晚须要「玩」一下 NSDate 类,去按某种方式处理一下日期。从简单的将一个日期转换成一个字符串到对日期作计算,总会有一个不变的事实:开发者必须在 iOS 编程中学会这个知识点。这并不难掌握,并且能够为之后更重要任务节省时间。在新手看来,对日期的操做很麻烦;然而事实并不是如此。你须要作的就是掌握它。php

在应用中对日期(NSDate)对象最多见的操做就是把它转换成一个字符串对象,这样就能够用正确的格式把它展现给用户。反向操做也很常见:把字符串转换成日期对象。然而日期的操做并不仅有这些。下面是一个简单的列表,列出了除上述操做以外能够对日期进行的其余操做:html

  • 日期之间的比较。
  • 计算将来或者过去的日期,很简单:用一个参考日期(好比当前日期)加上或者减去一段时间(天、月、年等等)。
  • 计算不一样日期之间的差值(好比算出两个特定日期之间的时间间隔有多久)。
  • 将一个日期按其组成元素(components)作分解,并对每一个部分作分别访问(天、月等等)。

上面列出的全部内容,包括日期和字符串之间的相互转换,都是这篇教程要讨论的主题。在接下来的各个小节中,你会发现只要你知道该用什么工具以及如何使用它们,你就能为所欲为的对日期进行操做。java

 
 

下面的连接清单里有不少重要的文章,供参考。若是须要深刻了解某些特定知识点,别忘了点击访问一下:ios

关于 Demo App

嗯,这个教程咱们不使用 demo 应用(是的,你没看错)。取而代之,咱们此次用一个 Playground来展现你将要看到的全部例子。我是特地这么作的,由于个人目的是给你提供丰富的、能更好的展现出关于 NSDate方方面面的代码。程序员

你能够下载并在 Xcode 中打开这个写好的 playground 文件,但我仍是强烈建议你新建一个 Playground 文件,并测试下面章节中的每个新代码段。这样会让你更容易的去理解每一个示例是如何工做的,除此以外你还能够修改代码,实时观察你的修改会如何影响生成的结果。编程

我给你的 playground 文件名是 PlayingWithDates,里面包含了全部的代码。你本身的文件能够用相同的文件名,或者换一个,都无所谓。swift

基本概念

在咱们开始查看日期相关的技术细节并思考能用它们作什么以前,先要确保每一个人都已经掌握一些基本概念,这很重要。先从一个最简单的开始:NSDate对象。从程序角度来讲这种对象包含了对日(date)时(time)二者的描述,因此它不只仅能够帮咱们处理「日」,还能够帮咱们处理「时」。对于 NSDate对象自己来讲是没有格式(formatting)这个概念的;和其余类中的全部属性同样,能够把日和时看作是属性(properties)。只有在将一个日期对象转换成一个字符串时,格式这个概念才会派上用场,下面的内容里咱们会看到不少关于这个的细节。一般来说,记住你所须要的就是 NSDate这个类,不管你只关心「日」、「时」或者二者。数组

接下来咱们会遇到的另外一个类是 NSDateComponents。能够把这个类看作 NSDate的「姊妹」类,由于这个类给开发者提供了一些极为有用的特性和操做。这个类的第一个要点是它能够将「日」部分或者「时」部分做为一个单独的属性显示出来,因此咱们能够直接访问「日」或者「时」,而后在其余的任务中使用(好比对「日」或「时」的计算)。例如,一个 NSDateComponents实例中的天和月在下面的代码中表示为 day和 month属性:安全

let dateComponents = NSDateComponents() let day = dateComponents.day let month = dateComponents.month 

就这么简单。固然访问日期元素并将该日期的值传递给一个 NSDateComponents对象须要先作一些强制转换,这些咱们以后再讨论。

除上所述以外,NSDateComponents这个类在用于计算将来或者过去的日期时也很是有用。当你想获得一个在某个特定日期以后或以前的那个日期时,你要作的就是加上或者减去合适的那一部分,最终就能转换成一个新的日期。另外 NSDateComponents也适合计算日期之间的差值。如今无需深刻研究这两个内容,咱们一下子会看到细节。

对于 NSCalendar类,虽然它不会派上大用场,并且咱们仅须要用它来实现 NSDate和 NSDateComponents相互转换,但它在咱们的日期游戏中也是重要的一员。关于它所支持的特性,本文不会再进行介绍。将日期从 NSDate转换成 NSDateComponents(或者反过来)的任务属于 NSCalendar类,按照惯例,作转换须要一个特定的 c alendar(日历)对象。实际上系统在作任何转换以前都须要知道要用一个怎样的 calendar 对象,从而才可能给出正确的结果(别忘了满世界有太多不一样的 calendar 对象,转换出来的「天」、「月」等值会千差万别)。你能够读一些和 calendar 有关的文章(参考简介里的连接),而在这里为图简便,咱们会用 NSCalendar的类方法 currentCalendar()来获得用户设置中指定的 calendar。

此外,在下一节中咱们会使用一个特别好的工具,它就是 NSDateFormatter类。它可以实现 NSDate对象到字符串、以及字符串到 NSDate对象的转换。它还可使用预约义的日期样式(date styles)来给最终的日期字符串制定格式,或是经过给出指望格式的描述来实现高度格式样式定制。下面会有一些相关的例子,其中一些例子示范了双向转换。一个 NSDateFormatter对象一样也支持本地化(localization);咱们所须要的就是给它提供一个有效的 NSLocale对象,基于该给定的位置(locale)设置最终转换出的对象就会正确显示出来。

还有个相似的 NSDateComponentsFormatter类,它能够将「日」和「时」部分做为输入,输出人类可读的、有特定格式的日期字符串。对此这个类包含了不少方法(methods),在此教程的最后一部分咱们会看见其中几个;咱们只讨论在教程的例子中用到的那些知识点。

上面已经说了那么多,咱们能够开始编程了,具体学习上面提到的每一个类的用法。再说一次,建议你建立一个新的 playground 文件,而后把我介绍的每一条都试一下。没有什么学习方法比亲手作更有效果。

NSDate 和 String 之间的转换

首先,咱们使用 NSDate得到当前日期,并将它赋给一个常量以便访问。和其余一些语言所要求的不一样,得到当前的日期并不须要调用相似 now()或者 today()的特殊方法。你所要作的就是初始化一个 NSDate对象:

let currentDate = NSDate() 

在 Xcode 的 playground 里敲入上面的语句,你会看到:

 

注意咱们会在下面的代码中屡次使用到上面的这个值。如今初始化一个 NSDateFormatter对象。它用来在 dates 和 strings 之间作转换。以下

let dateFormatter = NSDateFormatter() 

除非是有其余明确的设定,不然 dateFormatter会默认采用设备中的位置(locale)设置。尽管系统并不要求你去手动设置当前的位置,但若是须要的话你能够这么作:

dateFormatter.locale = NSLocale.currentLocale() 

设一个不一样的位置很容易:你仅须要知道与位置(locale)相匹配的位置标识符(locale identifier)是什么,而后指定给 locale 属性便可:

dateFormatter.locale = NSLocale(localeIdentifier: "el_GR") dateFormatter.locale = NSLocale(localeIdentifier: "fr_FR") 

这两行代码展现了如何给 date formatter 去设置一个不一样的位置(例子里分别是希腊和法国地区)。固然设置多个位置的值没有意义,由于能起做用的仅仅是最后一个。你是否是想知道 locale 是怎么影响日期和字符串之间的转换的呢?过会儿你就会获得答案。

用 Date formatter styles 为输出结果设置格式

把一个日期对象(NSDate)转换成一个字符串以前,你须要「告诉」date formatter 你要获得的字符串结果的格式是怎样的。这里有两种方法。第一种是使用预约义的 date formatter styles,第二种是使用某些特定的分类符(specifier)来手动指定最终输出结果的格式。

先用第一种方法,咱们须要使用 NSDateFormatterStyle enum。这个枚举类型的每个枚举值都表明一种不一样的格式样式类型。第一个样式是 FullStyle,下面的图片是使用它的效果:

 

下面是上面代码的文本,想复制的话随意:

dateFormatter.dateStyle = NSDateFormatterStyle.FullStyle
var convertedDate = dateFormatter.stringFromDate(currentDate) 

除了日期样式(date style)以外,上面两行代码中的 stringFromDate:方法也同等重要,这个方法实现了真正的转换。当谈及转换时,咱们实际上说的是这个方法,其他的只不过是自定义结果格式过程当中所需的一些步骤。若是你想要在你的项目里作日期的转换,那么这个方法对你来讲确定很是方便。

好,来看下一个样式,Long Style

 

文本形式的代码:

dateFormatter.dateStyle = NSDateFormatterStyle.LongStyle convertedDate = dateFormatter.stringFromDate(currentDate) 

能够看到这种类型的样式中不包含星期几(和 Full Style 相比而言)。下面是 Medium Style

 
dateFormatter.dateStyle = NSDateFormatterStyle.MediumStyle convertedDate = dateFormatter.stringFromDate(currentDate) 

最后是 Short Style

dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle convertedDate = dateFormatter.stringFromDate(currentDate) 

如今你已经知道可用的 date formatter styles 都是什么了,你能够根据项目需求去使用它们。每种样式的设置都会产生出一个不一样的结果,可能其中有一种会适合你。

以前我说过 date formatter 的 locale 能够被设置成非默认值。如今咱们已经看到如何使用 date formatter styles 作转换,咱们再来看看不一样的 locale 值如何改变初始日期的字符串转换结果。下面的例子中我会使用 Full Style,以及前面提到的两个 locale identifier(希腊和法国)。

 

我想如今 locale 能作什么你已经很清楚了,好好使用它吧。


使用 Date format specifier

上面的 date formatter style 足以应对多数状况,可是咱们没法经过修改这些格式来得到不一样于预设格式的结果。这种状况下咱们还有另外一个选择,一个能设置自定义 date format的能力,这个自定义的 date format 可以正确描述你理想中的 date formatter 对象的的格式样式。通常来讲设置一个自定义的 date format 对如下两种状况很适用:当 date formatter style 实现不了你所指望的输出结果的样式时(显然),还有当你须要把一个复杂的日期字符串(好比“Thu, 08 Oct 2015 09:22:33 GMT”)转换成一个日期对象时。

为了正确的设置一个 date format,必定要用一组分类符(specifier)。Specifier 不过是一些简单的字符,这些字符对 date formatter 对象来讲有着特定的意义。在我给你具体的例子以前,先列出来一些在接下来的代码中会使用到的format specifier:

  • EEEE:表示星期几(如 Monday)。使用 1-3 个字母表示周几的缩略写法。
  • MMMM:月份的全写(如 October)。使用 1-3 个字母表示月份的缩略写法。
  • dd:表示一个月里面日期的数字(如 09 或 15)。
  • yyyy:4 个数字表示的年(如 2015)。
  • HH:2 个数字表示的小时(如 08 或 19)。
  • mm:2 个数字表示的分钟(如 05 或者 54)。
  • ss:2 个数字表示的秒。
  • zzz:3 个字母表示的时区(如 GMT)。
  • GGG:BC 或者 AD。

若是想查看 date format specifiers 的参考内容,建议访问官方技术规范,你能够找到上面给出的 specifier 的使用方法,以及那些没有列出的 specifier。

继续咱们的例子,看一下 format specifier 具体怎么用。这回咱们把当前日期转换成一个字符串,显示成具备星期名称、月的全写,日期数字和年份的格式:

 
dateFormatter.dateFormat = "EEEE, MMMM dd, yyyy" convertedDate = dateFormatter.stringFromDate(currentDate) 

我想怎么用自定义的 date format 已经不须要额外的讲解了,用法十分简单。再来一个例子,转换一下时间:

 
dateFormatter.dateFormat = "HH:mm:ss" convertedDate = dateFormatter.stringFromDate(currentDate) 

到如今为止咱们看到的全部转换都是从 NSDate对象变成一个有特定格式的字符串。相反的操做也颇有意思,以前关于 date formatter styles 和 format specifiers 的也一样适用。把有既定格式的字符串转换成一个 NSDate对象的关键是要对 date formatter 的 dateFormat属性作出正确设置,而后调用 dateFromString:方法。咱们再看几个例子:

 
var dateAsString = "24-12-2015 23:59" dateFormatter.dateFormat = "dd-MM-yyyy HH:mm" var newDate = dateFormatter.dateFromString(dateAsString) 

再看一个更复杂的字符串,还包含了时区:

 
dateAsString = "Thu, 08 Oct 2015 09:22:33 GMT" dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz" newDate = dateFormatter.dateFromString(dateAsString) 

注意一下时间(09:22)是如何经过简单的、在日期字符串中引入了一个时区而发生改变的(变成了 12:22)。这里没有任何实际上的变化,仅仅是我所在的时区(EFT)的时间在 GMT 时区中的表示,基于上面的代码,根据你本身的状况自由发挥吧。

到这里你已经基本上看到了为实现日期和字符串之间的转换你所须要的全部知识点。你能够敲敲本身的代码,试试你在上面所看到的那些,深刻感觉一下这些东西是如何工做的。



使用 NSDateComponents

不少时候你须要在项目里拆分一个日期对象,而后从中得到特定组成元素的值。例如你可能会从一个日期对象中获取它的日和月的值,或者从时间中得到小时和分钟的值。此种状况下你须要用到的工具就是 NSDateComponents这个类。

NSDateComponents类一般和 NSCalendar类相结合来使用。具体点说,NSCalendar方法实现了真正的从 NSDate到 NSDateComponents对象的转换;以及咱们待会儿会看到的,从日期的组成元素到日期对象的转换。记好了这一点,这一节中咱们首先要作的就是获取当前的 calendar,把它赋给一个常量以便访问:

let calendar = NSCalendar.currentCalendar() 

如今咱们看一个典型例子,一个 NSDate对象是怎样被转换成一个 NSDateComponents对象,以后我会作些讲解:

 
let dateComponents = calendar.components([NSCalendarUnit.Day, NSCalendarUnit.Month, NSCalendarUnit.Year, NSCalendarUnit.WeekOfYear, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second, NSCalendarUnit.Nanosecond], fromDate: currentDate) print("day = \(dateComponents.day)", "month = \(dateComponents.month)", "year = \(dateComponents.year)", "week of year = \(dateComponents.weekOfYear)", "hour = \(dateComponents.hour)", "minute = \(dateComponents.minute)", "second = \(dateComponents.second)", "nanosecond = \(dateComponents.nanosecond)" , separator: ", ", terminator: "") 

上面第一行代码用的方法是 NSCalendar类的 components(_:fromDate:)。该方法接受两个参数:第二个参数是原日期对象,咱们要从中得到它的组成元素。但有意思是第一个参数,该方法要求第一个参数是一个元素为 NSCalendarUnit属性的数组,这些属性对要从日期对象中抽取出的元素作出了描述。

NSCalendarUnit是一个结构体,你能够从这里看到全部可用的属性。上面的例子中,在你看到的代码段截图中给定的这些 calendar unit 值返回以下构成部分:

  • Day
  • Month
  • Year
  • Week of year
  • Hour
  • Minute
  • Second
  • Nanosecond

注意到在第一个参数数组中那些没有列出的 calendar unit(日历单元)在调用方法以后是不可用的。例如因为咱们没有将 NSCalendarUnit.TimeZone这个单元包括进去,因此在剩下获取到的元素中是访问不到时区(timezone)的(好比用 print(dateComponents.timezone))。这么作的话会获得一个运行时错误。若是你须要额外的部分,你就必须再调用一次该方法,指定你想要的额外的calendar units。

从 date components 转换到日期对象也很容易。这回不会涉及到对 calendar unit 的使用。所须要的就是初始化一个新的NSDateComponents对象,而后明确指定出全部须要的components元素(固然是根据你app的须要),而后调用 NSCalendar类的 dateFromComponents方法实现转换。来看一下:

 
let components = NSDateComponents() components.day = 5 components.month = 01 components.year = 2016 components.hour = 19 components.minute = 30 newDate = calendar.dateFromComponents(components) 

前面的部分咱们看过一个在把某特定格式的字符串转换成一个日期对象时使用了 timezone 的例子。若是你足够好奇想看看对一个日期对象设置不一样 timezone 的结果,咱们就将上面的代码稍稍扩展一下,看看 timezone 的多种取值:

 
components.timeZone = NSTimeZone(abbreviation: "GMT") newDate = calendar.dateFromComponents(components) components.timeZone = NSTimeZone(abbreviation: "CST") newDate = calendar.dateFromComponents(components) components.timeZone = NSTimeZone(abbreviation: "CET") newDate = calendar.dateFromComponents(components) 

GMT = 格林威治标准时间
CST = 中国标准时间
CET = 欧洲中部时间

你能够在这里找到全部 timezone 的缩写,还有一些很棒的在线工具。

如今你也知道如何去处理 NSDateComponents对象了,那么我们继续来研究另外一个有意思的东西。

比较日期和时间

处理日期的另一个常见状况是须要对两个日期对象进行比较,判断哪个表明着更早或者更晚,甚至比较这两个是否为同一日期。归纳来讲我在下面会告诉你三种不一样的比较日期对象的方式,但我不但愿让你有种哪一个是最好或者最坏的观点。很明显这取决于你在你的应用中想要干什么,而每种方式和其余两种都有些不一样,哪一种方法对你帮助最有效就选哪一种。

在比较日期对象的方法给出以前,咱们先建立两个日期对象,在本节的例子中使用。首先设定日期格式(date formatter 的 dateFormat属性),而后把两个日期格式的字符串转换成两个日期对象:

dateFormatter.dateFormat = "MMM dd, yyyy zzz" dateAsString = "Oct 08, 2015 GMT" var date1 = dateFormatter.dateFromString(dateAsString)! dateAsString = "Oct 10, 2015 GMT" var date2 = dateFormatter.dateFromString(dateAsString)! 

先看看用来比较日期的第一个方式。若是你想要比较两个日期中比较早的那一个,那么 NSDate类会给你提供较大帮助,它分别提供了两个方法,earlierDate:和 laterDate:。这两个方法的语法很简单:

date1.earlierDate(date2)

原理以下:

  • 若是 date1对象比 date2更早,那么上面的方法会返回 date1的值。
  • 若是 date2对象比 date1更早,那么上面的方法会返回 date2的值。
  • 若是二者相等,则返回 date1

一样道理也使用于 laterDate:方法。

如今来看咱们的例子,使用咱们以前建立的那两个日期对象。下面的两条指令分别使用了刚才提到的那两个方法,为咱们显示出更早的和更晚的日期:

 
// Comparing dates - Method #1 print("Earlier date is: \(date1.earlierDate(date2))") print("Later date is: \(date1.laterDate(date2))") 

第二种比较两个 NSDate对象的方式使用的是 NSDate类的 compare:方法,以及 NSComparisonResult枚举类型。看下面的例子就会明白个人意思,可是我先提一下这种方式的语法和我上面例子中的很像。比较日期所得的结果是和全部的可能值做比较,用这种方式能够很容易的判断出两个日期是否相等、哪个更早或者更晚。不说了,下面的代码已经足够明了:

 

Playground 中的结果以下:

 

可复制的代码:

// Comparing dates - Method #2 if date1.compare(date2) == NSComparisonResult.OrderedDescending { print("Date1 is Later than Date2") } else if date1.compare(date2) == NSComparisonResult.OrderedAscending { print("Date1 is Earlier than Date2") } else if date1.compare(date2) == NSComparisonResult.OrderedSame { print("Same dates") } 

比较两个日期对象的第三种方式多少有些不一样,由于这种方式引入了对 time intervals的使用。实际上这种方式很简单,它作的就是得到自每一个日期以来的时间间隔(每一个日期和如今的时间间隔),而后作比较:

 
// Comparing dates - Method #3 if date1.timeIntervalSinceReferenceDate > date2.timeIntervalSinceReferenceDate { print("Date1 is Later than Date2") } else if date1.timeIntervalSinceReferenceDate < date2.timeIntervalSinceReferenceDate { print("Date1 is Earlier than Date2") } else { print("Same dates") } 

上面的代码也能够应用到对时间的比较。下面我给你最后一个例子,而此次 date1和 date2对象包含了对时间的表示。我再次使用 earlierDate:方法,但另外还有一个,idEqualToDate:,很明显,看名字就知道它是干什么的:

 
// Comparing time. dateFormatter.dateFormat = "HH:mm:ss zzz" dateAsString = "14:28:16 GMT" date1 = dateFormatter.dateFromString(dateAsString)! dateAsString = "19:53:12 GMT" date2 = dateFormatter.dateFromString(dateAsString)! if date1.earlierDate(date2) == date1 { if date1.isEqualToDate(date2) { print("Same time") } else { print("\(date1) is earlier than \(date2)") } } else { print("\(date2) is earlier than \(date1)") } 

若是看到上面代码中「2000-01-01」这个日期以后你感受好奇或疑惑的话,不用担忧。NSDate若是在没有给定任何特定日期来作转换的状况下会默认将其添加,它不会影响到这个日期中其余的元素(例子中其余的元素是时间)。

好了,到这里你也会怎么对日期作比较了。

计算出将来或过去的日期

处理日期另外一个有趣的方面就是计算出一个未来或者过去的日期。咱们以前看到的那些用法在这里会变得很方便,好比 NSCalendarUnit结构体,或者 NSDateComponents类。实际上,我会给你展现两种不一样的计算出其余日期的方式,第一种使用的就是 NSCalendar类和 NSCalendarUnit结构体,第二种使用的是 NSDateComponents类。最后我会给出第三种方式,可是通常状况我不推荐使用(到那部分我会解释为何)。

一开始咱们先记一下当前日期(是我写这篇教程的日期),它会被用做咱们的参考日期:

 

如今假设咱们想把当前日期加上两个月零五天,实际上仍是写下来比较好:

let monthsToAdd = 2 let daysToAdd = 5 

咱们如今就能够看一下第一种方式了,来获得想要的新日期吧。先给代码,立刻解释:

var calculatedDate = NSCalendar.currentCalendar().dateByAddingUnit(NSCalendarUnit.Month, value: monthsToAdd, toDate: currentDate, options: NSCalendarOptions.init(rawValue: 0)) calculatedDate = NSCalendar.currentCalendar().dateByAddingUnit(NSCalendarUnit.Day, value: daysToAdd, toDate: calculatedDate!, options: NSCalendarOptions.init(rawValue: 0)) 

如你所见,这里用到的方法是 NSCalendar类的 dateByAddingUnit:value:toDate:options:方法。这个方法的任务就是给一个现有的日期加上一个特定的 calendar unit(由第一个参数指定),并将这个加法的结果作为一个新的日期返回。咱们开始想的是在当前日期的基础上同时加两个不一样的 calendar unit,但很显然这不现实。因此这里问题的关键是就要连续的调用该方法,每次设置其中的一个 calendar unit,从而获得最终结果。

下面是每次叠加以后 playground 显示的结果:

 

上面的方式不错,可是仅限于你要加的只有 1~2 个 calendar units,不然你得连续屡次调用上面那个方法才行。

当须要叠加更多的 units 时,第二个,也是更倾向的方式是使用 NSDateComponents这个类。为了演示,咱们不会再引入其余的组成元素,除上面已经定好的月和日以外。在这儿要作的事情很简单:首先初始化一个新的 NSDateComponents对象,并给它设置以前定好的月和日。而后调用 NSCalendar类的另外一个叫作 dateByAddingComponents:toDate:options:的方法,咱们会当即获得一个新的 NSDate对象,这个新对象即表明了最终想要的日期。

 
let newDateComponents = NSDateComponents() newDateComponents.month = monthsToAdd newDateComponents.day = daysToAdd calculatedDate = NSCalendar.currentCalendar().dateByAddingComponents(newDateComponents, toDate: currentDate, options: NSCalendarOptions.init(rawValue: 0)) 

注意到上面的两个代码段中,我都没给这两个新介绍方法的最后一个参数作任何设置。而若是你想对这个可设选项了解更多的话,就去参考NSCalendar类的官方文档

第三种计算另外一个日期方式不推荐对时间跨度大的状况使用,由于因为闰秒,闰年,夏令时等等会致使这种方式产生出错误结果。该方式的想法是给当前日期加上一个特定的时间间隔。咱们会使用 NSDate类的 dateByAddingTimeInterval:方法来实现这个目的。下面的例子中咱们算出来一个至关因而 1.5 小时的时间间隔,而后把它加到当前日期上:

let hoursToAddInSeconds: NSTimeInterval = 90 * 60 calculatedDate = currentDate.dateByAddingTimeInterval(hoursToAddInSeconds) 

再强调一下,要作任何类型的日期计算的话,仍是使用前两种方式更安全。但这仍是取决于你,选择你更喜欢的那一种。

上面的三个例子都是给当前日期加上某些个组成元素。那如今用一样方式给当前日期减去几天,算出来那个过去的日期该怎么作?

下面的代码示范了该怎么作。首先给当前日期加上一个特定天数的值,这就能够获得一个属于过去的日期了。而后把结果转换成一个有适当格式的字符串,最后的结果...颇有意思:

 
let numberOfDays = -5684718 calculatedDate = NSCalendar.currentCalendar().dateByAddingUnit(NSCalendarUnit.Day, value: numberOfDays, toDate: currentDate, options: NSCalendarOptions.init(rawValue: 0)) dateFormatter.dateFormat = "EEEE, MMM dd, yyyy GGG" dateAsString = dateFormatter.stringFromDate(calculatedDate!) 

以上全部的小代码段示例能够彻底给你讲明白怎样经过给某个参考日期加上或正或负的 calendar unit 来算出一个新的日期。本身随便扩展一下上面的代码吧,写下你本身的代码,你就会对这些技巧更加熟悉。


计算出日期的差值

和标题的意思同样,这节讲的是计算出两个日期之间的差值,它是在你编程生涯中某个时间确定要作的一个任务,显然须要作不止一次。在这(教程的最后)一部分,我会告诉你计算出两个 NSDate对象之间差值的三种方式,你能够根据须要选出最适合你的那一种。

开始以前先定义两个 NSDate对象:

dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" dateAsString = "2015-10-08 14:25:37" date1 = dateFormatter.dateFromString(dateAsString)! dateAsString = "2018-03-05 08:14:19" date2 = dateFormatter.dateFromString(dateAsString)! 

有了上面的日期对象,咱们再来看一下如何获取日期组成元素(date components)形式的日期差值(date difference )。咱们会再次用到 NSCalendar类,还有它的一个以前咱们没见过的方法。最后把日期组成元素打印出来看一下结果。很明显当有了它,这个表明了日期差值的元素以后,想怎么作都取决于你了。来看下示范:

 
var diffDateComponents = NSCalendar.currentCalendar().components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second], fromDate: date1, toDate: date2, options: NSCalendarOptions.init(rawValue: 0)) print("The difference between dates is: \(diffDateComponents.year) years, \(diffDateComponents.month) months, \(diffDateComponents.day) days, \(diffDateComponents.hour) hours, \(diffDateComponents.minute) minutes, \(diffDateComponents.second) seconds") 

这种新方式就是使用 components:fromDate:toDate:options:方法,一样它的第一个参数是一个 NSCalendarUnit的数组。注意下若是第一个日期比第二个晚的话,返回值就会是负数。

在计算日期差值的另外两种方式中,咱们会第一次用到 NSDateComponentsFormatter类,这个类有不少方法,能自动作出差值计算,而后返回一个带有特定格式的字符串。先生成一个对象,并先指定它的一个属性:

let dateComponentsFormatter = NSDateComponentsFormatter() dateComponentsFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyle.Full 

unitsStyle属性告诉 dateComponentsFormatter描述日期差值的那个字符串的格式应该是什么样的,显示出的日期组成元素应该是怎样的样式。好比用 Full这个样式,星期几、月份等等就会显示成常规的全写(full-length)单词。而若是咱们用了 Abbreviated样式的话,则会显示这些信息的缩写。从这里你能看到关于单元样式(units style)的全说明列表。

回到日期差值中来,此次咱们要先算出两个日期之间的时间间隔。而后这个间隔自己会做为一个参数传递给 NSDateComponentFormatter类的 stringFromTimeInterval:方法,结果就会以一个格式化好了的字符串形式返回。

 
let interval = date2.timeIntervalSinceDate(date1) dateComponentsFormatter.stringFromTimeInterval(interval) 

最后,在计算日期差值的最后一个方式中,两个日期须要做为参数传递给 NSDateComponentsFormatter类的 stringFromDate:toDate:方法。然而用这个方法以前须要先知足一个条件:allowedUnits属性必需要设置一个 calendar unit,不然该方法会返回一个 nil。因此咱们就「告诉」这个方法咱们想要怎样的 unit,以后就等它给咱们差值结果:

 
dateComponentsFormatter.allowedUnits = [NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second] let autoFormattedDifference = dateComponentsFormatter.stringFromDate(date1, toDate: date2) 

总结

简介部分中我说过,处理 NSDate对象这件事在你项目中很是常见,并且确定没法避免。不能否认它并非程序员最喜欢讨论的话题,因此我就写了前面的那些,在小例子中告诉你其实处理日期是很容易的。这篇教程中 NSDate的方方面面,以及其余相关的类都有一个共同目标:教你小巧高效的用法,两三行代码就让你把活儿搞定。但愿这篇文章能给你作个指南,尤为若是你是一个新开发者。下篇文章出来以前,好好练习吧。

本文由 SwiftGG 翻译组翻译,已经得到做者翻译受权,最新文章请访问 http://swift.gg

连接:https://www.jianshu.com/p/3e5f6cb1c31c
相关文章
相关标签/搜索