美文网首页
NSDate日期类学习笔记

NSDate日期类学习笔记

作者: 寻心_0a46 | 来源:发表于2019-01-30 23:37 被阅读0次

NSDate

NSDate是Foundation框架中表示日期的类,用于保存时间值的一个OC类,同时提供了一些方法来处理一些与时间相关的事。NSDate对象用来表示一个具体的时间点。NSDate是一个类簇,我们所使用的NSDate对象,都是NSDate的私有子类的实体。NSDate存储的是GMT(格林威治时间)时间,使用的时候会根据 当前应用指定的时区进行时间上的增减,以供计算或显示。

//返回当前时间(GMT,0时区,格林尼治时间)
+ (instancetype)data;

例如实例化一个当前时间对象:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSDate *date = [NSDate date];
    NSLog(@"%@",date);
}

当前NSDate对象打印的时间:

截屏2019-11-12下午10.16.12.png

当前NSDate对象的实际时间:


截屏2019-11-12下午10.17.27.png
// 返回以当前时间为基准,然后过了secs秒的时间
+ (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;
//返回以2001/01/01  GMT为基准,然后过了secs秒的时间
+ (instancetype)dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti;
// 返回以1970/01/01  GMT为基准,然后过了secs秒的时间
+ (instancetype)dateWithTimeIntervalSince1970:(NSTimeInterval)secs;

例如:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSDate *date = [NSDate date];
    NSDate *date2 = [NSDate dateWithTimeIntervalSinceNow:10];
    NSLog(@"%@-%@",date,date2);
}

两者之间相差10秒:

截屏2019-11-12下午10.23.55.png
//  根据时间间隔和指定的date,获得对应的时间
+ (instancetype)dateWithTimeInterval:(NSTimeInterval)secsToBeAdded sinceDate:(NSDate *)date;

例如:

//平年365天一年有8760小时,525600分钟,31536000秒。闰年366天一年有8784小时,527040分钟,31622400秒
- (void)viewDidLoad {
    [super viewDidLoad];
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:0];
    NSDate *date2 = [NSDate dateWithTimeInterval:31536000 sinceDate:date];
    NSLog(@"%@",date2);
}

相差一年:

截屏2019-11-12下午10.41.58.png
// 以anotherDate为基准时间,返回NSDate实例保存的时间与anotherDate的时间间隔
- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate;

例如:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSDate *date = [NSDate date];
    NSDate *date2 = [NSDate dateWithTimeIntervalSinceNow:10];
    NSLog(@"%f",[date2 timeIntervalSinceDate:date]);
}

如果调用函数的NSDate对象小于参数的NSDate对象,会返回负数,例如:

截屏2019-11-12下午10.34.37.png
//返回很多年以后的未来的某一天
@property (class, readonly, copy) NSDate *distantFuture;
//返回很多年以前的某一天
@property (class, readonly, copy) NSDate *distantPast;
//以当前时间(now)为基准时间,返回NSDate实例保存的时间与当前时间(now)的时间间隔
@property (readonly) NSTimeInterval timeIntervalSinceNow;
// 以 1970/01/01 GMT 为基准时间,返回NSDate实例保存的时间与 1970/01/01 GMT 的时间间隔
@property (readonly) NSTimeInterval timeIntervalSince1970;
//系统绝对参考日期(2001年1月1日00:00:00 UTC)与当前日期和时间之间的间隔。
@property (class, readonly) NSTimeInterval timeIntervalSinceReferenceDate;

比较两个NSDate时间对象的代码片段:

- (int)compareOneDay:(NSDate *)oneDay withAnotherDay:(NSDate *)anotherDay{
    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    
    [dateFormatter setDateFormat:@"dd-MM-yyyy"];
    
    NSString *oneDayStr = [dateFormatter stringFromDate:oneDay];
    
    NSString *anotherDayStr = [dateFormatter stringFromDate:anotherDay];
    
    NSDate *dateA = [dateFormatter dateFromString:oneDayStr];
    
    NSDate *dateB = [dateFormatter dateFromString:anotherDayStr];
    
    NSComparisonResult result = [dateA compare:dateB];
    
    if (result == NSOrderedDescending) {
        //NSLog(@"oneDay比 anotherDay时间晚");
        return 1;
    }
    else if (result == NSOrderedAscending){
        //NSLog(@"oneDay比 anotherDay时间早");
        return -1;
    }
    //NSLog(@"两者时间是同一个时间");
    return 0;
}

NSDateFormatter

派生自NSFormatter,是在日期和它们的文本表示之间转换的格式化程序。

例如时间戳转字符串的代码片段:

//返回当前时间的时间戳
double timeStamp = [[NSDate date] timeIntervalSince1970];
//NSTimeInterval 时间间隔,double类型
NSTimeInterval time = timeStamp;
//得到Date类型的时间,这个时间是1970-1-1 00:00:00经过你时间戳的秒数之后的时间
NSDate * detaildate = [NSDate dateWithTimeIntervalSince1970:time];
//实例化NSDateFormatter对象
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
//设定时间格式,这里可以设置成自己需要的格式
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
//转换成字符串
NSString * currentDateStr = [dateFormatter stringFromDate:detaildate];
//输出一下
NSLog(@"%@", currentDateStr);
屏幕快照 2019-01-30 下午11.29.51.png

