Swift OC-开发案例收集

iOS 关于Date、DateFormatter、时区和Cale

2020-03-24  本文已影响0人  大成小栈

1. Swift 实现 Date 的日常用法

// 获取当前的时间戳10位
class func getCurrentTimeInTerval() -> TimeInterval {

  return Date().timeIntervalSince1970
}

// 获取当前的日期
class func getCurrentDate() -> String {

  let now = Date()
  let formatter = DateFormatter()
  formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
  return formatter.string(from: now)
}

// 获取明天年月日
class func getTomorrowDate() -> String {

  let current = Date()
  let formatter = DateFormatter()
  formatter.dateFormat = "yyyy年MM月dd日"
  let interval: TimeInterval = TimeInterval(24*60*60)
  let tomorrow = current.addingTimeInterval(interval)
  return formatter.string(from: tomorrow) 
}

// 时间戳转换为Date类型
class func dateFromTimeStamp(timeStamp:String) ->Date {

  let interval:TimeInterval = TimeInterval.init(timeStamp)!
  return Date(timeIntervalSince1970: interval)
}

// 时间格式转换成时间戳
class func dateStrToTimeInterval(dateStr: String) -> Int  {

  let dateformatter = DateFormatter()
  dateformatter.dateFormat = "yyyy年MM月dd日 HH:mm:ss"
  let date = dateformatter.date(from: dateStr)
  let dateTimeInterval:TimeInterval = date!.timeIntervalSince1970
  return Int(dateTimeInterval)
}

// 时间格式转换为Date类型
 class func timeStrToDate(timeStr: String) -> Date {

  let dateformatter = DateFormatter()
  dateformatter.dateFormat = "yyyy年MM月dd日"
  return dateformatter.date(from: timeStr)!
}   // 注:print(dateformatter.date(from: time)!)不要这样打印去看date ,看到的跟你输入的不一样但是它并不是错误的。可以采用下面的方式打印查看 print(dateformatter.string(from: date))

// 获取当前年份和月份和日
class func getCurrentYearMonthDay() -> (Int, Int, Int) {

  let calendar = Calendar.current
  let dateComponets = calendar.dateComponents([Calendar.Component.year,Calendar.Component.month,Calendar.Component.day], from: Date())
  return (dateComponets.year!, dateComponets.month!, dateComponets.day!)
}

// 获取当前月的总天数
class func getCurentMonthDays() -> Int {

  let calendar = Calendar.current
  let range = calendar.range(of: Calendar.Component.day, in: Calendar.Component.month, for: Date())
  return range!.count
}

// 根据date获取是周几
 func getWeedayFromeDate(date: Date) -> String {

  let calendar = Calendar.current
  let dateComponets = calendar.dateComponents([Calendar.Component.year,Calendar.Component.month,Calendar.Component.weekday,Calendar.Component.day], from: date)
  //获取到今天是周几 1(星期天) 2(星期一) 3(星期二) 4(星期三) 5(星期四) 6(星期五) 7(星期六)
  let weekDay = dateComponets.weekday
  switch weekDay {
    case 1:
      return "星期天"
    case 2:
      return  "星期一"
    case 3:
      return "星期二"
    case 4:
      return "星期三"
    case 5:
      return "星期四"
    case 6:
      return "星期五"
    case 7:
      return "星期六"
    default:
      return ""
   }
}

// 根据时间戳与当前时间的比较(类似朋友圈的时间显示)
    class func compareCurrntTime(timeStamp:String) -> String {

  //计算出时间戳距离现在时间的一个秒数(..s)
  let interval:TimeInterval=TimeInterval(timeStamp)!
  let date = Date (timeIntervalSince1970: interval)
  var timeInterval = date.timeIntervalSinceNow
  //得到的是一个负值 (加' - ' 得正以便后面计算)
  timeInterval = -timeInterval
  //根据时间差 做所对应的文字描述 (作为返回文字描述)
  var result:String
  //一分钟以内
  if interval < 60{
    result = "刚刚"
    return result
  } 
  else if Int(timeInterval/60) < 60{
    //一小时以内
    result = String.init(format:"%@分钟前",String(Int(timeInterval/60)))
    return result
  } else if Int((timeInterval/60)/60) < 24{
    //一天以内
    result = String.init(format:"%@小时前",String(Int((timeInterval/60)/60)))
    return result
  }
  else {
    //超过一天的
    let dateformatter = DateFormatter()
    //自定义日期格式
    dateformatter.dateFormat="yyyy年MM月dd日 HH:mm"
    result = dateformatter.string(from: date as Date)
    return result
  }
}

