问题
I'm trying to work out how to decide if a given timestamp occurs today, or +1 / -1 days. Essentially, I'd like to do something like this (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'
Crucially though, it needs to be in Swift and I'm struggling with the NSDate / NSCalendar objects. I started with working out the time difference like this:
let calendar = NSCalendar.currentCalendar()
let date = NSDate(timeIntervalSince1970: Double(timestamp))
let timeDifference = calendar.components([.Second,.Minute,.Day,.Hour],
fromDate: date, toDate: NSDate(), options: NSCalendarOptions())
However comparing in this way isn't easy, because the .Day
is different depending on the time of day and the timestamp. In PHP I'd just use mktime to create a new date, based on the start of the day (i.e. mktime(0,0,0)
), but I'm not sure of the easiest way to do that in Swift.
Does anybody have a good idea on how to approach this? Perhaps an extension to NSDate or something similar would be best?
回答1:
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.
回答2:
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
.
回答3:
Swift 4 update:
let calendar = Calendar.current
let date = Date()
calendar.isDateInYesterday(date)
calendar.isDateInToday(date)
calendar.isDateInTomorrow(date)
回答4:
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
回答5:
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"
回答6:
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
来源:https://stackoverflow.com/questions/39345101/swift-check-if-a-timestamp-is-yesterday-today-tomorrow-or-x-days-ago