例如将格式化的字符串转为NSDate对象:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *dateStr = @"2019-11-11 10:56:30";
    NSDate *date= [self nsstringConversionNSDate:dateStr];
    NSLog(@"%@",date);
    
}

///字符串转Date时间
- (NSDate *)nsstringConversionNSDate:(NSString *)dateStr {
    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"YYYY-MM-dd hh:mm:ss"];
    NSDate *date = [dateFormatter dateFromString:dateStr];
    return date;
    
}

结果在使用时要注意时间差:

截屏2019-11-12下午11.00.17.png

注:YYYY-MM-dd 和yyyy-MM-dd区别

YYYY 是按照周来计算时间,一周从周日开始,周六结束,例如2019年12月29号周日,以这个时间计算的方式,一年当中的时间,不足一周的(年末那一周),就要计算到下一年中去,就变成了2020年了,而月份与天数保持的是正确的。

yyyy是按照天来计算的,今天是12月29号,也是2019年,符合中国人的计算方式,平常计算中还是最好使用yyyy-MM-dd。

例如将时间戳(秒)转换xx天xx小时xx分xx秒形式的字符串

- (void)viewDidLoad {
    [super viewDidLoad];
    //2019-08-20 21:14:40 的时间戳
    NSInteger timeStamp1 = 1566306880;
    //2019-08-12 21:14:40 的时间戳
    NSInteger timeStamp2 = 1565615680;
    //时间差
    NSString *timeDifference = [NSString stringWithFormat:@"%ld",timeStamp1 - timeStamp2];
    NSLog(@"%@",[NSString stringWithFormat:@"%@",[self getOvertime:timeDifference]]);
}

//将时间戳(秒)转换xx天xx小时xx分xx秒形式的字符串
- (NSString*)getOvertime:(NSString*)mStr
{
    long msec = [mStr longLongValue];
    
    if (msec <= 0)
    {
        return @"";
    }
    
    NSInteger days = (int)(msec / (3600 * 24));
    NSInteger hours = (int)((msec - days * 24 * 3600) / 3600);
    NSInteger minutes = (int)(msec - days * 24 * 3600 - hours * 3600) /60;
    NSInteger seconds = (int)msec - days * 24 * 3600 - hours * 3600 - minutes * 60;
    
    
    NSString *timeStr = @"";
    NSString *daysStr = @"";
    NSString *hoursStr = @"";
    NSString *minutesStr = @"";
    NSString *secondsStr = @"";
    
    if (days >= 0)
    {
        daysStr = [NSString stringWithFormat:@"%ld天",(long)days];
    }
    
    if (hours >= 0)
    {
        hoursStr = [NSString stringWithFormat:@"%ld小时",(long)hours];
    }
    
    if (minutes >= 0)
    {
        minutesStr = [NSString stringWithFormat:@"%ld分",(long)minutes];
    }
    
    if (seconds >= 0)
    {
        secondsStr = [NSString stringWithFormat:@"%ld秒",(long)seconds];
    }
    timeStr = [NSString stringWithFormat:@"%@%@%@%@",daysStr,hoursStr,minutesStr,secondsStr];
    
    return timeStr;
}

运行结果:

屏幕快照 2019-08-12 下午11.19.05.png

NSTimeZone

NSTimeZone派生自NSObject,有关与特定地缘政治区域相关的标准时间约定的信息。用于处理时区。

需要重点区分三个属性:

@property (class, readonly, copy) NSTimeZone *systemTimeZone;
  1. systemTimeZone: 当前系统使用的时区,其获取实际为系统时区对象的副本,因此,一经获取,当系统时区发生变化时,app中的systemTimeZone不会关联变化,如果想重新获取,需要先执行resetSystemTimeZone方法
@property (class, copy) NSTimeZone *defaultTimeZone;
  1. defaultTimeZone: 可以通过setDefaultTimeZone方法进行设置,如果没有特别设置,则返回systemTimeZone,但是app一旦获取该值后,如果使用setDefaultTimeZone方法更新defaultTimeZone,app中获取到的值不会发生关联变化。
@property (class, readonly, copy) NSTimeZone *localTimeZone;
  1. localTimeZone:等于defaultTimeZone,与defaultTimeZone的唯一区别是,当使用setDefaultTimeZone方法更新defaultTimeZone,app中获取到的值会发生关联变化
@property (readonly) NSInteger secondsFromGMT;

较为常用的属性,返回与GMT之间的时间偏移量,单位:秒
可以使用 [NSTimeZone localTimeZone].secondsFromGMT 直接获取当前使用时区与GMT时间的偏移量,从而计算当前时区的正确时间。

例如处理时区差的代码片段:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSDate *date = [NSDate date];
    NSDate *date2 = [self handlingTimeZoneDifferences:[NSDate date]];
    NSLog(@"%@ —— %@",date,date2);
}

///处理时区差
- (NSDate *)handlingTimeZoneDifferences:(NSDate *)date{
    
    NSTimeZone *zone = [NSTimeZone systemTimeZone];
    NSInteger interval = [zone secondsFromGMTForDate:date];
    NSDate *localeDate = [date dateByAddingTimeInterval:interval];
    return localeDate;
}

