iOS - 聊聊时间(Date)

时间概念

  • GMT

格林尼治标准时间(旧译格林威治平均时间或格林威治标准时间;英语:GreenwichMeanTime,GMT)是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。 理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治时)的时间。由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能和实际的太阳时相差16分钟。

  • UTC

协调世界时,又称世界统一时间、世界标准时间、国际协调时间。由于英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称UTC。

协调世界时是以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统。中国大陆采用ISO 8601-1988的《数据元和交换格式信息交换日期和时间表示法》(GB/T 7408-1994)称之为国际协调时间,代替原来的GB/T 7408-1994;中国台湾采用CNS 7648的《资料元及交换格式–资讯交换–日期及时间的表示法》,称之为世界统一时间。

Date介绍

A specific point in time, independent of any calendar or time zone.

SwiftDate是一个结构体(struct),该结构体提供了日期相关的操作

public struct Date : ReferenceConvertible, Comparable, Equatable {}

创建Date

public init()
public init(timeIntervalSinceNow: TimeInterval)
public init(timeIntervalSince1970: TimeInterval)
public init(timeInterval: TimeInterval, since date: Date)
public init(timeIntervalSinceReferenceDate ti: TimeInterval)
  • init()

该方法会根据当前的日期和时间来创建Date

let date = Date()
print("now: \(date)")
// now: 2019-03-27 06:37:23 +0000
  • init(timeIntervalSinceNow: TimeInterval)

该方法会根据当前时间为基准,然后过了指定的时间(秒)创建Date,如下面5秒之后

let date1 = Date()
print("date1: \(date1)")

let date2 = Date(timeIntervalSinceNow: 5)
print("date2: \(date2)")

// date1: 2019-03-27 06:45:29 +0000
// date2: 2019-03-27 06:45:34 +0000
  • init(timeIntervalSince1970: TimeInterval)

该方法以世界时间(UTC)1970年1月1日凌晨为参考创建Date,参数是相对于指定时间的间隔

let date = Date(timeIntervalSince1970: 0)
print("date: \(date)")
// 1970-01-01 00:00:00 +0000
  • init(timeInterval: TimeInterval, since date: Date)

方法根据给定的date和指定的时间间隔创建一个新的Date

let currentDate = Date()
print("currentDate: \(currentDate)")
let date = Date(timeInterval: 2, since: currentDate)
print("date: \(date)")

currentDate: 2019-03-27 07:06:47 +0000
date: 2019-03-27 07:06:49 +0000
  • init(timeIntervalSinceReferenceDate ti: TimeInterval)

返回以2001/01/01 UTC为基准,然后过了secs秒的时间

let date = Date(timeIntervalSinceReferenceDate: 2)
print("date: \(date)")
// date: 2001-01-01 00:00:02 +0000

Date比较

public func compare(_ other: Date) -> ComparisonResult 
public static func == (lhs: Date, rhs: Date) -> Bool //返回true,表示两个Date值代表相同的时间
public static func < (lhs: Date, rhs: Date) -> Bool // 左边的时间早返回true
public static func > (lhs: Date, rhs: Date) -> Bool // 左边的时间晚返回true

ComparisonResult是一个枚举,用于表示请求排序的结果,如下

public enum ComparisonResult : Int {
    case orderedAscending // 操作数a < 操作数b 
    case orderedSame // a == b
    case orderedDescending // a > b
}

对于Date而言

当前date值早于anotherDate时返回orderedAscending
当前date值与anotherDate相同时返回orderedSame
当前date值晚于anotherDate时返回orderedDescending

let date1 = Date(timeIntervalSinceNow: 1)
let date2 = Date(timeIntervalSinceNow: 5)
let result = date1.compare(date2)
switch result {
case .orderedAscending:
    print("orderedAscending")
case .orderedSame:
    print("orderedSame")
case .orderedDescending:
    print("orderedDescending")
}
// orderedAscending

获取时间间隔