// 得到本每周 开始 和 结束的时间
class func getCurrentWeekDays() -> (String, String) {

  let now = Date()
  let calendar = Calendar.current
  let dateComponets = calendar.dateComponents([Calendar.Component.year,Calendar.Component.month,Calendar.Component.weekday,Calendar.Component.day], from: now)
  //获取到今天是周几 1(星期天) 2(星期一) 3(星期二) 4(星期三) 5(星期四) 6(星期五) 7(星期六)
  let weekDay = dateComponets.weekday
  // 得到几号
  let day = dateComponets.day        
  // 计算当前日期和这周的星期一和星期天差的天数
  var firstDiff = 0
  var lastDiff = 0
  if weekDay == 1 {
    firstDiff = 1
    lastDiff = 0
  } 
  else {
    firstDiff = calendar.firstWeekday - weekDay!+1;
    lastDiff = 9 - weekDay!-1;
  }
  var firstDayComp = calendar.dateComponents([Calendar.Component.year,Calendar.Component.month,Calendar.Component.day], from: now)
  firstDayComp.day = day! + firstDiff
  let firstDayOfWeek = calendar.date(from: firstDayComp)
  var lastDayComp = calendar.dateComponents([Calendar.Component.year,Calendar.Component.month,Calendar.Component.day], from: now)
  lastDayComp.day = day! + lastDiff
  let lastDayOfWeek = calendar.date(from: lastDayComp)
  let formater = DateFormatter()
  formater.dateFormat="yyyy年MM月dd日"
  let startW = formater.string(from: firstDayOfWeek!)
  let endW = formater.string(from: lastDayOfWeek!)
  return (startW, endW)
}

// 检测日期
class func checkDate(str: String) -> String {
  let format = DateFormatter()
  if let date = format.date(from: str) {
    if Calendar.current.isDateInToday(date) {
        return "日期是今天"
    } else if Calendar.current.isDateInYesterday(date) {
        return "日期是昨天"
    } else if Calendar.current.isDateInTomorrow(date) {
        return "日期是明天"
    } else if Calendar.current.isDateInWeekend(date) {
        return "日期是周末"
    } else if Calendar.current.isDate(date, inSameDayAs: Date()) {
        return "日期是今天,也就是传入的和今天的是相同的日期"
    } else {
        return ""
    }
  }
  return ""
}

2. Swift中使用DateFormatter

iOS中DateFormatter可以把时间转换成我们想要的时间格式:

//日期转字符串
let currentDate = Date.init()
let dateFormatter = DateFormatter.init()
dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
let currentTime: String = dateFormatter.string(from: currentDate)

//字符串转日期
let createTime = "2018-11-30 13:40:54"
let dateFormatter = DateFormatter.init()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date: Date = dateFormatter.date(from: createTime)
2.1 时间格式化过程中的符号
2.2 时间格式化过程中的locale

最近在工作中,需要将后台返回的时间字符串做格式化操作,期望格式是要展示成
09 Nov 2018 14:56:47,后台返回的时间字符串格式是20181119175515,所以程序中代码自然就写成如下格式:

NSString* createTime =@"20181119175515";
NSDateFormatter* dateFormat = [[NSDateFormatter alloc] init];
 [dateFormat setDateFormat:@"yyyyMMddHHmmss"];
NSDate*date =[dateFormat dateFromString:createTime];
 [dateFormat setDateFormat:@"dd MMM yyyy HH:mm:ss"];
 NSString*currentDateStr = [dateFormat stringFromDate:date];

但是输出的是:19 11月 2018 17:55:15
如果更改手机系统语言为English,时间格式化输出的就是19 Nov 2018 17:55:15