获取当前的时间date与处理过时区的当前时间date2:

截屏2019-11-13下午9.46.58.png

NSCalendar

NSCalendar 派生自NSObject,定义日历单位(如aseras、years和weekday)与绝对时间点之间关系的对象,提供计算和比较日期的功能。

常用属性

@property (class, readonly, copy) NSCalendar *currentCalendar;

属性描述 : 返回的日历是由当前用户所选系统区域设置的设置组成的,这些设置覆盖了用户在系统首选项中指定的任何自定义设置。从该日历获得的设置不会随着系统首选项的更改而更改

@property (class, readonly, copy) NSCalendar *currentCalendar;

例如:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents  *components  =  [calendar components:NSCalendarUnitMinute | NSCalendarUnitMonth | NSCalendarUnitHour | NSCalendarUnitDay fromDate:[NSDate date]];
    NSLog(@"%ld月%ld日%ld时%ld分" ,(long)components.month,(long)components.day,(long)components.hour,(long)components.minute);
    
}

打印结果:

截屏2019-11-13下午10.36.01.png

@property NSUInteger firstWeekday;

属性描述 : 接收器第一个工作日的索引。西方工作日的第一天是周日,而我们是周一。

@property NSUInteger firstWeekday;
常用函数

- (nullable id)initWithCalendarIdentifier:(NSCalendarIdentifier)ident NS_DESIGNATED_INITIALIZER;

函数描述 : 根据给定的标识符初始化日历。

参数 :

ident : 日历的标识符。

返回值 : 初始化的日历,如果标识符未知(例如,它是无法识别的字符串或当前版本的操作系统不支持该日历),则为nil。

- (nullable id)initWithCalendarIdentifier:(NSCalendarIdentifier)ident NS_DESIGNATED_INITIALIZER;

一些日历标识符:

//欧洲、西半球和其他地方的通用日历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierGregorian  API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); 
//中国日历的标识(农历)
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierChinese  API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
//佛教日历的标识符。
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierBuddhist            API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
//伊斯兰日历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierIslamic             API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

例如:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierChinese];
    NSDateComponents  *components  =  [calendar components:NSCalendarUnitMinute | NSCalendarUnitMonth | NSCalendarUnitHour | NSCalendarUnitDay fromDate:[NSDate date]];
    NSLog(@"%ld月%ld日%ld时%ld分" ,(long)components.month,(long)components.day,(long)components.hour,(long)components.minute);
    
}

初始化中国日历(农历)打印结果:

截屏2019-11-13下午10.50.36.png

- (NSUInteger)ordinalityOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;

函数描述 : 在给定的绝对时间内,返回指定的较大日历单位(例如一周)内较小日历单位(例如一天)的序号。

参数 :

smaller:较小的日历单位。

larger: 较大的日历单位。

date: 执行计算的绝对时间

- (NSUInteger)ordinalityOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;

例如:

- (void)viewDidLoad {
    [super viewDidLoad];
   NSCalendar *calendar1 = [NSCalendar currentCalendar];
    NSInteger days = [calendar1 ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitYear forDate:[NSDate date]];
    NSLog(@"今天是今年的第%ld天",(long)days);    
}

打印结果:

截屏2019-11-13下午11.19.25.png

- (nullable NSDate *)dateByAddingComponents:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSCalendarOptions)opts;

函数描述 : 返回一个日期,该日期表示通过将给定组件添加到给定日期而计算出的绝对时间。有些操作可能是不明确的,并且计算的行为是特定于日历的,但是通常组件是按照指定的顺序添加的。请注意,有些计算可能需要相对较长的时间。

函数 :

comps : 要添加到日期的组件。

date : 添加补偿的日期。

opts : 计算选项。

返回值 : 一个新的NSDate对象,表示通过使用opts指定的选项将comps指定的日历组件添加到date来计算的绝对时间。如果日期超出接收器的定义范围或无法执行计算,则返回nil。

- (nullable NSDate *)dateByAddingComponents:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSCalendarOptions)opts;

- (nullable NSDate *)dateFromComponents:(NSDateComponents *)comps;

函数描述 : 返回一个日期,表示从给定组件计算的绝对时间。当提供的组件不足以完全指定绝对时间时,日历将使用其选择的默认值。当存在不一致的信息时,日历可能会忽略一些组件参数,或者方法可能返回nil。注意,有些计算可能需要相对较长的时间来执行。

参数 :

comps : 从中计算返回日期的组件。

返回值 : 一个新的NSDate对象,表示从comps计算的绝对时间。如果接收器无法将comps中给定的组件转换为NSDate对象,则返回nil。

- (nullable NSDate *)dateFromComponents:(NSDateComponents *)comps;

NSDateComponents

NSDateComponents派生自NSObject,是一个日期信息的容器,以日历系统和时区中要计算的单位(如年、月、日、小时和分钟)来指定日期或时间的对象,NSDateComponents对象本身没有意义,而是需要知道它是根据哪种日历解释的,并且需要知道这些值是单位的绝对值还是单位的数量。

