DateTools 是为了简化 Objective-C 中的日期和时间处理而编写的。DateTools 从其他语言中的类和概念中汲取了灵感,特别是 .NET 中的 DateTime 结构和 Time Period Library。通过这些类和其他类,DateTools 消除了访问日期组件所需的样板代码,并处理了更多的日期比较细节,并作为像时间段及其集合等全新概念的基础。
|
|
|
|
|
Yahoo! Livetext | My Disney Experience | ALDI | Guidebook | Pitch Locator Pro |
CocoaPods
pod 'DateTools'
手动安装
DateTools 所需的所有类都位于此仓库根目录下的 DateTools 文件夹中。以下列出了它们
DateTools.h
NSDate+DateTools.{h,m}
DTConstants.h
DTError.{h,m}
DTTimePeriod.{h,m}
DTTimePeriodGroup.{h,m}
DTTimePeriodCollection.{h,m}
DTTimePeriodChain.{h,m}
如果您想支持国际化或使用 "时间之前" 功能,则需要以下包。您可以在 "项目" 菜单下的 "Info" 下的 Localizations
子标题下添加本地化。
DateTools.bundle
DateTools.h
包含其他所有文件的头文件。如果您想要链接整个框架,请导入此文件。
DateTools的一个使命是使NSDate感到更加完整。许多其他语言允许从它们的日期类直接访问有关日期的信息,但NSDate(遗憾的是)不行。它可以安全地在Unix时间偏移量中通过timeIntervalSince...
方法构建日期,且对日历不敏感。但并非总是我们想要做的事情。有时,我们想要在更抽象的级别上基于日期组件(如年、月、日等)来处理日期。这就是DateTools发挥作用的地方。
没有日期库能不包括如何快速创建一个基于当前日期之前多少时间转换成DateTime的功能。DateTools可以满足这一需求。这些"时间 ago"字符串有长格式和短格式两种,其中后者与Twitter类似。您可以这样获取这些字符串
NSDate *timeAgoDate = [NSDate dateWithTimeIntervalSinceNow:-4];
NSLog(@"Time Ago: %@", timeAgoDate.timeAgoSinceNow);
NSLog(@"Time Ago: %@", timeAgoDate.shortTimeAgoSinceNow);
//Output:
//Time Ago: 4 seconds ago
//Time Ago: 4s
假设您已经将本地化添加到您的项目中,DateTools
当前支持以下语言
如果您知道本文档中未列出的语言,请考虑提交翻译。语言代码根据语言。
此项目是由用户推动的(像您这样的人)。拉取请求比问题(合并或拒绝)关闭得更快。
感谢Kevin Lawler对NSDate+TimeAgo的工作,该库已被正式合并到这个库中。
从NSDate获取日期组件涉及大量样板代码。您必须设置日历,使用所需标志来选择您想要的组件,并最终从日历中提取它们。
使用DateTools,这
//Create calendar
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit;
NSDateComponents *dateComponents = [calendar components:unitFlags fromDate:date];
//Get components
NSInteger year = dateComponents.year;
NSInteger month = dateComponents.month;
...变成了这样
NSInteger year = date.year;
NSInteger month = date.month;
如果您想使用非公历日历,DateTools也提供这项选项。
NSInteger day = [date dayWithCalendar:calendar];
如果您想覆盖DateTools使用的默认日历,可以在NSDate+DateTools.m
文件中的defaultCalendar
方法中更改它。
NSDate+DateTools中的日期编辑方法使得很容易通过添加和减去日期组件来将日期向前或向后移动。例如,如果您想要从给定日期后一年,只需调用dateByAddingYears
方法。
使用DateTools,这
//Create calendar
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:[NSDate defaultCalendar]];
NSDateComponents *components = [[NSDateComponents alloc] init];
//Make changes
[components setYear:1];
//Get new date with updated year
NSDate *newDate = [calendar dateByAddingComponents:components toDate:date options:0];
...变成了这样
NSDate *newDate = [date dateByAddingYears:1];
也完全支持通过dateBySubtractingYears
减去日期组件。
DateTools类别的一个使命是极大地增加日期比较的灵活性。NSDate提供了四个基本方法
earlierDate:
和 laterDate:
都很棒,但要是能有一个布尔值返回结果来帮助构建代码中的逻辑就更好了;方便地问“这个日期比那个日期早吗?”。DateTools 提供了一套代理方法,不仅可以完成这个任务,还有几个其他方法,提供了更大的灵活性。新方法包括
这些方法非常适合以布尔形式比较日期,但如果我们想比较日期并返回一些关于它们之间差异的有意义的信息呢?NSDate 提供了两个方法 timeIntervalSinceDate:
和 timeIntervalSinceNow
,它们都返回一个代表两个日期之间秒数的 double
偏移量。这很不错,但有时人们想知道两个日期之间有多少年或天。为此,DateTools 回到了始终可靠的 NSCalendar,并为您抽象了所有必要的代码。
使用 Date Tools,这将
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:[NSDate defaultCalendar]];
NSDate *earliest = [firstDate earlierDate:secondDate];
NSDate *latest = (secondDate == firstDate) ? secondDate : firstDate;
NSInteger multiplier = (secondDate == firstDate) ? -1 : 1;
NSDateComponents *components = [calendar components:allCalendarUnitFlags fromDate:earliest toDate:latest options:0];
NSInteger yearsApart = multiplier*(components.month + 12*components.year);
..变成了这样
NSInteger yearsApart = [firstDate yearsFrom:secondDate];
这个类别的比较方法包括
yearsFrom:
、yearsUntil:
、yearsAgo:
、yearsEarlierThan:
、yearsLaterThan:
monthsFrom:
、monthsUntil:
、monthsAgo:
、monthsEarlierThan:
、monthsLaterThan:
weeksFrom:
、weeksUntil:
、weeksAgo:
、weeksEarlierThan:
、weeksLaterThan:
daysFrom:
、daysUntil:
、daysAgo:
、daysEarlierThan:
、daysLaterThan:
hoursFrom:
、hoursUntil:
、hoursAgo:
、hoursEarlierThan:
、hoursLaterThan:
minutesFrom:
、minutesUntil:
、minutesAgo:
、minutesEarlierThan:
、minutesLaterThan:
secondsFrom:
、secondsUntil:
、secondsAgo:
、secondsEarlierThan:
、secondsLaterThan:
只是开个玩笑,DateTools 还有一些便利方法可以帮助快速将日期转换为字符串。这两个方法是 formattedDateWithStyle:
和 formattedDateWithFormat:
。除非由附加方法参数指定,否则使用当前区域。当然,还是只是为了开玩笑。
日期很重要,但现实世界并没有那么离散。生活是由时间段组成的,比如下午的约会或一周的度假。在 DateTools 中,时间段由 DTTimePeriod 类表示,并附带一系列初始化、操作和比较方法,使您能够轻松地操作它们。
时间段由一个起始日期和一个结束日期组成。要初始化一个时间段,请调用 init 函数。
DTTimePeriod *timePeriod = [[DTTimePeriod alloc] initWithStartDate:startDate endDate:endDate];
或者,如果您想要创建一个已知长度的时间段,该时间段开始或结束于特定时间,您可以尝试其他几个 init 方法。下面的方法,例如,创建了一个从当前时间开始,长度恰好为 5 小时的时间段。
DTTimePeriod *timePeriod = [DTTimePeriod timePeriodWithSize:DTTimePeriodSizeHour amount:5 startingAt:[NSDate date]];
已经扩展了很多方法,提供了关于 DTTimePeriod 实例的信息。以下是其中一些:
hasStartDate
- 如果该时间段有起始日期,则返回 truehasEndDate
- 如果该时间段有结束日期,则返回 trueisMoment
- 如果该时间段有相同的起始和结束日期,则返回 truedurationIn...
- 返回时间段在请求的单位的长度时间段也可以进行操作。它们可以提前或延后,也可以扩展或收缩。
调整
当一个时间段被调整时,开始日期和结束日期都会按照所需数量提前或延后移动。要提前调整时间段,调用 shiftEarlierWithSize:amount:
,要延后调整,调用 shiftLaterWithSize:amount:
。金额字段作为一个乘数,就像在上面的初始化方法中一样。
延长/缩短
当一个时间段被延长或缩短时,它会将时间段的一个日期作为基准,然后改变另一个日期。还有一个选项是将时间段的中心点作为基准,改变开始日期和结束日期。
以下是一个延长时间段的示例
DTTimePeriod *timePeriod = [DTTimePeriod timePeriodWithSize:DTTimePeriodSizeMinute endingAt:[NSDate date]];
[timePeriod lengthenWithAnchorDate:DTTimePeriodAnchorEnd size:DTTimePeriodSizeMinute amount:1];
这会将持续时间1分钟的时间段延长至2分钟。保留“现在”的结束日期,仅将开始日期提前1分钟。
可能需要的时候,比如在做日程安排应用程序时,可能会想知道两个时间段如何相互关联。它们是否相同?一个是否包含在另一个内部?所有这些问题都可以使用DTTimePeriod的关系方法来提问。
一系列方法已经被扩展,用于检查基本关系。以下是列出
您还可以使用以下方法检查官方关系(如图表中所示)
-(DTTimePeriodRelation)relationToPeriod:(DTTimePeriod *)period;
所有可能的关系都已列举在DTTimePeriodRelation枚举中。
为了更好地了解时间段之间的关系,请查看示例应用程序中的"时间段"选项卡。您可以调整几个时间段,并观察它们关系的改变。
时间段组是DateTools中日期和时间的最终抽象。在这里,时间段被收集和组织成有用的东西。主要有两种时间段组,DTTimePeriodCollection
和 DTTimePeriodChain
。从高层次来看,将集合视为可能发生重叠的宽松组,将链视为不允许重叠的更线性、紧密的组。
集合和链都像NSArray一样运行。您可以像处理数组中的对象一样,从它们中添加、插入和删除DTTimePeriod对象。不同之处在于它们在底层如何处理这些时间段。
时间段集合作为时间段的不严格集合。除非您决定排序,否则它们是无组织的,并具有自己的特征,如StartDate和EndDate,这是从其内部的时间段中外推出来的。时间段集合允许其时间段集合内部存在重叠。
要创建一个新的集合,请调用类方法如下
//Create collection
DTTimePeriodCollection *collection = [DTTimePeriodCollection collection];
//Create a few time periods
DTTimePeriod *firstPeriod = [DTTimePeriod timePeriodWithStartDate:[dateFormatter dateFromString:@"2014 11 05 18:15:12.000"] endDate:[dateFormatter dateFromString:@"2015 11 05 18:15:12.000"]];
DTTimePeriod *secondPeriod = [DTTimePeriod timePeriodWithStartDate:[dateFormatter dateFromString:@"2015 11 05 18:15:12.000"] endDate:[dateFormatter dateFromString:@"2016 11 05 18:15:12.000"]];
//Add time periods to the colleciton
[collection addTimePeriod:firstPeriod];
[collection addTimePeriod:secondPeriod];
//Retreive collection items
DTTimePeriod *firstPeriod = collection[0];
排序 在集合中对时间段进行排序很简单,只需调用其中一个排序方法。总共有三种排序选项,如下所示
sortByStartAscending
, sortByStartDescending
sortByEndAscending
, sortByEndDescending
sortByDurationAscending
, sortByDurationDescending
操作 还可以检查日期或 DTTimePeriod 与集合的关系。例如,如果您想查看所有与特定日期相交的时间段,可以调用 periodsIntersectedByDate: 方法。结果是包含所有相交指定日期的时间段的新 DTTimePeriodCollection。还有许多其他方法可以尝试,包括两个集合之间完全相等性检查。
时间段链是一组紧密耦合的时间段。它们总是按起始日期和结束日期组织,并具有从时间段中推断出的自己的特征,如 StartDate 和 EndDate。时间段链不允许其时间段集合内部的重复。这种类型的群体非常适合建模顺序会议或约会等日程安排。
要创建一个新链,请调用类方法如下
//Create chain
DTTimePeriodChain *chain = [DTTimePeriodChain chain];
//Create a few time periods
DTTimePeriod *firstPeriod = [DTTimePeriod timePeriodWithStartDate:[dateFormatter dateFromString:@"2014 11 05 18:15:12.000"] endDate:[dateFormatter dateFromString:@"2015 11 05 18:15:12.000"]];
DTTimePeriod *secondPeriod = [DTTimePeriod timePeriodWithStartDate:[dateFormatter dateFromString:@"2015 11 05 18:15:12.000"] endDate:[dateFormatter dateFromString:@"2016 11 05 18:15:12.000"]];
//Add test periods
[chain addTimePeriod:firstPeriod];
[chain addTimePeriod:secondPeriod];
//Retreive chain items
DTTimePeriod *firstPeriod = chain[0];
将日期添加到时间链中时,它保留其时长,但会修改其 StartDate 以与链中最新段的 EndDate 相同。这有助于保持链的时间段的紧密耦合结构。除了 index 0 之外的所有插入都会将插入索引之后的日期按新时间段的时长移动,而不会触及索引较低的日期。索引为 0 的插入会将集合的起始日期按新时间段的时长移动。下面可以看到完整的操作列表。
操作 与集合一样,链具有相等性检查和向前或向后移动的能力。以下是其他操作的一小部分。
所有方法和变量都已进行了文档编写,并可供 option+click 检查,就像 SDK 类一样。这包括对方法的解释以及它们的输入和输出参数。如果您觉得文档令人困惑或误导,请提出问题,我们将修复它!
在库的所有主要类上进行了单元测试,以确保质量。您可以在库顶部的 "Tests" 文件夹中找到这些测试。所有测试用例超过 300 个!
如果您发现任何测试用例不完整,请提出问题,使我们能修复。
Travis CI 执行持续集成测试
感谢 Kevin Lawler 对 NSDate+TimeAgo 的初始工作。这为 DateTools 的 timeAgo 方法奠定了基础。您可以在这里找到这个伟大的项目。
非常感谢 .NET 团队对 DateTime 类的工作,并衷心感谢 Jani Giannoudis 对 ITimePeriod 的工作。
图片最初通过 itenso.com 经Code Project发布
我还想感谢 上帝 通过祂,万物都活着,动作,并拥有自己的本质。使徒行传 17:28
MIT 许可证 (MIT)
版权所有 (c) 2014 Matthew York
本许可证授予任何人免费使用和有权处置此软件及其附属文档文件(统称为“软件”),包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件副本,并且授权软件接受者可进行上述操作,但需遵守以下条件:
上述版权声明和本许可证声明应包含在软件所有副本或其大部分副本中。
该软件按“现状”提供,不提供任何形式的保证,无论是明示的还是暗示的,包括但不限于适销性、特定用途适用性和非侵权性。在任何情况下,作者或版权所有者不对因软件本身、软件的使用或与之相关的交易产生的任何索赔、损害或其他责任负责,无论这些索赔、损害或其他责任是基于合同、侵权或其他原因。