这时,NSDateFormatter中的locale属性就可以发挥作用了,NSLocale类是将与国家和语言相关的信息进行简单的组合,包括货币、语言、国家等的信息。将下面这段代码添加到dateFormat初始化之后,发现无论在什么系统语言下,时间格式化之后都是19 Nov 2018 17:55:15

//根据需要设置国家代码
NSLocale *usLocale=[[NSLocale alloc]initWithLocaleIdentifier:@"en_US"];
dateFormat.locale=usLocale;

NSLocale的常用方法:

//当前用户设置的本地化对象
[NSLocale currentLocale]
//获取系统所有本地化标识符数组列表
[NSLocale availableLocaleIdentifiers] ;
//获取所有已知合法的国家代码数组列表
[NSLocale ISOCountryCodes] ;
//获取所有已知合法的ISO货币代码数组列表
[NSLocale ISOCurrencyCodes] ;
//获取所有已知合法的ISO语言代码数组列表
[NSLocale ISOLanguageCodes] ;
//获取当前系统设置语言的标识符
[[NSLocale currentLocale] localeIdentifier];

//常量
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleIdentifier;// 当前系统设置语言的标识符
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleLanguageCode;// 语言代码
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleCountryCode;// 国家代码
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleScriptCode;// 脚本代码
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleVariantCode;// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleExemplarCharacterSet;// NSCharacterSet
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleCalendar;// 当地日历
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleCollationIdentifier;// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleUsesMetricSystem;// NSNumber boolean
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleMeasurementSystem;// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleDecimalSeparator;// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleGroupingSeparator;// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleCurrencySymbol;// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleCurrencyCode;// 货币代码
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleCollatorIdentifierNS_AVAILABLE(10_6,4_0);// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleQuotationBeginDelimiterKey NS_AVAILABLE(10_6,4_0);// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleQuotationEndDelimiterKey NS_AVAILABLE(10_6,4_0);// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleAlternateQuotationBeginDelimiterKey NS_AVAILABLE(10_6,4_0);// NSString
FOUNDATION_EXPORT NSLocaleKeyconst NSLocaleAlternateQuotationEndDelimiterKey NS_AVAILABLE(10_6,4_0);// NSString

//获取当前语言的排版方向和字符方向
[NSLocale lineDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode];
[NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode] ;
//获取用户的语言偏好设置列表,该列表对应于IOS中Setting>General>Language弹出的面板中的语言列表。
[NSLocale preferredLanguages];
//监听用户本地化设置的消息
[[NSNotification CenterdefaultCenter] addObserver:self selector:@selector(localChangedHandler:) name:NSCurrentLocaleDidChangeNotificationobject:nil];
//以本地化方式获取国际化信息的显示名称
NSLocale* curLocal = [[NSLocale alloc]initWithLocaleIdentifier:@"zh-Hans"] ;
NSLog(@"%@",[curLocal displayNameForKey:NSLocaleIdentifiervalue:@"fr_FR"] );//法文(法国)
curLocal= [[NSLocale alloc]initWithLocaleIdentifier:@"zh-Hant"] ;
NSLog(@"%@",[curLocal displayNameForKey:NSLocaleIdentifiervalue:@"fr_FR"]);//法文(法國)

3. 时区的处理 (dateFormatter.timeZone)

格林威治时间(Greenwich Mean Time,GMT),是指英国伦敦南郊格林威治的天文台所在地的标准时间。1884年,国际子午线会议通过表决,以通过格林威治的天文台的经线为本初子午线。子午线就是经线,本初子午线就是零度经线。这就是为什么24个时区都以格林威治的区时为基础进行加减的原因。
格林尼治平均时间的正午是指当平太阳横穿格林尼治子午线时(也就是在格林尼治上空最高点时)的时间。由于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治平时基于天文观测本身的缺陷,已经被原子钟报时的协调世界时(UTC)所取代。
一般使用GMT+8表示中国的时间,是因为中国位于东八区,时间上比格林威治时间快8个小时。

区分:CST、CET、UTC、GMT、DST、Unix时间戳