常用属性
//纪元
@property NSInteger era;
//年
@property NSInteger year;
//月
@property NSInteger month;
//日
@property NSInteger day;
//小时
@property NSInteger hour;
//分钟
@property NSInteger minute;
//秒
@property NSInteger second;
//纳秒
@property NSInteger nanosecond API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
//周
@property NSInteger weekday;
//表示工作日在下一个较大的日历单位(如月份)中的位置。例如,2是一个月的第二个星期五的工作日序数单位。
@property NSInteger weekdayOrdinal;
//季度
@property NSInteger quarter API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
//月份的周数。
@property NSInteger weekOfMonth API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
//年的周数
@property NSInteger weekOfYear API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
//年份的周编号
@property NSInteger yearForWeekOfYear API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
常用函数

- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)date;

函数描述 : 返回表示给定日期的日期组件。注:有些计算可能会花费相当长的时间。

参数 :

unitFlags : 要将数据分解为的组件。

date : 执行计算的日期。

返回值 : 一个NSDateComponents对象,包含分解为unitFlags指定的组件的日期。如果日期超出接收器的定义范围或无法执行计算,则返回nil。

- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)date;

例如为Date时间加上一个月:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSDate *date = [NSDate date];
    NSDate *newDate = [self PlusOneMonth:date];
    NSLog(@"%@",newDate);
    
}

///为Date时间加上一个月
- (NSDate *)PlusOneMonth:(NSDate *)currentDate{
    //以公历标识初始化日历对象
    NSCalendar *calender2 = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    //设置第一个工作日的索引
    [calender2 setFirstWeekday:2];// 国外是从周日开始算的,我们是周一,所以写了2
    //初始化日期组件对象
    NSDateComponents *adcomps = [[NSDateComponents alloc]init];
    //设置补偿年
    [adcomps setYear:0];
    //设置补偿月
    [adcomps setMonth:+1];
    //设置补偿天
    [adcomps setDay:0];
    //将日期组件加到给定日期
    NSDate *newdate = [calender2 dateByAddingComponents:adcomps toDate:currentDate options:0];
    //返回新的NSDate对象
    return newdate;
}

打印结果:


截屏2019-11-13下午11.30.41.png

例如获取当前月的第一天:

- (nullable NSDate *)fs_firstDayOfMonth:(NSDate *)month
{
    if (!month) return nil;
    //初始化日期组件(组件为年、月、日、小时)
    NSDateComponents *components = [self components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour fromDate:month];
    //设置补偿天数
    components.day = 1;
    //从给定组件计算的绝对时间
    return [self dateFromComponents:components];
}

例如获取当前月的最后一天

- (nullable NSDate *)fs_lastDayOfMonth:(NSDate *)month
{
    month = [NSDate date];
    if (!month) return nil;
    //初始化日期组件(组件为年、月、日、小时)
    NSDateComponents *components = [self components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour fromDate:month];
    //设置补偿月数
    components.month++;
    //设置补偿天数
    components.day = 0;
    //从给定组件计算的绝对时间
    return [self dateFromComponents:components];
}

FSCalendar封装的日历插件调用的小示例

//
//  SignInController.h

#import <UIKit/UIKit.h>

@interface SignInController : UIViewController

@end

//
//  SignInController.m


#import "SignInController.h"
#import "SignInView.h"

@interface SignInController ()

@end

@implementation SignInController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createUI];
}

///初始化签到视图
- (void)createUI{
    
    ///滚动视图
    UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
    scrollView.contentSize = CGSizeMake(SCREEN_WIDTH, 690 + HEAD_BAR_HEIGHT);
    scrollView.showsVerticalScrollIndicator = NO;
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.directionalLockEnabled = YES;
    scrollView.bounces = NO;
    scrollView.alwaysBounceVertical = YES;
    scrollView.alwaysBounceHorizontal = NO;
    [self.view addSubview:scrollView];
    
    /**
     签到页面,690为YSCSignInView内部控件总高度,用来设置滚动范围,分别为头部包装视图200,日历视图300,底部包装视图150,底部包装视图与日历视图与视图最底侧间距和40。
     */
    SignInView *signInView = [[SignInView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 690 + HEAD_BAR_HEIGHT)];
    [scrollView addSubview:signInView];
   
    
}

@end

//
//  SignInView.h

#import <UIKit/UIKit.h>
#import "FSCalendar.h"//日历类


@interface SignInView : UIView


@end
//
//  SignInView.m
//  YiShopCustomer

#import "SignInView.h"
#import "FSCalendarDynamicHeader.h"

static NSInteger const YSCCommonPadding = 10;
static NSInteger const YSCCommonTopBottomPadding = 15;

@interface SignInView()<FSCalendarDataSource,FSCalendarDelegate>

@property (nonatomic, strong) UIImageView *headerImageView;//头部背景图片视图
@property (nonatomic, strong) UIButton *signInButton;//签到按钮
@property (nonatomic, strong) UILabel *continuoussSignInLabel;//连续签到天数标签
@property (nonatomic, strong) UILabel *cumulativeSignInLabel;//累计签到天数标签
@property (nonatomic, strong) UILabel *everydaySignInRewardLabel;//每日签到奖励标签
@property (nonatomic, strong) FSCalendar *calendarView;//签到日历视图
@property (nonatomic, strong) UILabel *designatedDateSignInRewardLabel;//指定日期签到奖励标签
@property (nonatomic, strong) NSMutableArray<NSDate *> *calendarImageDataSource;//日历显示图片的数据源
@property (nonatomic, strong) NSMutableArray<NSDate *> *calendarAlreadyDataSource;//日历已经签到的数据源

