Swift Displaying The Time or Date Based on Timestamp

Swift displaying the time or date based on timestamp

There is a handy function on NSCalendar that tells you whether an NSDate is in today or not (requires at least iOS 8) isDateInToday()

To see it working, put this into a playground:

// Create a couple of unix dates.
let timeIntervalToday: NSTimeInterval = NSDate().timeIntervalSince1970
let timeIntervalLastYear: NSTimeInterval = 1438435830

// This is just to show what the dates are.
let now = NSDate(timeIntervalSince1970: timeIntervalToday)
let then = NSDate(timeIntervalSince1970: timeIntervalLastYear)

// This is the function to show a formatted date from the timestamp
func displayTimestamp(ts: Double) -> String {
let date = NSDate(timeIntervalSince1970: ts)
let formatter = NSDateFormatter()
formatter.timeZone = NSTimeZone.systemTimeZone()

if NSCalendar.currentCalendar().isDateInToday(date) {
formatter.dateStyle = .NoStyle
formatter.timeStyle = .ShortStyle
} else {
formatter.dateStyle = .ShortStyle
formatter.timeStyle = .NoStyle
}

return formatter.stringFromDate(date)
}

// This should just show the time.
displayTimestamp(timeIntervalToday)

// This should just show the date.
displayTimestamp(timeIntervalLastYear)

Or, if you just want to see what it looks like without running it yourself:

Sample Image

How to get the current time as datetime

Update for Swift 3:

let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)

I do this:

let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: date)
let hour = components.hour
let minutes = components.minute

See the same question in objective-c How do I get hour and minutes from NSDate?

Compared to Nate’s answer, you’ll get numbers with this one, not strings… pick your choice!

iOS Swift - Get the Current Local Time and Date Timestamp

For saving Current time to firebase database I use Unic Epoch Conversation:

let timestamp = NSDate().timeIntervalSince1970

and For Decoding Unix Epoch time to Date().

let myTimeInterval = TimeInterval(timestamp)
let time = NSDate(timeIntervalSince1970: TimeInterval(myTimeInterval))

Swift display time ago from Date (NSDate)

If you just want a Time Ago extension for Date go to the bottom of the answer /p>

I'll show you an example just to get seconds ago and after I'll show your extension updated.

Note: you can use directly the date from Pase if you want:

if let pastDate = (object?["createdAt"] as? Date) {
cell.TimeAgo.text = pastDate.timeAgoDisplay()
}

Since Swift 5.1

Example how to display seconds ago with Swift 5.1:

Since iOS13 Apple introduce a new class RelativeDateTimeFormatter

extension Date {
func timeAgoDisplay() -> String {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
return formatter.localizedString(for: self, relativeTo: Date())
}
}

This class will allow you to get a time ago string based on your language. It automatically select the right unit of time based on your interval, here is an example:

|--------------------------|------------------|
| Time interval in seconds | Display |
|--------------------------|------------------|
| -6 | 6 seconds ago |
| -60 | 1 minute ago |
| -600 | 10 minutes ago |
| -6000 | 1 hour ago |
| -60000 | 16 hours ago |
|--------------------------|------------------|

You'll notice that it handle automatically plurals for you.

Swift 3 or Swift 4

Example how to get seconds ago with Swift 3 or Swift 4:

First: To get the number of seconds ago we need to check if we have one minutes or less, to get the current Date minus one minute you can write that:

let minuteAgo = calendar.date(byAdding: .minute, value: -1, to: Date())!

Second: Now compare the 2 dates! (In the case of your extension we replace yourDate by self) and get the difference between this 2 dates.

if (minuteAgo < yourDate) {
let diff = Calendar.current.dateComponents([.second], from: yourDate, to: Date()).second ?? 0
print("\(diff) sec ago")
}

That's all, now you can print the time ago !

So your extension is like this:
(This is a simple extension to get the time ago)

