How to get 1 hour ago from a date in iOS swift?

40,473

Solution 1

For correct calculations involving NSDate that take into account all edge cases of different calendars (e.g. switching between day saving time) you should use NSCalendar class:

Swift 3+

let earlyDate = Calendar.current.date(
  byAdding: .hour, 
  value: -1, 
  to: Date())

Older

// Get the date that was 1hr before now
let earlyDate = NSCalendar.currentCalendar().dateByAddingUnit(
       .Hour,
       value: -1, 
       toDate: NSDate(),
       options: [])

Solution 2

Use this method and paste in your helper class.

Updated for Swift 3 and Xcode 8.3

class func timeAgoSinceDate(_ date:Date,currentDate:Date, numericDates:Bool) -> String {
    let calendar = Calendar.current
    let now = currentDate
    let earliest = (now as NSDate).earlierDate(date)
    let latest = (earliest == now) ? date : now
    let components:DateComponents = (calendar as NSCalendar).components([NSCalendar.Unit.minute , NSCalendar.Unit.hour , NSCalendar.Unit.day , NSCalendar.Unit.weekOfYear , NSCalendar.Unit.month , NSCalendar.Unit.year , NSCalendar.Unit.second], from: earliest, to: latest, options: NSCalendar.Options())
    
    if (components.year! >= 2) {
        return "\(components.year!) years ago"
    } else if (components.year! >= 1){
        if (numericDates){
            return "1 year ago"
        } else {
            return "Last year"
        }
    } else if (components.month! >= 2) {
        return "\(components.month!) months ago"
    } else if (components.month! >= 1){
        if (numericDates){
            return "1 month ago"
        } else {
            return "Last month"
        }
    } else if (components.weekOfYear! >= 2) {
        return "\(components.weekOfYear!) weeks ago"
    } else if (components.weekOfYear! >= 1){
        if (numericDates){
            return "1 week ago"
        } else {
            return "Last week"
        }
    } else if (components.day! >= 2) {
        return "\(components.day!) days ago"
    } else if (components.day! >= 1){
        if (numericDates){
            return "1 day ago"
        } else {
            return "Yesterday"
        }
    } else if (components.hour! >= 2) {
        return "\(components.hour!) hours ago"
    } else if (components.hour! >= 1){
        if (numericDates){
            return "1 hour ago"
        } else {
            return "An hour ago"
        }
    } else if (components.minute! >= 2) {
        return "\(components.minute!) minutes ago"
    } else if (components.minute! >= 1){
        if (numericDates){
            return "1 minute ago"
        } else {
            return "A minute ago"
        }
    } else if (components.second! >= 3) {
        return "\(components.second!) seconds ago"
    } else {
        return "Just now"
    }
    
}

Use of this method:

var timeAgo:String=AppHelper.timeAgoSinceDate(date, numericDates: true)
Print("\(timeAgo)")   // Ex- 1 hour ago

Solution 3

Please read the NSDate class reference.

let oneHourAgo = NSDate.dateWithTimeIntervalSinceNow(-3600)

should do it.

Or, for any NSDate object:

let oneHourBack = myDate.dateByAddingTimeInterval(-3600)

Swift 4:

let oneHourAgo = NSDate(timeIntervalSinceNow: -3600)

Solution 4

According to your needs, you may choose one of the 3 following Swift 5 methods to get one hour ago from a Date instance.


1. date(byAdding:value:to:wrappingComponents:)

Calendar has a method called date(byAdding:value:to:wrappingComponents:). date(byAdding:value:to:wrappingComponents:) has the following declaration:

func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool = default) -> Date?

Returns a new Date representing the date calculated by adding an amount of a specific component to a given date.

The Playground code below shows how to use it:

import Foundation

let now = Date()
let oneHourAgo = Calendar.current.date(byAdding: .hour, value: -1, to: now)

print(now) // 2016-12-19 21:52:04 +0000
print(String(describing: oneHourAgo)) // Optional(2016-12-19 20:52:04 +0000)

2. date(byAdding:to:wrappingComponents:)