@end

@implementation SignInView

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = HEXCOLOR(0x4c1130);
        [self addShowImageDaysData];
        [self createUI];
    }
    return self;
}

- (void)createUI{
    
    ///头部背景图片视图
    self.headerImageView = [[UIImageView alloc]initWithFrame:CGRectZero];
    [self.headerImageView setImage:[UIImage imageNamed:@"bg_img_0"]];
    [self addSubview:self.headerImageView];
    [self.headerImageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.right.equalTo(self);
        make.height.mas_equalTo(294.5);
    }];
    
    ///头部包装视图
    UIView *headerwWrapingView = [[UIView alloc]initWithFrame:CGRectZero];
    headerwWrapingView.backgroundColor = [UIColor clearColor];
    [self addSubview:headerwWrapingView];
    [headerwWrapingView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.mas_top);
        make.left.equalTo(self.mas_left).offset(36);
        make.right.equalTo(self.mas_right).offset(-36);
        make.height.mas_equalTo(200);
    }];
    
    ///签到按钮
    self.signInButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.signInButton setImage:[UIImage imageNamed:@"btn_sign_in_now"] forState:UIControlStateNormal];
    self.signInButton.adjustsImageWhenHighlighted = NO;
    [self.signInButton addTarget:self action:@selector(signInButtonClick) forControlEvents:UIControlEventTouchUpInside];
    [headerwWrapingView addSubview:self.signInButton];
    [self setupHeartbeatAnimationInView:self.signInButton];
    [self.signInButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(headerwWrapingView);
        make.size.mas_equalTo(CGSizeMake(86, 86));
    }];
    
    ///每日签到奖励标签
    self.everydaySignInRewardLabel = [[UILabel alloc]initWithFrame:CGRectZero];
    self.everydaySignInRewardLabel.font = [UIFont systemFontOfSize:14];
    self.everydaySignInRewardLabel.textColor = [UIColor whiteColor];
    self.everydaySignInRewardLabel.textAlignment = NSTextAlignmentCenter;
    self.everydaySignInRewardLabel.text = @"每日签到送3积分";
    [headerwWrapingView addSubview:self.everydaySignInRewardLabel];
    [self.everydaySignInRewardLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.signInButton.mas_bottom).offset(YSCCommonPadding * 2);
        make.left.equalTo(headerwWrapingView.mas_left).offset(YSCCommonPadding);
        make.right.equalTo(headerwWrapingView.mas_right).offset(- YSCCommonPadding);
    }];
    
    ///连续签到图片视图
    UIImageView *continuoussSignInView = [[UIImageView alloc]initWithFrame:CGRectZero];
    [continuoussSignInView setImage:[UIImage imageNamed:@"continuity-pic"]];
    [headerwWrapingView addSubview:continuoussSignInView];
    [continuoussSignInView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(headerwWrapingView);
        make.left.equalTo(headerwWrapingView.mas_left);
        make.size.mas_equalTo(CGSizeMake(72, 86));
    }];
    
    ///连续签到天数标签
    self.continuoussSignInLabel = [[UILabel alloc]initWithFrame:CGRectZero];
    self.continuoussSignInLabel.textAlignment = NSTextAlignmentCenter;
    self.continuoussSignInLabel.font = [UIFont systemFontOfSize:13];
    self.continuoussSignInLabel.attributedText = [self changeSignInLabelText:@"5天"];
    [headerwWrapingView addSubview:self.continuoussSignInLabel];
    [self.continuoussSignInLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(continuoussSignInView);
        make.bottom.equalTo(continuoussSignInView.mas_bottom).offset(-YSCCommonTopBottomPadding);
        make.left.right.equalTo(continuoussSignInView);
    }];
    
    ///累计签到图片视图
    UIImageView *cumulativeSignInView = [[UIImageView alloc]initWithFrame:CGRectZero];
    [cumulativeSignInView setImage:[UIImage imageNamed:@"cumulativec-pic"]];
    [headerwWrapingView addSubview:cumulativeSignInView];
    [cumulativeSignInView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(headerwWrapingView);
        make.right.equalTo(headerwWrapingView.mas_right);
        make.size.mas_equalTo(CGSizeMake(72, 86));
    }];
    
    ///累计签到天数标签
    self.cumulativeSignInLabel = [[UILabel alloc]initWithFrame:CGRectZero];
    self.cumulativeSignInLabel.textAlignment = NSTextAlignmentCenter;
    self.cumulativeSignInLabel.font = [UIFont systemFontOfSize:13];
    self.cumulativeSignInLabel.attributedText = [self changeSignInLabelText:@"5天"];
    [headerwWrapingView addSubview:self.cumulativeSignInLabel];
    [self.cumulativeSignInLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(cumulativeSignInView);
        make.bottom.equalTo(cumulativeSignInView.mas_bottom).offset(-YSCCommonTopBottomPadding);
        make.left.right.equalTo(cumulativeSignInView);
    }];
    
    ///签到日历视图
    self.calendarView = [[FSCalendar alloc] initWithFrame:CGRectMake(20, 200, SCREEN_WIDTH - 40, 300)];
    self.calendarView.backgroundColor = [UIColor whiteColor];
    //日历语言为中文
    self.calendarView.locale = [NSLocale localeWithLocaleIdentifier:@"zh-CN"];
    //允许多选,可以选中多个日期
    self.calendarView.allowsMultipleSelection = YES;
    //如果值为1,那么周日就在第一列,如果为2,周日就在最后一列
    self.calendarView.firstWeekday = 1;
    //周一\二\三...或者头部的2017年11月的显示方式
    self.calendarView.appearance.caseOptions = FSCalendarCaseOptionsWeekdayUsesSingleUpperCase;
    //设置头部年月的显示格式
    self.calendarView.appearance.headerDateFormat = @"MM月yyyy年";
    //设置头部年月的显示颜色
    self.calendarView.appearance.headerTitleColor = [UIColor  blackColor];
    //设置工作日的显示颜色
    self.calendarView.appearance.weekdayTextColor = [UIColor greenColor];
    //今天背景填充色
    self.calendarView.appearance.todayColor = HEXCOLOR(0Xf56456);
    //图片偏移量
    self.calendarView.appearance.imageOffset = CGPointMake(0, -10);
    //今天的副标题文本颜色
    self.calendarView.appearance.subtitleTodayColor = HEXCOLOR(0Xf56456);
    //隐藏日历的所有占位符
    self.calendarView.placeholderType = FSCalendarPlaceholderTypeNone;
    //日期是否可以选择
    self.calendarView.allowsSelection = NO;
    //上月与下月标签静止时的透明度
    self.calendarView.appearance.headerMinimumDissolvedAlpha = 0;
    //隐藏底部分割线,需要引入FSCalendarDynamicHeader.h文件
    self.calendarView.bottomBorder.hidden = YES;
    self.calendarView.dataSource = self;
    self.calendarView.delegate = self;
    self.calendarView.layer.cornerRadius = 10.0;
    [self addShadowToView:self.calendarView withColor:[UIColor blackColor]];
    [self addSubview:self.calendarView];
    
    ///创建点击跳转显示上一月的Button
    UIButton *previousButton = [UIButton buttonWithType:UIButtonTypeCustom];
    previousButton.titleLabel.font = [UIFont systemFontOfSize:15];
    [previousButton setImage:[UIImage imageNamed:@"btn_back_dark"] forState:UIControlStateNormal];
    [previousButton addTarget:self action:@selector(previousClicked:) forControlEvents:UIControlEventTouchUpInside];
    [self.calendarView addSubview:previousButton];
    [previousButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.calendarView.mas_top).offset(15);
        make.centerX.equalTo(self.calendarView.mas_centerX).offset(-60);
        make.size.mas_equalTo(CGSizeMake(15, 15));
    }];
    
    ///创建点击跳转显示下一月的Button
    UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeCustom];
    nextButton.titleLabel.font = [UIFont systemFontOfSize:15];
    [nextButton setImage:[UIImage imageNamed:@"btn_back_dark"] forState:UIControlStateNormal];
    nextButton.imageView.transform = CGAffineTransformMakeRotation(M_PI);
    [nextButton addTarget:self action:@selector(nextClicked:) forControlEvents:UIControlEventTouchUpInside];
    [self.calendarView addSubview:nextButton];
    [nextButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.calendarView.mas_top).offset(15);
        make.centerX.equalTo(self.calendarView.mas_centerX).offset(60);
        make.size.mas_equalTo(CGSizeMake(15, 15));
    }];
    
    ///底部图片视图
    UIImageView *footerView = [[UIImageView alloc]initWithFrame:CGRectZero];
    footerView.backgroundColor = [UIColor redColor];
    footerView.contentMode = UIViewContentModeScaleAspectFit;
    [footerView setImage:[UIImage imageNamed:@"mew_baseline"]];
    footerView.layer.cornerRadius = 10.0;
    [self addShadowToView:footerView withColor:[UIColor blackColor]];
    [self addSubview:footerView];
    [footerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.calendarView);
        make.top.equalTo(self.calendarView.mas_bottom).offset(YSCCommonPadding * 2).priorityHigh();
        make.height.mas_equalTo(150);
        make.bottom.equalTo(self.mas_bottom).offset(- YSCCommonPadding * 2).priorityLow();
    }];
    
}