extension Date {
func timeAgoDisplay() -> String {

let calendar = Calendar.current
let minuteAgo = calendar.date(byAdding: .minute, value: -1, to: Date())!
let hourAgo = calendar.date(byAdding: .hour, value: -1, to: Date())!
let dayAgo = calendar.date(byAdding: .day, value: -1, to: Date())!
let weekAgo = calendar.date(byAdding: .day, value: -7, to: Date())!

if minuteAgo < self {
let diff = Calendar.current.dateComponents([.second], from: self, to: Date()).second ?? 0
return "\(diff) sec ago"
} else if hourAgo < self {
let diff = Calendar.current.dateComponents([.minute], from: self, to: Date()).minute ?? 0
return "\(diff) min ago"
} else if dayAgo < self {
let diff = Calendar.current.dateComponents([.hour], from: self, to: Date()).hour ?? 0
return "\(diff) hrs ago"
} else if weekAgo < self {
let diff = Calendar.current.dateComponents([.day], from: self, to: Date()).day ?? 0
return "\(diff) days ago"
}
let diff = Calendar.current.dateComponents([.weekOfYear], from: self, to: Date()).weekOfYear ?? 0
return "\(diff) weeks ago"
}
}

To use it, this is very straightforward:

var now = Date()
now.timeAgoDisplay()

Swift - check if a timestamp is yesterday, today, tomorrow, or X days ago

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.

How to get only time from date in swift

It seems like you want to transform a time string in one format to another format. Your method signature should look like this:

func changeFormat(str:String) -> String {

Note that you should not output a Date here, because Dates don't have formats. They will always be printed in the same way. What you need to do in this method is 2 things:

  • parse str to a Date using a DateFormatter, specifying the format HH:mm. You seem to assume that DateFormatter can automatically work this format out. It can't :(

  • format the Date object you just got using a DateFormatter, specifying the format hh:mm a. This produces a string, not a date.

(You could also consider having the method return a Date (then it would be called parseTime), and do the second step just before you show the date to the screen.)

func changeFormat(str:String) -> String {
let dateFormatter = DateFormatter()

// step 1
dateFormatter.dateFormat = "HH:mm" // input format
let date = dateFormatter.date(from: str)!

// step 2
dateFormatter.dateFormat = "hh:mm a" // output format
let string = dateFormatter.string(from: date)
return string
}

Convert Timestamp to Date with various formats Swift

As from Calendar object you can get if the date is today or yesterday.
based on that you can set String as you like.
I've created an example like you need.
below is code.

var yesterdayStr = "17-Jan-2018 10:23 AM"
var todayStr = "18-Jan-2018 10:23 AM"
var tomorrowStr = "19-Jan-2018 10:23 AM"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MMM-yyyy hh:mm a"
let yesterDaydate = dateFormatter.date(from: yesterdayStr)
let todayDate = dateFormatter.date(from: todayStr)
let tomorrowDate = dateFormatter.date(from: tomorrowStr)
let anotherDateFormatter = DateFormatter()
anotherDateFormatter.dateFormat = "hh:mm a"
if Calendar.current.isDateInYesterday(yesterDaydate!)
{
let yesterdayDisplayString = "Yesterday, " + anotherDateFormatter.string(from: yesterDaydate!)
}
if Calendar.current.isDateInToday(todayDate!) {
let todayDisplayString = "Today, " + anotherDateFormatter.string(from: todayDate!)
}
if Calendar.current.isDateInToday(tomorrowDate!) {

}
else {
let anotherDisplayString = anotherDateFormatter.string(from: tomorrowDate!)
}

and here is output,
Output of date Formatter

iOS simulator timestamp or Date() issue?

I think best practice here is that if your app is timestamp sensitive, to use a fixed and stable timestamp source which would be using Firebase Timestamp.

Locally generated dates or timestamps can be unstable and unpredictable; if the device hasn't updated to local time wherever it is, or they have that feature was turned off or maybe they just changed the time for some other reason. That can lead to inaccuracies in your data and sorting sequence.

The Real Time Database Timestamp and Timestamp has a different implementation than the Cloud Firestore one but there are a number of posts and examples here for implementing a server based timestamp.

how to check if time is within a specific range in swift

There are lots of ways to do this. Personally, I don't like working with strings if I can avoid it. I'd rather deal with date components.

Below is code that creates dates for 8:00 and 16:30, and then compares the dates to see if the current date/time falls in that range.

It's longer than other people's code, but I think it's worth learning how to do calculations with dates using a Calendar:

EDIT #3:

This answer is from a long time ago. I'll leave the old answer below, but here is the current solution:

@CodenameDuchess' answer uses a system function, date(bySettingHour:minute:second:of:matchingPolicy:repeatedTimePolicy:direction:)

Using that function, the code can be simplified to this:

import UIKit

// The function `Calendar.date(bySettingHour:minute:second)` lets you
// create date objects for a given time in the same day of given date
// For example, 8:00 today

let calendar = Calendar.current
let now = Date()
let eight_today = calendar.date(
bySettingHour: 8,
minute: 0,
second: 0,
of: now)!

let four_thirty_today = calendar.date(
bySettingHour: 16,
minute: 30,
second: 0,
of: now)!

// In recent versions of Swift Date objectst are comparable, so you can
// do greater than, less than, or equal to comparisons on dates without
// needing a date extension

if now >= eight_today &&
now <= four_thirty_today
{
print("The time is between 8:00 and 16:30")
}

The old (Swift 2) answer follows, for historical completeness:

This code uses a Calendar object to get the day/month/year of the current date, and adds the desired hour/minute components, and then generates a date for those components.

import UIKit
//-------------------------------------------------------------
//NSDate extensions.
extension NSDate
{
/**
This adds a new method dateAt to NSDate.

It returns a new date at the specified hours and minutes of the receiver

:param: hours: The hours value
:param: minutes: The new minutes

:returns: a new NSDate with the same year/month/day as the receiver, but with the specified hours/minutes values
*/
func dateAt(#hours: Int, minutes: Int) -> NSDate
{
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!

//get the month/day/year componentsfor today's date.

println("Now = \(self)")

let date_components = calendar.components(
NSCalendarUnit.CalendarUnitYear |
NSCalendarUnit.CalendarUnitMonth |
NSCalendarUnit.CalendarUnitDay,
fromDate: self)

//Create an NSDate for 8:00 AM today.
date_components.hour = hours
date_components.minute = minutes
date_components.second = 0

let newDate = calendar.dateFromComponents(date_components)!
return newDate
}
}
//-------------------------------------------------------------
//Tell the system that NSDates can be compared with ==, >, >=, <, and <= operators
extension NSDate: Equatable {}
extension NSDate: Comparable {}

//-------------------------------------------------------------
//Define the global operators for the
//Equatable and Comparable protocols for comparing NSDates

public func ==(lhs: NSDate, rhs: NSDate) -> Bool
{
return lhs.timeIntervalSince1970 == rhs.timeIntervalSince1970
}

public func <(lhs: NSDate, rhs: NSDate) -> Bool
{
return lhs.timeIntervalSince1970 < rhs.timeIntervalSince1970
}
public func >(lhs: NSDate, rhs: NSDate) -> Bool
{
return lhs.timeIntervalSince1970 > rhs.timeIntervalSince1970
}
public func <=(lhs: NSDate, rhs: NSDate) -> Bool
{
return lhs.timeIntervalSince1970 <= rhs.timeIntervalSince1970
}
public func >=(lhs: NSDate, rhs: NSDate) -> Bool
{
return lhs.timeIntervalSince1970 >= rhs.timeIntervalSince1970
}
//-------------------------------------------------------------

let now = NSDate()
let eight_today = now.dateAt(hours: 8, minutes: 0)
let four_thirty_today = now.dateAt(hours:16, minutes: 30)

if now >= eight_today &&
now <= four_thirty_today
{
println("The time is between 8:00 and 16:30")
}

EDIT:

The code in this answer has changed a LOT for Swift 3.

Instead of using NSDate, it makes more sense to us the native Date object, and Date objects are Equatable and Comparable "out of the box".

Thus we can get rid of the Equatable and Comparable extensions and the definitions for the <, > and = operators.

Then we need to do a fair amount of tweaking of the syntax in the dateAt function to follow Swift 3 syntax. The new extension looks like this in Swift 3:

Swift 3 version:

import Foundation

extension Date
{

func dateAt(hours: Int, minutes: Int) -> Date
{
let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!

//get the month/day/year componentsfor today's date.

var date_components = calendar.components(
[NSCalendar.Unit.year,
NSCalendar.Unit.month,
NSCalendar.Unit.day],
from: self)

//Create an NSDate for the specified time today.
date_components.hour = hours
date_components.minute = minutes
date_components.second = 0

let newDate = calendar.date(from: date_components)!
return newDate
}
}

let now = Date()
let eight_today = now.dateAt(hours: 8, minutes: 0)
let four_thirty_today = now.dateAt(hours: 16, minutes: 30)

if now >= eight_today &&
now <= four_thirty_today
{
print("The time is between 8:00 and 16:30")
}


Related Topics



Leave a reply



Submit