UTC:UTC指的是Coordinated Universal Time- 世界协调时间(又称世界标准时间、世界统一时间),是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间,计算过程相当严谨精密,因此若以「世界标准时间」的角度来说,UTC比GMT来得更加精准。其误差值必须保持在0.9秒以内,若大于0.9秒则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。所以基本上UTC的本质强调的是比GMT更为精确的世界时间标准。
GMT:Greenwich Mean Time 格林尼治平均时,UTC和GMT都与英国伦敦的本地时相同,所以程序中UTC与GMT没什么不同。只是说GMT可能就精确性来说不如UTC。
Unix时间戳:在计算机中看到的UTC时间都是从(1970年01月01日 0:00:00)开始计算秒数的。所看到的UTC时间那就是从1970年这个时间点起到具体时间共有多少秒。 这个时间戳可以唯一地标识某一刻的时间,即不论时区、当地时间是多少,时间戳都一致。它的提出主要是为用户提供一份电子证据, 以证明用户的某些数据的产生时间。
CST:CST却同时可以代表如下 4 个不同的时区:
Central Standard Time (USA) UT-6:00(美国中部时间)
Central Standard Time (Australia) UT+9:30(澳大利亚中部时间)
China Standard Time UT+8:00(中国标准时间)
Cuba Standard Time UT-4:00(古巴标准时间)
CET:Central European Time,欧洲中部时间,它是比世界标准时间UTC早一个小时的时区名称之一,它被大部分欧洲国家和部分北非国家采用。冬季时间为UTC+1,夏季欧洲夏令时为UTC+2。
DST:Daylight Saving Time(夏日节约时),其实就是前面提到的夏令时。
这么来看,它们的关系就很明确了,一般认为:
UTC = GMT
CET = UTC/GMT+1
CST = CET+9 = UTC/GMT+8 = UTC/GMT-6 = UTC/GMT-4

4. 时间的比较

let date1 = Date()
let date2 = Date()

// date1 < date2 升序排列
if date1?.compare(date2!) == .orderedAscending {
      print("<")
}

//date1 = date2 相等
if date1?.compare(date2!) == .orderedSame {
      print(" = ")
}  
//降序排列的 date1 > date2 降序排列
if date1?.compare(date2!) == .orderedDescending {
    print("<")
}

5. iOS中的Calendar

用打印台来输出日历:

在显示日历的时候,我们只需要传入参数年月即可,加上日期可以定位到当天在日历上的显示。日历的显示排版一般是7x5或7x4,每一行从周日开始,周六结束,当我们要显示某个月份的时候,我们必需获取到下面这些值:
1.当月第一天是周几;
2.当月总天数

有了这两条数据我们就可以显示出一个粗糙的日历了,但是有一点,假如当月第一天不是周一,如上图,那么前面几天的日期如何显示呢?所以我们会需要多一条数据:上个月份的总天数,通过简单的加减就能显示了,下面开始通过代码了解如何制作一个日历。

//根据date获取日
- (NSInteger)convertDateToDay:(NSDate *)date {
    NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitDay) fromDate:date];
    return [components day];
}

//根据date获取月
- (NSInteger)convertDateToMonth:(NSDate *)date {
    NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitMonth) fromDate:date];
    return [components month];
}

//根据date获取年
- (NSInteger)convertDateToYear:(NSDate *)date {
    NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitYear) fromDate:date];
    return [components year];
}

//根据date获取当月周几 (美国时间周日-周六为 1-7,改为0-6方便计算)
- (NSInteger)convertDateToWeekDay:(NSDate *)date {
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond|NSCalendarUnitWeekday fromDate:date];
    NSInteger weekDay = [components weekday] - 1;
    weekDay = MAX(weekDay, 0);
    return weekDay;
}

//根据date获取当月周几
- (NSInteger)convertDateToFirstWeekDay:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    [calendar setFirstWeekday:1];//1.Sun. 2.Mon. 3.Thes. 4.Wed. 5.Thur. 6.Fri. 7.Sat.
    NSDateComponents *comp = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date];
    [comp setDay:1];
    NSDate *firstDayOfMonthDate = [calendar dateFromComponents:comp];
    NSUInteger firstWeekday = [calendar ordinalityOfUnit:NSCalendarUnitWeekday inUnit:NSCalendarUnitWeekOfMonth forDate:firstDayOfMonthDate];
    return firstWeekday - 1;  //美国时间周日为星期的第一天,所以周日-周六为1-7,改为0-6方便计算
}