///添加显示图片的天数数据
- (void)addShowImageDaysData{
    
    [self.calendarImageDataSource addObject:[self handlingTimeZoneDifferences:[self nsstringConversionNSDate:@"2019-11-11"]]];
    [self.calendarImageDataSource addObject:[self handlingTimeZoneDifferences:[self nsstringConversionNSDate:@"2019-11-17"]]];
    [self.calendarImageDataSource addObject:[self handlingTimeZoneDifferences:[self nsstringConversionNSDate:@"2019-11-19"]]];
    [self.calendarImageDataSource addObject:[self handlingTimeZoneDifferences:[self nsstringConversionNSDate:@"2019-11-25"]]];
    
}

///添加显示选中的天数数据
- (void)addShowSelectDaysData{
    
    [self.calendarAlreadyDataSource addObject:[self handlingTimeZoneDifferences:[self nsstringConversionNSDate:@"2019-11-15"]]];
    [self.calendarAlreadyDataSource addObject:[self handlingTimeZoneDifferences:[self nsstringConversionNSDate:@"2019-11-21"]]];
    [self.calendarAlreadyDataSource addObject:[self handlingTimeZoneDifferences:[self nsstringConversionNSDate:@"2019-11-23"]]];
    [self.calendarAlreadyDataSource addObject:[self handlingTimeZoneDifferences:[self nsstringConversionNSDate:@"2019-11-29"]]];
}