public func timeIntervalSince(_ date: Date) -> TimeInterval // 以date为基准时间,返回实例保存的时间与date的时间间隔
public var timeIntervalSinceNow: TimeInterval { get } // 以当前时间(Now)为基准时间,返回实例保存的时间与当前时间(Now)的时间间隔
public var timeIntervalSince1970: TimeInterval { get } //以1970/01/01 UTC为基准时间,返回实例保存的时间与1970/01/01 UTC的时间间隔
public var timeIntervalSinceReferenceDate: TimeInterval { get } // 以2001/01/01 UTC为基准时间,返回实例保存的时间与2001/01/01 UTC的时间间隔
public static var timeIntervalSinceReferenceDate: TimeInterval { get } // 以2001/01/01 UTC为基准时间,返回当前时间(Now)与2001/01/01 UTC的时间间隔
public static let timeIntervalBetween1970AndReferenceDate: TimeInterval //1970/01/01 UTC与2001/01/01 UTC的时间间隔

DateFormatter

A formatter that converts between dates and their textual representations.

DateFormatter简单理解就是Date的格式化工具,展示成易于理解的样式

open class DateFormatter : Formatter { }

对象之间的转换

open func string(from date: Date) -> String //  Date ->  String
open func date(from string: String) -> Date? // String -> Date

格式化和样式

open var dateFormat: String!
open var dateStyle: DateFormatter.Style
open var timeStyle: DateFormatter.Style

DateFormatter.Style是一个枚举,如下

extension DateFormatter {
    public enum Style : UInt {
        case none
        case short
        case medium
        case long
        case full
    }
}

简单使用

let date = Date()
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .full

let dateString = formatter.string(from: date)
print(dateString)

测试修改timeStyle的样式,运行如下

// full full
Wednesday, March 27, 2019 at 4:12:29 PM China Standard Time
// full long
Wednesday, March 27, 2019 at 4:13:19 PM GMT+8
// full medium
Wednesday, March 27, 2019 at 4:11:27 PM
// full short
Wednesday, March 27, 2019 at 4:13 PM
// full none
Wednesday, March 27, 2019

自定义格式化

实际的开发中,更多的是根据需求,自定义显示样式,将样式字符串赋值dateFormat属性

let date = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

let dateString = formatter.string(from: date)
print(dateString) // 2019-03-27 16:19:10

一些格式化形式

  • EEEE:表示星期几(Monday),使用1-3个字母表示周几的缩写
  • MMMM:月份的全写(October),使用1-3个字母表示月份的缩写
  • dd:表示日期,使用一个字母表示没有前导0
  • YYYY:四个数字的年份
  • HH:两个数字表示的小时
  • mm:两个数字的分钟
  • ss:两个数字的秒
  • zzz:三个字母表示的时区
屏幕快照 2019-03-26 下午7.07.14.png

基本使用

  • 时间(Date)转字符串(String)
// 获取当前时间
let now = Date()

// 格式化
let formatter = DateFormatter()
formatter.dateFormat = "yyyy年MM月dd日 HH:mm:ss"
print("当前日期时间:\(formatter.string(from: now))") //当前日期时间:2019年03月27日 17:06:22

 // 当前时间的时间戳
let timeInterval:TimeInterval = now.timeIntervalSince1970
let timeStamp = Int(timeInterval)
print("时间戳:\(timeStamp)") // 时间戳:1553677582
  • 将时间戳转为日期时间
// 时间戳
let timeStamp = 1553677582

// 转换为时间
let timeInterval:TimeInterval = TimeInterval(timeStamp)
let date = Date(timeIntervalSince1970: timeInterval)

// 格式话输出
let formatter = DateFormatter()
formatter.dateFormat = "yyyy年MM月dd日 HH:mm:ss"
print("时间:\(formatter.string(from: date))") // 时间:2019年03月27日 17:06:22
  • String转换为Date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZ" // 格式
let date = dateFormatter.date(from: strDate) // strDate:字符串日期
  • 拆分Date

有时候你可能想获取Date中的day,month,hour 等的值。这里就需要使用DateComponents通常和 Calendar.

Calendar 实现了真正的从DateDateComponents的转换以及从日期的组成元素到日期对象的转换.

Date到DateComponents

let currentdate = Date()
let calendar = Calendar.current

let dateComponents = calendar.dateComponents([.year,.month, .day, .hour,.minute,.second], from: currentdate)

print("year: \(dateComponents.year), \n month: \(dateComponents.month),\n day: \(dateComponents.day),\n hour: \(dateComponents.hour),\n minute: \(dateComponents.hour),\n second: \(dateComponents.second)")