//根据date获取当月总天数
- (NSInteger)convertDateToTotalDays:(NSDate *)date {
    NSRange daysInOfMonth = [[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date];
    return daysInOfMonth.length;
}

在获取周几的时候要注意一点,美国时间是星期日作为一周的第一天,所以通过函数回调的值,周日-周六是为1-7的,为了方便计算,我进行了-1操作。

接下来是获取上个月份的数据:

//根据date获取偏移指定天数的date
- (NSDate *)getDateFrom:(NSDate *)date offsetDays:(NSInteger)offsetDays {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM"];

    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
    [lastMonthComps setDay:offsetDays];  //year = 1表示1年后的时间 year = -1为1年前的日期,month day 类推
    NSDate *newdate = [calendar dateByAddingComponents:lastMonthComps toDate:date options:0];
    return newdate;
}

//根据date获取偏移指定月数的date
- (NSDate *)getDateFrom:(NSDate *)date offsetMonths:(NSInteger)offsetMonths {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM"];

    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
    [lastMonthComps setMonth:offsetMonths];  //year = 1表示1年后的时间 year = -1为1年前的日期,month day 类推
    NSDate *newdate = [calendar dateByAddingComponents:lastMonthComps toDate:date options:0];
    return newdate;
}

//根据date获取偏移指定年数的date
- (NSDate *)getDateFrom:(NSDate *)date offsetYears:(NSInteger)offsetYears {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy"];

    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
    [lastMonthComps setYear:offsetYears];  //year = 1表示1年后的时间 year = -1为1年前的日期,month day 类推
    NSDate *newdate = [calendar dateByAddingComponents:lastMonthComps toDate:date options:0];
    return newdate;
}

有了这几个函数,就能具备制作一个日历的数据支持了,接下来的代码可以自行复制输出:

- (void)test {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    for (int i = 1; i <= 12; i++) {
        NSString *string = [NSString stringWithFormat:@"2018-%02d-01",i];
        NSDate *date = [dateFormatter dateFromString:string];
        [self logCalendarWith:date];
    }
}

- (void)logCalendarWith:(NSDate *)date {
    NSInteger year = [self convertDateToYear:date];
    NSInteger month = [self convertDateToMonth:date];
    NSInteger day = [self convertDateToDay:date];
    NSInteger firstWeekDay = [self convertDateToFirstWeekDay:date];
    NSInteger totalDays = [self convertDateToTotalDays:date];

    printf("第%ld月\n",month);

    NSInteger line = totalDays <= 28 ? 4 : 5;
    NSInteger column = 7;

    NSInteger available = 1;    //超过总天数后为下月
    NSInteger nextMonthDay = 1; //下月天数开始计数

    NSDate *lastMonthDate = [self getDateFrom:date offsetMonths:-1];    //上月月数
    NSInteger lastMonthTotalDays = [self convertDateToTotalDays:lastMonthDate]; //上月天数计数

    for (int i = 0; i < line; i++) {
        for (int j = 0; j < column; j++) {
            if (available > totalDays) {
                printf("\t%ld ",nextMonthDay++);
                continue;
            }

            if (i == 0 && j < firstWeekDay) {
                NSInteger lastMonthDay = lastMonthTotalDays - firstWeekDay + j + 1; //j从0开始,所以这里+1
                printf("\t%ld ",lastMonthDay);
            }else {
                printf("\t%ld",available++);
            }
        }
        printf("\n");
    }
    printf("\n");
    printf("\n");
}

想要测试年份、月份、日的准确性的话,就在test函数里面自行修改就好了,如果没有问题,打印台就有下面的显示:

参考文章:
https://www.jianshu.com/p/e008341fbda1
https://www.jianshu.com/p/b7d0023c0bdf

上一篇下一篇

猜你喜欢

热点阅读