// // Date+Extension.swift // QuickSearchLocation // // Created by Destiny on 2024/4/15. // import Foundation public enum TimestampType: Int { /// 秒 case second /// 毫秒 case millisecond } public extension Date { // MARK: 1.1、获取当前 秒级 时间戳 - 10 位 /// 获取当前 秒级 时间戳 - 10 位 static var secondStamp : String { let timeInterval: TimeInterval = Date().timeIntervalSince1970 return "\(Int(timeInterval))" } // MARK: 1.2、获取当前 毫秒级 时间戳 - 13 位 /// 获取当前 毫秒级 时间戳 - 13 位 static var milliStamp : String { let timeInterval: TimeInterval = Date().timeIntervalSince1970 let millisecond = CLongLong(round(timeInterval*1000)) return "\(millisecond)" } // MARK: 1.3、获取当前的时间 Date /// 获取当前的时间 Date static var currentDate : Date { return Date() } // MARK: 1.4、从 Date 获取年份 /// 从 Date 获取年份 var year: Int { return Calendar.current.component(Calendar.Component.year, from: self) } // MARK: 1.5、从 Date 获取月份 /// 从 Date 获取年份 var month: Int { return Calendar.current.component(Calendar.Component.month, from: self) } // MARK: 1.6、从 Date 获取 日 /// 从 Date 获取 日 var day: Int { return Calendar.current.component(.day, from: self) } // MARK: 1.7、从 Date 获取 小时 /// 从 Date 获取 日 var hour: Int { return Calendar.current.component(.hour, from: self) } // MARK: 1.8、从 Date 获取 分钟 /// 从 Date 获取 分钟 var minute: Int { return Calendar.current.component(.minute, from: self) } // MARK: 1.9、从 Date 获取 秒 /// 从 Date 获取 秒 var second: Int { return Calendar.current.component(.second, from: self) } // MARK: 1.10、从 Date 获取 毫秒 /// 从 Date 获取 毫秒 var nanosecond: Int { return Calendar.current.component(.nanosecond, from: self) } // MARK: 1.11、从日期获取 星期(英文) /// 从日期获取 星期 var weekday: String { qsl_formatter.dateFormat = "EEEE" return qsl_formatter.string(from: self) } // MARK: 1.12、从日期获取 星期(中文) var weekdayStringFromDate: String { let weekdays = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"] var calendar = Calendar(identifier: .gregorian) let timeZone = TimeZone(identifier: "Asia/Shanghai") calendar.timeZone = timeZone! let theComponents = calendar.dateComponents([.weekday], from: self as Date) return weekdays[theComponents.weekday! - 1] } // 现在日期的格式化形式 var formateCurrentDate: String { qsl_formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" return qsl_formatter.string(from: Date()) } // MARK: 1.13、从日期获取 月(英文) /// 从日期获取 月(英文) var monthAsString: String { qsl_formatter.dateFormat = "MM" return qsl_formatter.string(from: self) } } //MARK: - 二、时间格式的转换 // MARK: 时间条的显示格式 public enum JKTimeBarType { // 默认格式,如 9秒:09,66秒:01:06, case normal case second case minute case hour } public extension Date { // MARK: 2.1、时间戳(支持10位和13位)按照对应的格式 转化为 对应时间的字符串 /// 时间戳(支持10位和13位)按照对应的格式 转化为 对应时间的字符串 如:1603849053 按照 "yyyy-MM-dd HH:mm:ss" 转化后为:2020-10-28 09:37:33 /// - Parameters: /// - timestamp: 时间戳 /// - format: 格式 /// - Returns: 对应时间的字符串 static func timestampToFormatterTimeString(timestamp: String, format: String = "yyyy-MM-dd HH:mm:ss") -> String { // 时间戳转为Date let date = timestampToFormatterDate(timestamp: timestamp) // let dateFormatter = DateFormatter() // 设置 dateFormat qsl_formatter.dateFormat = format // 按照dateFormat把Date转化为String return qsl_formatter.string(from: date) } // MARK: 2.2、时间戳(支持 10 位 和 13 位) 转 Date /// 时间戳(支持 10 位 和 13 位) 转 Date /// - Parameter timestamp: 时间戳 /// - Returns: 返回 Date static func timestampToFormatterDate(timestamp: String) -> Date { guard timestamp.count == 10 || timestamp.count == 13 else { #if DEBUG fatalError("时间戳位数不是 10 也不是 13") #else return Date() #endif } guard let timestampInt = Int(timestamp) else { #if DEBUG fatalError("时间戳位有问题") #else return Date() #endif } let timestampValue = timestamp.count == 10 ? timestampInt : timestampInt / 1000 // 时间戳转为Date let date = Date(timeIntervalSince1970: TimeInterval(timestampValue)) return date } /// 根据本地时区转换 private static func getNowDateFromatAnDate(_ anyDate: Date?) -> Date? { // 设置源日期时区 let sourceTimeZone = NSTimeZone(abbreviation: "UTC") // 或GMT // 设置转换后的目标日期时区 let destinationTimeZone = NSTimeZone.local as NSTimeZone // 得到源日期与世界标准时间的偏移量 var sourceGMTOffset: Int? = nil if let aDate = anyDate { sourceGMTOffset = sourceTimeZone?.secondsFromGMT(for: aDate) } // 目标日期与本地时区的偏移量 var destinationGMTOffset: Int? = nil if let aDate = anyDate { destinationGMTOffset = destinationTimeZone.secondsFromGMT(for: aDate) } // 得到时间偏移量的差值 let interval = TimeInterval((destinationGMTOffset ?? 0) - (sourceGMTOffset ?? 0)) // 转为现在时间 var destinationDateNow: Date? = nil if let aDate = anyDate { destinationDateNow = Date(timeInterval: interval, since: aDate) } return destinationDateNow } // MARK: 2.3、Date 转换为相应格式的时间字符串,如 Date 转为 2020-10-28 /// Date 转换为相应格式的字符串,如 Date 转为 2020-10-28 /// - Parameter format: 转换的格式 /// - Returns: 返回具体的字符串 func toformatterTimeString(formatter: String = "yyyy-MM-dd HH:mm:ss") -> String { // let dateFormatter = DateFormatter() qsl_formatter.timeZone = TimeZone.autoupdatingCurrent qsl_formatter.dateFormat = formatter return qsl_formatter.string(from: self) } // MARK: 2.4、带格式的时间转 时间戳,支持返回 13位 和 10位的时间戳,时间字符串和时间格式必须保持一致 /// 带格式的时间转 时间戳,支持返回 13位 和 10位的时间戳,时间字符串和时间格式必须保持一致 /// - Parameters: /// - timeString: 时间字符串,如:2020-10-26 16:52:41 /// - formatter: 时间格式,如:yyyy-MM-dd HH:mm:ss /// - timestampType: 返回的时间戳类型,默认是秒 10 为的时间戳字符串 /// - Returns: 返回转化后的时间戳 static func formatterTimeStringToTimestamp(timesString: String, formatter: String, timestampType: TimestampType = .second) -> String { qsl_formatter.dateFormat = formatter qsl_formatter.locale = NSLocale.system guard let date = qsl_formatter.date(from: timesString) else { #if DEBUG fatalError("日期格式不匹配") #else return "" #endif } if timestampType == .second { return "\(Int(date.timeIntervalSince1970))" } return "\(Int((date.timeIntervalSince1970) * 1000))" } // MARK: 2.5、带格式的时间转 Date /// 带格式的时间转 Date /// - Parameters: /// - timesString: 时间字符串 /// - formatter: 格式 /// - Returns: 返回 Date static func formatterTimeStringToDate(timesString: String, formatter: String) -> Date { qsl_formatter.dateFormat = formatter qsl_formatter.locale = NSLocale.system guard let date = qsl_formatter.date(from: timesString) else { #if DEBUG fatalError("时间有问题") #else return Date() #endif } /* guard let resultDate = getNowDateFromatAnDate(date) else { return Date() } */ return date } // MARK: 2.6、秒转换成播放时间条的格式 /// 秒转换成播放时间条的格式 /// - Parameters: /// - secounds: 秒数 /// - type: 格式类型 /// - Returns: 返回时间条 static func getFormatPlayTime(seconds: Int, type: JKTimeBarType = .normal) -> String { if seconds <= 0{ return "00:00" } // 秒 let second = seconds % 60 if type == .second { return String(format: "%02d", seconds) } // 分钟 var minute = Int(seconds / 60) if type == .minute { return String(format: "%02d:%02d", minute, second) } // 小时 var hour = 0 if minute >= 60 { hour = Int(minute / 60) minute = minute - hour * 60 } if type == .hour { return String(format: "%02d:%02d:%02d", hour, minute, second) } // normal 类型 if hour > 0 { return String(format: "%02d:%02d:%02d", hour, minute, second) } if minute > 0 { return String(format: "%02d:%02d", minute, second) } return String(format: "%02d", second) } // MARK: 2.7、Date 转 时间戳 /// Date 转 时间戳 /// - Parameter timestampType: 返回的时间戳类型,默认是秒 10 为的时间戳字符串 /// - Returns: 时间戳 func dateToTimeStamp(timestampType: TimestampType = .second) -> String { // 10位数时间戳 和 13位数时间戳 let interval = timestampType == .second ? CLongLong(Int(self.timeIntervalSince1970)) : CLongLong(round(self.timeIntervalSince1970 * 1000)) return "\(interval)" } // 转成当前时区的日期 func dateFromGMT() -> Date { let secondFromGMT: TimeInterval = TimeInterval(TimeZone.current.secondsFromGMT(for: self)) return self.addingTimeInterval(secondFromGMT) } } // MARK: - 三、本地化时间格式的转换(在日期及其文本表示形式之间进行转换的格式化) public extension Date { //MARK: 3.1、date使用DateFormatter.Style的形式格式化(传本地化字符串) /// date使用DateFormatter.Style的形式格式化(传本地化字符串) /// - Parameters: /// - localIdentifier: 本地化语言字符串 /// - formatter: 格式 /// - dateStyle: 日期格式 /// - timeStyle: 时间格式 /// - timeZone: 时区 /// - Returns: 返回对应的格式化后的时间 /// /// - Note:在向用户显示日期时,可以根据您的具体需要设置 date formatter 的dateStyle和timeStyle属性。例如,如果您想要显示月份、日期和年份而不显示时间,则可以将dateStyle属性设置为DateFormatter.Style.long 并且将timeStyle属性设置为DateFormatter. Style.none 。相反,如果您只想显示时间,您可以将dateStyle属性设置为DateFormatter.Style.none 并且将timeStyle属性设置为DateFormatter.Style.short。DateFormatter根据dateStyle和timeStyle属性的值,提供适合于给定语言环境的指定日期的表示 func toLocalDateFormatterStyleString(localIdentifier: String = "zh_CN" , formatter: String = "yyyyMMMd", dateStyle: DateFormatter.Style = .short, timeStyle: DateFormatter.Style = .none, timeZone: TimeZone = TimeZone.autoupdatingCurrent) -> String { return toLocalDateFormatterStyleString(locale: Locale(identifier: localIdentifier), formatter: formatter, dateStyle: dateStyle, timeStyle: timeStyle, timeZone: timeZone) } //MARK: 3.2、date使用DateFormatter.Style的形式格式化(传本地化Locale对象) /// date使用DateFormatter.Style的形式格式化(传Locale对象) /// - Parameters: /// - locale: 本地化Locale对象 /// - formatter: 格式 /// - dateStyle: 日期格式 /// - timeStyle: 时间格式 /// - timeZone: 时区 /// - Returns: 返回对应的格式化后的时间 func toLocalDateFormatterStyleString(locale: Locale = Locale.current, formatter: String = "yyyyMMMd", dateStyle: DateFormatter.Style = .short, timeStyle: DateFormatter.Style = .none, timeZone: TimeZone = TimeZone.autoupdatingCurrent) -> String { let dateFormatter = DateFormatter() dateFormatter.timeZone = timeZone dateFormatter.dateStyle = .short dateFormatter.timeStyle = timeStyle dateFormatter.setLocalizedDateFormatFromTemplate(formatter) dateFormatter.locale = locale return dateFormatter.string(from: self) } //MARK: 3.3、date使用locale和formatter的形式格式化(传本地化字符串) /// date使用locale和formatter的形式格式化(传本地化字符串) /// - Parameters: /// - localIdentifier: 本地化语言字符串 /// - formatter: 格式 /// - timeZone: 时区 /// - Returns: 返回对应的格式化后的时间 func toFormatterLocalTimeString(localIdentifier: String = "zh_CN", formatter: String = "yyyyMMMd", timeZone: TimeZone = TimeZone.autoupdatingCurrent) -> String { return toformatterLocalTimeString(locale: Locale(identifier: localIdentifier), formatter: formatter, timeZone: timeZone) } //MARK: 3.4、date使用locale和formatter的形式格式化(传本地化Locale对象) /// date使用locale和formatter的形式格式化(传本地化Locale对象) /// - Parameters: /// - locale: 本地化Locale对象 /// - formatter: 格式 /// - timeZone: 时区 /// - Returns: 返回对应的格式化后的时间 func toformatterLocalTimeString(locale: Locale = Locale.current, formatter: String = "yyyyMMMd", timeZone: TimeZone = TimeZone.autoupdatingCurrent) -> String { let dateFormatter = DateFormatter() dateFormatter.timeZone = timeZone dateFormatter.setLocalizedDateFormatFromTemplate(formatter) dateFormatter.locale = locale return dateFormatter.string(from: self) } } // MARK: - 四、前天、昨天、今天、明天、后天、是否同一年同一月同一天 的判断 public extension Date { // MARK: 4.1、今天的日期 /// 今天的日期 static var todayDate: Date { return Date() } // MARK: 4.2、昨天的日期(相对于date的昨天日期) /// 昨天的日期 static var yesterDayDate: Date? { return Calendar.current.date(byAdding: DateComponents(day: -1), to: Date()) } // MARK: 4.3、明天的日期 /// 明天的日期 static var tomorrowDate: Date? { return Calendar.current.date(byAdding: DateComponents(day: 1), to: Date()) } // MARK: 4.4、前天的日期 /// 前天的日期 static var theDayBeforYesterDayDate: Date? { return Calendar.current.date(byAdding: DateComponents(day: -2), to: Date()) } // MARK: 4.5、后天的日期 /// 后天的日期 static var theDayAfterYesterDayDate: Date? { return Calendar.current.date(byAdding: DateComponents(day: 2), to: Date()) } // MARK: 4.6、是否为今天(只比较日期,不比较时分秒) /// 是否为今天(只比较日期,不比较时分秒) /// - Returns: bool var isToday: Bool { return Calendar.current.isDate(self, inSameDayAs: Date()) } // MARK: 4.7、是否为昨天 /// 是否为昨天 var isYesterday: Bool { // 1.先拿到昨天的 date guard let date = Date.yesterDayDate else { return false } // 2.比较当前的日期和昨天的日期 return Calendar.current.isDate(self, inSameDayAs: date) } // MARK: 4.8、是否为前天 /// 是否为前天 var isTheDayBeforeYesterday: Bool { // 1.先拿到前天的 date guard let date = Date.theDayBeforYesterDayDate else { return false } // 2.比较当前的日期和昨天的日期 return Calendar.current.isDate(self, inSameDayAs: date) } // MARK: 4.9、是否为今年 /// 是否为今年 var isThisYear: Bool { let calendar = Calendar.current let nowCmps = calendar.dateComponents([.year], from: Date()) let selfCmps = calendar.dateComponents([.year], from: self) let result = nowCmps.year == selfCmps.year return result } // MARK: 4.10、两个date是否为同一天 /// 是否为 同一年 同一月 同一天 /// - Returns: bool func isSameDay(date: Date) -> Bool { return Calendar.current.isDate(self, inSameDayAs: date) } // MARK: 4.11、当前日期是不是润年 /// 当前日期是不是润年 var isLeapYear: Bool { let year = self.year return ((year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0))) } /// 日期的加减操作 /// - Parameter day: 天数变化 /// - Returns: date private func adding(day: Int) -> Date? { return Calendar.current.date(byAdding: DateComponents(day:day), to: self) } /// 是否为 同一年 同一月 同一天 /// - Parameter date: date /// - Returns: 返回bool private func isSameYeaerMountDay(_ date: Date) -> Bool { let com = Calendar.current.dateComponents([.year, .month, .day], from: self) let comToday = Calendar.current.dateComponents([.year, .month, .day], from: date) return (com.day == comToday.day && com.month == comToday.month && com.year == comToday.year ) } // MARK: 4.12、是否为本周 /// 是否为本周 /// - Returns: 是否为本周 var isThisWeek: Bool { let calendar = Calendar.current // 当前时间 let nowComponents = calendar.dateComponents([.weekday, .month, .year], from: Date()) // self let selfComponents = calendar.dateComponents([.weekday,.month,.year], from: self as Date) return (selfComponents.year == nowComponents.year) && (selfComponents.month == nowComponents.month) && (selfComponents.weekday == nowComponents.weekday) } // MARK: 4.13、是否为12小时制 /// 是否为12小时制 /// - Returns: true:12小时,否则24小时 static var isTwelve: Bool { var isTwelve: Bool = false if let formatString = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: Locale.current), formatString.contains("a") { // 12 小时制 isTwelve = true } else { // 24 小时制 isTwelve = false } return isTwelve } } // MARK: - 五、相对的时间变化 public extension Date { // MARK: 5.1、取得与当前时间的间隔差 /// 取得与当前时间的间隔差 /// - Returns: 时间差 func callTimeAfterNow() -> String { let timeInterval = Date().timeIntervalSince(self) if timeInterval < 0 { return "刚刚" } let interval = fabs(timeInterval) let i60 = interval / 60 let i3600 = interval / 3600 let i86400 = interval / 86400 let i2592000 = interval / 2592000 let i31104000 = interval / 31104000 var time:String! if i3600 < 1 { let s = NSNumber(value: i60 as Double).intValue if s == 0 { time = "刚刚" } else { time = "\(s)分钟前" } } else if i86400 < 1 { let s = NSNumber(value: i3600 as Double).intValue time = "\(s)小时前" } else if i2592000 < 1 { let s = NSNumber(value: i86400 as Double).intValue time = "\(s)天前" } else if i31104000 < 1 { let s = NSNumber(value: i2592000 as Double).intValue time = "\(s)个月前" } else { let s = NSNumber(value: i31104000 as Double).intValue time = "\(s)年前" } return time } // MARK: 5.2、获取两个日期之间的数据 /// 获取两个日期之间的数据 /// - Parameters: /// - date: 对比的日期 /// - unit: 对比的类型 /// - Returns: 两个日期之间的数据 func componentCompare(from date: Date, unit: Set = [.year, .month, .day, .hour, .minute]) -> DateComponents { let calendar = Calendar.current let component = calendar.dateComponents(unit, from: date, to: self) return component } // MARK: 5.3、获取两个日期之间的天数 /// 获取两个日期之间的天数 /// - Parameter date: 对比的日期 /// - Returns: 两个日期之间的天数 func numberOfDays(from date: Date) -> Int? { return componentCompare(from: date, unit: [.day]).day } // MARK: 5.4、获取两个日期之间的小时 /// 获取两个日期之间的小时 /// - Parameter date: 对比的日期 /// - Returns: 两个日期之间的小时 func numberOfHours(from date: Date) -> Int? { return componentCompare(from: date, unit: [.hour]).hour } // MARK: 5.5、获取两个日期之间的分钟 /// 获取两个日期之间的分钟 /// - Parameter date: 对比的日期 /// - Returns: 两个日期之间的分钟 func numberOfMinutes(from date: Date) -> Int? { return componentCompare(from: date, unit: [.minute]).minute } // MARK: 5.6、获取两个日期之间的秒数 /// 获取两个日期之间的秒数 /// - Parameter date: 对比的日期 /// - Returns: 两个日期之间的秒数 func numberOfSeconds(from date: Date) -> Int? { return componentCompare(from: date, unit: [.second]).second } } // MARK: - 六、年/月/日 的一些判断 public extension Date { // MARK: 6.1、获取当前的年 /// 获取当前的年 static var currentYear : Int { return currentDate.year } // MARK: 6.2、今年是不是闰年 /// 1.16、今年是不是闰年 static var currentYearIsLeapYear: Bool { return todayDate.isLeapYear } // MARK: 6.3、某年是不是闰年 /// 6.3、某年是不是闰年 static func yearIsLeapYear(year: Int) -> Bool { return ((year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0))) } // MARK: 6.4、当前的月份 /// 当前的月份 static var currentMonth: Int { return currentDate.month } // MARK: 6.5、获取当前月的天数 /// 获取当前月的天数 /// - Returns: 返回天数 static var currentMonthDays: Int { return monthOfDays(month: currentMonth) } // MARK: 6.6、获取当前某月的天数 /// 获取当前某月的天数 /// - Returns: 返回天数 static func monthOfDays(month: Int) -> Int { switch month { case 1, 3, 5, 7, 8, 10, 12: return 31 case 4, 6, 9, 11: return 30 case 2: return currentYearIsLeapYear ? 29 : 28 default: fatalError("非法的月份:\(month)") } } }