快速检查时间戳是昨天、今天、明天还是 X 天以前

我正在尝试解决如何决定一个给定的时间戳是今天发生,还是 + 1/-1天。本质上,我想做这样的事情(Pseudocode)

IF days_from_today(timestamp) == -1 RETURN 'Yesterday'
ELSE IF days_from_today(timestamp) == 0 RETURN 'Today'
ELSE IF days_from_today(timestamp) == 1 RETURN 'Tomorrow'
ELSE IF days_from_today(timestamp) < 1 RETURN days_from_today(timestamp) + ' days ago'
ELSE RETURN 'In ' + days_from_today(timestamp) + ' ago'

不过关键是,它需要在 Swift 中,而我正在努力处理 NSDate/NSCalendar 对象。我从这样计算时差开始:

let calendar = NSCalendar.currentCalendar()
let date = NSDate(timeIntervalSince1970: Double(timestamp))
let timeDifference = calendar.components([.Second,.Minute,.Day,.Hour],
fromDate: date, toDate: NSDate(), options: NSCalendarOptions())

然而,用这种方法进行比较并不容易,因为 .Day根据一天中的时间和时间戳的不同而不同。在 PHP 中,我只是使用 mktime 根据一天的开始创建一个新的日期(即 mktime(0,0,0)) ,但我不确定在 Swift 中是否有最简单的方法来实现这一点。

有人知道该怎么做吗?也许扩展 NSDate 或类似的东西是最好的?

67660 次浏览

NSCalender has new methods that you can use directly.

NSCalendar.currentCalendar().isDateInTomorrow(NSDate())//Replace NSDate() with your date
NSCalendar.currentCalendar().isDateInYesterday()
NSCalendar.currentCalendar().isDateInTomorrow()

Hope this helps

Calendar has methods for all three cases

func isDateInYesterday(_ date: Date) -> Bool
func isDateInToday(_ date: Date) -> Bool
func isDateInTomorrow(_ date: Date) -> Bool

To calculate the days earlier than yesterday use

func dateComponents(_ components: Set<Calendar.Component>,
from start: Date,
to end: Date) -> DateComponents

pass [.day] to components and get the day property from the result.


This is a function which considers also is in for earlier and later dates by stripping the time part (Swift 3+).

func dayDifference(from interval : TimeInterval) -> String
{
let calendar = Calendar.current
let date = Date(timeIntervalSince1970: interval)
if calendar.isDateInYesterday(date) { return "Yesterday" }
else if calendar.isDateInToday(date) { return "Today" }
else if calendar.isDateInTomorrow(date) { return "Tomorrow" }
else {
let startOfNow = calendar.startOfDay(for: Date())
let startOfTimeStamp = calendar.startOfDay(for: date)
let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
let day = components.day!
if day < 1 { return "\(-day) days ago" }
else { return "In \(day) days" }
}
}

Alternatively you could use DateFormatter for Yesterday, Today and Tomorrow to get localized strings for free

func dayDifference(from interval : TimeInterval) -> String
{
let calendar = Calendar.current
let date = Date(timeIntervalSince1970: interval)
let startOfNow = calendar.startOfDay(for: Date())
let startOfTimeStamp = calendar.startOfDay(for: date)
let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
let day = components.day!
if abs(day) < 2 {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
formatter.doesRelativeDateFormatting = true
return formatter.string(from: date)
} else if day > 1 {
return "In \(day) days"
} else {
return "\(-day) days ago"
}
}

Update:

In macOS 10.15 / iOS 13 RelativeDateTimeFormatter was introduced to return (localized) strings relative to a specific date.

Swift 3/4/5:

Calendar.current.isDateInToday(yourDate)
Calendar.current.isDateInYesterday(yourDate)
Calendar.current.isDateInTomorrow(yourDate)

Additionally:

Calendar.current.isDateInWeekend(yourDate)

Note that for some countries weekend may be different than Saturday-Sunday, it depends on the calendar.

You can also use autoupdatingCurrent instead of current calendar, which will track user updates. You use it the same way:

Calendar.autoupdatingCurrent.isDateInToday(yourDate)

Calendar is a type alias for the NSCalendar.

Swift 4 update:

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

calendar.isDateInYesterday(date)
calendar.isDateInToday(date)
calendar.isDateInTomorrow(date)

1)According to your example you want to receive labels "Yesterday", "Today" and etc. iOS can do this by default:

https://developer.apple.com/documentation/foundation/nsdateformatter/1415848-doesrelativedateformatting?language=objc

2)If you want to compute your custom label when iOS don't add these labels by itself then alternatively you can use 2 DateFormatter objects with both doesRelativeDateFormatting == true and doesRelativeDateFormatting == false and compare if their result date strings are the same or different

On Swift 5 and iOS 13 use the RelativeDateTimeFormatter,

let formatter = RelativeDateTimeFormatter()
formatter.dateTimeStyle = .named


formatter.localizedString(from: DateComponents(day: -1)) // "yesterday"
formatter.localizedString(from: DateComponents(day: 1)) // "Tomorrow"
formatter.localizedString(from: DateComponents(hour: 2)) // "in 2 hours"
formatter.localizedString(from: DateComponents(minute: 45)) // "in 45 minutes"