///更改签到天数的颜色与字体大小
- (NSMutableAttributedString *)changeSignInLabelText:(NSString *)labelText{
    
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:labelText];
    [attributedString addAttributes:@{
                                      NSForegroundColorAttributeName:[UIColor redColor],
                                      NSFontAttributeName:[UIFont systemFontOfSize:17],
                                      NSKernAttributeName:@(3),
                                      } range:NSMakeRange(0, labelText.length - 1)];
    return attributedString;
}

/// 添加四边阴影效果
- (void)addShadowToView:(UIView *)theView withColor:(UIColor *)theColor {
    // 阴影颜色
    theView.layer.shadowColor = theColor.CGColor;
    // 阴影偏移,默认(0, -3)
    theView.layer.shadowOffset = CGSizeMake(0,0);
    // 阴影透明度,默认0
    theView.layer.shadowOpacity = 0.15;
    // 阴影半径,默认3
    theView.layer.shadowRadius = 3;
}

///设置签到按钮动画
-(void)setupHeartbeatAnimationInView:(UIView *)view{
    // 设定为缩放
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    // 动画选项设定
    animation.duration = 0.4; // 动画持续时间
    animation.repeatCount = HUGE_VALF; // 重复次数(HUGE_VALF为无限重复)
    animation.autoreverses = YES; // 动画结束时执行逆动画
    // 缩放倍数
    animation.fromValue = [NSNumber numberWithFloat:1.0]; // 开始时的倍率
    animation.toValue = [NSNumber numberWithFloat:1.1]; // 结束时的倍率
    animation.removedOnCompletion = NO;
    // 添加动画
    [view .layer addAnimation:animation forKey:@"scale-layer"];
}

///处理签到按钮点击的方法
- (void)signInButtonClick{
    
    [self.signInButton setImage:[UIImage imageNamed:@"btn_sign_in_success"] forState:UIControlStateNormal];
    [self.signInButton.layer removeAnimationForKey:@"scale-layer"];
    self.signInButton.userInteractionEnabled = NO;
    [self addShowSelectDaysData];
    [self.calendarView reloadData];
    
}

///字符串转Date时间
- (NSDate *)nsstringConversionNSDate:(NSString *)dateStr {
    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"YYYY-MM-dd"];
    NSDate *datestr = [dateFormatter dateFromString:dateStr];
    return datestr;
    
}

///懒加载日历显示图片的数据源
- (NSMutableArray *)calendarImageDataSource{
    
    if(_calendarImageDataSource == nil){
        
        _calendarImageDataSource = [[NSMutableArray alloc]init];
       
    }
    return _calendarImageDataSource;
    
}

///懒加载日历显示选中的数据源
- (NSMutableArray *)calendarAlreadyDataSource{
    
    if(_calendarAlreadyDataSource == nil){
        
        _calendarAlreadyDataSource = [[NSMutableArray alloc]init];
       
    }
    return _calendarAlreadyDataSource;
    
}

///Date数据源是否包含指定的Date
- (BOOL)didDataDource:(NSMutableArray<NSDate *> *)dataSource contains:(NSDate *)date{
    
    //处理时区差
    NSDate *localeDate = [self handlingTimeZoneDifferences:date];
    //如果数据源包含date,这一天要显示小礼盒
    if([dataSource containsObject:localeDate]){
        //如果今天和小礼盒要显示的天数相等,显示小礼盒,隐藏填充色
        if([self compareOneDay:localeDate withAnotherDay:[self handlingTimeZoneDifferences:[NSDate date]]]){
            self.calendarView.appearance.todayColor = [UIColor clearColor];
        }
        return YES;
        
    }
    return NO;
}

///处理时区差
- (NSDate *)handlingTimeZoneDifferences:(NSDate *)date{
    
    NSTimeZone *zone = [NSTimeZone systemTimeZone];
    NSInteger interval = [zone secondsFromGMTForDate:date];
    NSDate *localeDate = [date dateByAddingTimeInterval:interval];
    return localeDate;
}

///忽略时分秒进行Date比较,相等返回yes
- (BOOL)compareOneDay:(NSDate *)oneDay withAnotherDay:(NSDate *)anotherDay{
    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    NSString *oneDayStr = [dateFormatter stringFromDate:oneDay];
    NSString *anotherDayStr = [dateFormatter stringFromDate:anotherDay];
    if([oneDayStr isEqualToString:anotherDayStr]){
        
        return YES;
        
    }else{
        
        return NO;
        
    }
    
}