// 运行结果
year: Optional(2019), 
 month: Optional(3),
 day: Optional(27),
 hour: Optional(16),
 minute: Optional(16),
 second: Optional(17)

DateComponents到Date

let calendar = Calendar.current

var dateComponents = DateComponents()
dateComponents.day = 28
dateComponents.month = 3
dateComponents.year = 2019
dateComponents.hour = 18
dateComponents.minute = 35
dateComponents.second = 16

let date = calendar.date(from: dateComponents)
print(date!) // 2019-03-28 10:35:16 +0000

Date简单的扩展

实际开发过程中将相关功能添加到extension中是一种很好的方式

extension Date {
    public init?(fromString string: String, format: String) {
        let formatter = DateFormatter()
        formatter.dateFormat = format
        if let date = formatter.date(from: string) {
            self = date
        } else {
            return nil
        }
    }

    public func toString(format: String) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = format
        return formatter.string(from: self)
    }

    public func timePassed() -> String {
        let date = Date()
        let calendar = Calendar.current
        let components = (calendar as NSCalendar).components([.year, .month, .day, .hour, .minute, .second], from: self, to: date, options: [])

        if components.year! >= 1 {
            return "\(components.year!)年前"
        } else if components.month! >= 1 {
            return "\(components.month!)个月前"
        } else if components.day! >= 1 {
            return "\(components.day!)天前"
        } else if components.hour! >= 1 {
            return "\(components.hour!)小时前"
        } else if components.minute! >= 1 {
            return "\(components.minute!)分钟前"
        } else if components.second == 0 {
            return "刚刚"
        } else {
            return "\(components.second!)秒前"
        }
    }

    public var year: Int {
        return Calendar.current.component(Calendar.Component.year, from: self)
    }

    public var month: Int {
        return Calendar.current.component(Calendar.Component.month, from: self)
    }

    public var weekday: String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "EEEE"
        return dateFormatter.string(from: self)
    }

    public var monthAsString: String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMMM"
        return dateFormatter.string(from: self)
    }

    public var day: Int {
        return Calendar.current.component(.day, from: self)
    }

    public var hour: Int {
        return Calendar.current.component(.hour, from: self)
    }

    public var minute: Int {
        return Calendar.current.component(.minute, from: self)
    }

    public var second: Int {
        return Calendar.current.component(.second, from: self)
    }
}

实际场景

  • 1、判断两个日期是否为同一天

OC实现

- (BOOL)isToday {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    int unit = NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear;

    NSDateComponents *nowCmps = [calendar components:unit fromDate:[NSDate date]];
    NSDateComponents *selfCmps = [calendar components:unit fromDate:self];

    return (selfCmps.year == nowCmps.year) && (selfCmps.month == nowCmps.month) && (selfCmps.day == nowCmps.day);
}

Swift实现

1、格式化成字符串比较

将两个日期格式化成只包含年月日的字符串,再比较两个字符串是否相等。

func isTheSameDay(startDate: Date, endDate: Date) {
    // 初始化日期格式器
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyyMMdd"

    // 开始比较
    if formatter.string(from: startDate) == formatter.string(from: endDate) {
        print("它们是同一天")
    } else {
        print("它们不是同一天")
    }
}

2、取出日期的年、月、日分别进行比较

func isTheSameDay(startDate: Date, endDate: Date) {
    let calendar = Calendar.current
    let comp1 = calendar.dateComponents([.year,.month,.day], from: startDate)
    let comp2 = calendar.dateComponents([.year,.month,.day], from: endDate)

    //开始比较
    if comp1.year == comp2.year &&
        comp1.month == comp2.month &&
        comp1.day == comp2.day {
        print("它们是同一天")
    } else {
        print("它们不是同一天")
    }
}

3、使用Calendar的isDate方法进行判断

这个是 Swift3 新增的方法,使用方便,效率也最高

func isTheSameDay(startDate: Date, endDate: Date) {
    if Calendar.current.isDate(startDate, inSameDayAs: endDate) {
        print("它们是同一天")
    } else {
        print("它们不是同一天")
    }
}

参考

Date
DateFormatter

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容