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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容