///上一月按钮点击事件
- (void)previousClicked:(id)sender {
    
    NSDate *currentMonth = self.calendarView.currentPage;
    NSCalendar *gregorian = [NSCalendar currentCalendar];
    NSDate *previousMonth = [gregorian dateByAddingUnit:NSCalendarUnitMonth value:-1 toDate:currentMonth options:0];
    [self.calendarView setCurrentPage:previousMonth animated:YES];
}

///下一月按钮点击事件
- (void)nextClicked:(id)sender {
    
    NSDate *currentMonth = self.calendarView.currentPage;
    NSCalendar *gregorian = [NSCalendar currentCalendar];
    NSDate *nextMonth = [gregorian dateByAddingUnit:NSCalendarUnitMonth value:1 toDate:currentMonth options:0];
    [self.calendarView setCurrentPage:nextMonth animated:YES];
}

///按大小缩放图片
- (UIImage *)scaleToSize:(UIImage *)img size:(CGSize)size{
    
    UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
    [img drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}


#pragma make -- FSCalendarDataSource
// 向数据源查询特定日期的图像。
- (nullable UIImage *)calendar:(FSCalendar *)calendar imageForDate:(NSDate *)date{
    
    if([self didDataDource:self.calendarImageDataSource contains:date]){
        //缩放一下图片
        UIImage *image = [self scaleToSize:[UIImage imageNamed:@"ic_gift"] size:CGSizeMake(20, 20)];
        return image;
        
    }
    return nil;
    
}

//向代理询问未选定状态下的具体日期的填充颜色。
- (nullable UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance fillDefaultColorForDate:(NSDate *)date{
    
    if([self didDataDource:self.calendarAlreadyDataSource contains:date]){
        return HEXCOLOR(0Xf56456);
    }
    return [UIColor clearColor];
}

//向代理询问未选定状态下的日期文本颜色。
- (nullable UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance titleDefaultColorForDate:(NSDate *)date{
    
    if([self didDataDource:self.calendarAlreadyDataSource contains:date]){
        return [UIColor whiteColor];
    }
    return [UIColor blackColor];
}

//在日期文本下向数据源请求特定日期的副标题
- (nullable NSString *)calendar:(FSCalendar *)calendar subtitleForDate:(NSDate *)date{
    
    if ([self.calendarView.today isEqualToDate:date]){
    
        return @"今天";
        
    }
    
    return nil;
    
}

//向代理询为特定日期的日期文本提供偏移量。
- (CGPoint)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance titleOffsetForDate:(NSDate *)date{
    
    if ([self.calendarView.today isEqualToDate:date]){
        
        return CGPointMake(0, 7);
        
    }
    return CGPointMake(0,0);

}

//向代理询问特定日期副标题的偏移量。
- (CGPoint)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance subtitleOffsetForDate:(NSDate *)date{
    
    if ([self.calendarView.today isEqualToDate:date]){
        
        return CGPointMake(0, 18);
        
    }
    return CGPointMake(0, 0);
    
}


@end

//
//  Macro.h
// 宏定义

#ifndef Macro_h
#define Macro_h

// MARK:- 系统尺寸宏定义
#define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT))
#define SCREEN_MIN_LENGTH (MIN(SCREEN_WIDTH, SCREEN_HEIGHT))

// MARK:- 手机型号
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_4_OR_LESS (IS_IPHONE && SCREEN_MAX_LENGTH < 568.0)
#define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0)
#define IS_IPHONE_6 (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0)
#define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)
#define IS_IPHONE_6_OR_6P (IS_IPHONE_6 || IS_IPHONE_6P)
#define IS_IPHONE_X (IS_IPHONE && SCREEN_MAX_LENGTH >= 812)

//屏幕的宽
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
//屏幕的高
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
//导航栏的高
#define NAVIGATIONBAR_HEIGHT self.navigationController.navigationBar.frame.size.height
//导航栏的高
#define HEAD_BAR_HEIGHT (IS_IPHONE_X?88:64)
//状态栏的高
#define STATUSBARHEIGHT [UIApplication sharedApplication].statusBarFrame.size.height
//获取视图的宽度
#define WIDTH(view) view.frame.size.width
//字符串不为空
#define IS_NOT_EMPTY(string) (string !=nil && [string isKindOfClass:[NSString class]] && ![string isEqualToString:@""] && ![string isKindOfClass:[NSNull class]] && ![string isEqualToString:@"<null>"])
//数组不为空
#define ARRAY_IS_NOT_EMPTY(array) (array && [array isKindOfClass:[NSArray class]] && [array count])
//设置RGBA颜色
#define RGBA(r, g, b, a) [UIColor colorWithRed:r / 255.0 green:g / 255.0 blue:b / 255.0 alpha:a]
//十六进制颜色
#define HEXCOLOR(c)                                  \
[UIColor colorWithRed:((c >> 16) & 0xFF) / 255.0 \
green:((c >> 8) & 0xFF) / 255.0  \
blue:(c & 0xFF) / 255.0         \
alpha:1.0]

//是否为iphone_X
#define DEVICE_IS_IPHONE_X ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125.0, 2436.0), [[UIScreen mainScreen] currentMode].size) : NO)

#endif /* Macro_h */

运行结果:

Jietu20191115-225750-HD.gif

相关文章

网友评论

      本文标题:NSDate日期类学习笔记

      本文链接:https://www.haomeiwen.com/subject/uarhsqtx.html