Calendar has a method called date(byAdding:to:wrappingComponents:). date(byAdding:value:to:wrappingComponents:) has the following declaration:

func date(byAdding components: DateComponents, to date: Date, wrappingComponents: Bool = default) -> Date?

Returns a new Date representing the date calculated by adding components to a given date.

The Playground code below shows how to use it:

import Foundation

let now = Date()

var components = DateComponents()
components.hour = -1
let oneHourAgo = Calendar.current.date(byAdding: components, to: now)

print(now) // 2016-12-19 21:52:04 +0000
print(String(describing: oneHourAgo)) // Optional(2016-12-19 20:52:04 +0000)

Alternative:

import Foundation

// Get the date that was 1hr before now
let now = Date()

let components = DateComponents(hour: -1)
let oneHourAgo = Calendar.current.date(byAdding: components, to: now)

print(now) // 2016-12-19 21:52:04 +0000
print(String(describing: oneHourAgo)) // Optional(2016-12-19 20:52:04 +0000)

3. addingTimeInterval(_:) (use with caution)

Date has a method called addingTimeInterval(_:). addingTimeInterval(_:) has the following declaration:

func addingTimeInterval(_ timeInterval: TimeInterval) -> Date

Return a new Date by adding a TimeInterval to this Date.

Note that this method comes with a warning:

This only adjusts an absolute value. If you wish to add calendrical concepts like hours, days, months then you must use a Calendar. That will take into account complexities like daylight saving time, months with different numbers of days, and more.

The Playground code below shows how to use it:

import Foundation

let now = Date()
let oneHourAgo = now.addingTimeInterval(-3600)

print(now) // 2016-12-19 21:52:04 +0000
print(oneHourAgo) // 2016-12-19 20:52:04 +0000

Solution 5

If you are using NSDate you can do:

let date = NSDate()
date.dateByAddingTimeInterval(-3600)

It will change the date object to be "1 hour ago".

Share:
40,473
saksut
Author by

saksut

Updated on February 25, 2021

Comments

  • saksut
    saksut over 3 years

    I have been researching, but I couldnt find exact solution for my problem. I have been trying to get 1 hour ago from a date. How can I achieve this in swift?

  • saksut
    saksut over 9 years
    Thank you for your answers. The problem disappeared :)
  • William Entriken
    William Entriken over 8 years
    New syntax for the former is: NSDate(timeIntervalSinceNow: -3600)
  • Van Du Tran
    Van Du Tran over 8 years
    What is WrapComponents for?
  • Steve
    Steve over 8 years
    Thanks a lot, really useful !
  • AamirR
    AamirR over 8 years
    very useful answer !
  • vikzilla
    vikzilla over 8 years
    Here it is as an extension of the NSDate class: gist.github.com/vikdenic/988d6f3920b7b7950d40
  • Robert Chen
    Robert Chen about 8 years
    .WrapComponents means don't increment the day if adding an hour pushes you past midnight. I think it makes more sense to use options: [], like Deepak's answer at the bottom of the thread.
  • Chris Allinson
    Chris Allinson over 7 years
    For Swift3 ... let alteredDate = userCalendar.date(byAdding: .hour, value: -1, to: now)
  • Duncan C
    Duncan C over 5 years
    Option one, date(byAdding:value:to:wrappingComponents:) seems like the best/simplest fit. It lets you add a single date component value to a date.
  • vadian
    vadian over 5 years
    Suggestions for real Swift 3(+) to get rid of NS... classes: let earliest = min(now, date)let latest = max(now, date)let components = calendar.dateComponents([.minute , .hour , .day , .weekOfYear , .month , .year , .second], from: earliest, to: latest)
  • WaitingForGuacamole
    WaitingForGuacamole over 3 years
    Please consider formatting your relevant parts of your answer as code.
  • buzatto
    buzatto over 3 years
    it does not look any improvement on the other answers provided previously
  • Nilu Sahani
    Nilu Sahani about 3 years
    Thank u so much.... :) this function really very useful for me