81

How To Add Month To NSDate Object?

NSDate *someDate = [NSDate Date] + 30Days.....;
Larme
  • 24,190
  • 6
  • 51
  • 81
orthehelper
  • 4,009
  • 10
  • 40
  • 67

9 Answers9

140

You need to use NSDateComponents:

NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setMonth:1];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *newDate = [calendar dateByAddingComponents:dateComponents toDate:originalDate options:0];
[dateComponents release]; // If ARC is not used, release the date components
Sam Spencer
  • 8,492
  • 12
  • 76
  • 133
TheEye
  • 9,280
  • 2
  • 42
  • 58
  • do you know how can i compare between now to the destiny date? to check if i pass this date? – orthehelper Nov 14 '11 at 10:32
  • 1
    Date comparisons are done with the NSDate functions compare, earlierDate and laterDate - see the NSDate documentation for that: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html – TheEye Nov 14 '11 at 10:41
  • 1
    @orazran you can compare dates with: `[date timeIntervalSinceDate:otherDate]`, which will return the difference between them in seconds (less than 0 for past dates, greater than 0 for future dates). – Abhi Beckert Nov 14 '11 at 10:53
130

With iOS 8 and OS X 10.9 you can add NSCalendarUnits using NSCalendar:

Objective-C

NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *someDate = [cal dateByAddingUnit:NSCalendarUnitMonth value:1 toDate:[NSDate date] options:0];

Swift 3

let date = Calendar.current.date(byAdding: .month, value: 1, to: Date())

Swift 2

let cal = NSCalendar.currentCalendar()
let date = cal.dateByAddingUnit(.Month, value: 1, toDate: NSDate(), options: [])
Kevin
  • 16,696
  • 7
  • 51
  • 68
24

For swift 3.0

extension Date {
    func addMonth(n: Int) -> Date {
        let cal = NSCalendar.current
        return cal.date(byAdding: .month, value: n, to: self)!
    }
    func addDay(n: Int) -> Date {
        let cal = NSCalendar.current
        return cal.date(byAdding: .day, value: n, to: self)!
    }
    func addSec(n: Int) -> Date {
        let cal = NSCalendar.current
        return cal.date(byAdding: .second, value: n, to: self)!
    }
}
Soohwan Park
  • 625
  • 4
  • 11
14

For example, to add 3 months to the current date in Swift:

let date = NSCalendar.currentCalendar().dateByAddingUnit(.MonthCalendarUnit, value: 3, toDate: NSDate(), options: nil)!

In Swift 2.0:

let date = NSCalendar.currentCalendar().dateByAddingUnit(.Month, value: 3, toDate: NSDate(), options: [])
  • The new OptionSetType structure of NSCalendarUnit lets you more simply specify .Month
  • Parameters that take OptionSetType (like the options: parameter, which takes NSCalendarOptions) can't be nil, so pass in an empty set ([]) to represent "no options".
Community
  • 1
  • 1
Aaron Brager
  • 65,323
  • 19
  • 161
  • 287
3

In Swift 2.0

    let startDate = NSDate()
    let dateComponent = NSDateComponents()
    dateComponent.month = 1
    let cal = NSCalendar.currentCalendar()
    let endDate = cal.dateByAddingComponents(dateComponent, toDate: startDate, options: NSCalendarOptions(rawValue: 0))
RiceAndBytes
  • 1,286
  • 10
  • 21
2

FOR SWIFT 3.0

here is function , you can reduce days , month ,day by any count like for example here , i have reduced the current system date's year by 100 year , you can do it for day , month also just set the counter and then store the values in array , and do whatever you want to do with that array

func currentTime(){

    let date = Date()
    let calendar = Calendar.current
    var year = calendar.component(.year, from: date)
    let month = calendar.component(.month, from: date)
    let  day = calendar.component(.day, from: date)
    let pastyear = year - 100
    var someInts = [Int]()
    printLog(msg: "\(day):\(month):\(year)" )

    for _ in pastyear...year        {
        year -= 1
                     print("\(year) ")
        someInts.append(year)
    }

    print(someInts)
}
RPichioli
  • 3,245
  • 2
  • 25
  • 29
1

Other answers work fine if your desired behaviour is adding a month and allowing for daylight savings time. This produces results such that:

01/03/2017 00:00 + 1 month -> 31/03/2017 23:00
01/10/2017 00:00 + 1 month -> 01/11/2017 01:00

However I wanted to ignore the hour lost or gained by DST, such that:

01/03/2017 00:00 + 1 month -> 01/04/2017 00:00
01/10/2017 00:00 + 1 month -> 01/11/2017 00:00

So I check if a DST boundary is passed, and if so either add or subtract an hour accordingly:

func offsetDaylightSavingsTime() -> Date {
        // daylightSavingTimeOffset is either + 1hr or + 0hr. To offset DST for a given date, we need to add an hour or subtract an hour
        // +1hr -> +1hr
        // +0hr -> -1hr
        // offset = (daylightSavingTimeOffset * 2) - 1 hour

        let daylightSavingsTimeOffset = TimeZone.current.daylightSavingTimeOffset(for: self)
        let oneHour = TimeInterval(3600)
        let offset = (daylightSavingsTimeOffset * 2) - oneHour
        return self.addingTimeInterval(offset)
    }

    func isBetweeen(date date1: Date, andDate date2: Date) -> Bool {
        return date1.compare(self).rawValue * self.compare(date2).rawValue >= 0
    }

    func offsetDaylightSavingsTimeIfNecessary(nextDate: Date) -> Date {
        if let nextDST = TimeZone.current.nextDaylightSavingTimeTransition(after: self) {
            if nextDST.isBetweeen(date: self, andDate: nextDate){
                let offsetDate = nextDate.offsetDaylightSavingsTime()
                let difference = offsetDate.timeIntervalSince(nextDate)
                return nextDate.addingTimeInterval(difference)
            }
        }

        return nextDate
    }

    func dateByAddingMonths(_ months: Int) -> Date? {
        if let dateWithMonthsAdded = Calendar.current.date(byAdding: .month, value: months, to: self) {
            return self.offsetDaylightSavingsTimeIfNecessary(nextDate: dateWithMonthsAdded)
        }

        return self
    }

Test:

func testDateByAddingMonths() {

    let date1 = "2017-01-01T00:00:00Z".asDate()
    let date2 = "2017-02-01T00:00:00Z".asDate()
    let date3 = "2017-03-01T00:00:00Z".asDate()
    let date4 = "2017-04-01T00:00:00Z".asDate()
    let date5 = "2017-05-01T00:00:00Z".asDate()
    let date6 = "2017-06-01T00:00:00Z".asDate()
    let date7 = "2017-07-01T00:00:00Z".asDate()
    let date8 = "2017-08-01T00:00:00Z".asDate()
    let date9 = "2017-09-01T00:00:00Z".asDate()
    let date10 = "2017-10-01T00:00:00Z".asDate()
    let date11 = "2017-11-01T00:00:00Z".asDate()
    let date12 = "2017-12-01T00:00:00Z".asDate()
    let date13 = "2018-01-01T00:00:00Z".asDate()
    let date14 = "2018-02-01T00:00:00Z".asDate()

    var testDate = "2017-01-01T00:00:00Z".asDate()
    XCTAssertEqual(testDate, date1)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date2)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date3)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date4)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date5)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date6)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date7)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date8)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date9)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date10)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date11)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date12)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date13)

    testDate = testDate.dateByAddingMonths(1)!
    XCTAssertEqual(testDate, date14)
}

For completeness, the .asDate() method I'm using

extension String {

    static let dateFormatter = DateFormatter()
    func checkIsValidDate() -> Bool {
        return self.tryParseToDate() != nil
    }

    func tryParseToDate() -> Date? {
        String.dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
        return String.dateFormatter.date(from: self)
    }

    func asDate() -> Date {
        return tryParseToDate()!
    }
}
mbdavis
  • 3,861
  • 2
  • 22
  • 42
1

Do you want to add a "month" or exactly 30 days or one day or one year based on user selecting automatically calculation to date.

  NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] 
  init];
    [dateFormatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
    NSDateComponents *components = [calendar components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:[NSDate date]];

        NSDateComponents *dayComponent = [[NSDateComponents alloc] 
 init];
        int changeid = [here number of days intValue];

        dayComponent.hour = changeid;

        NSCalendar *theCalendar = [NSCalendar currentCalendar];
        NSDate *nextDate = [theCalendar 
 dateByAddingComponents:dayComponent toDate:[dateFormatter 
  dateFromString:self.fromDateTF.text] options:0];

        NSLog(@"nextDate: %@ ...", nextDate);
        [self.toDateTF setText:[dateFormatter 
            stringFromDate:nextDate]];

////month

-2

Do you want to add a "month" or exactly 30 days? If it's 30 days, you do it like this:

// get a date
NSDate *date = [NSDate dateWithNaturalLanguageString:@"2011-01-02"];

// add 30 days to it (in seconds)
date = [date dateByAddingTimeInterval:(30 * 24 * 60 * 60)];

NSLog(@"%@", date); // 2011-02-01

Note: this will not take daylight savings time transitions or leap seconds into account. Use @TheEye's answer if you need that

Abhi Beckert
  • 32,787
  • 12
  • 83
  • 110
  • 2
    This would fail if used across a DST change or leap seconds etc. – James Webster Nov 14 '11 at 10:20
  • @JamesWebster that's a very good point, I've added a note including it to my answer. The low level add/subtract seconds still belongs as one of the answers. You don't always want to follow things like DST, it depends what the date is being used for. – Abhi Beckert Nov 14 '11 at 10:26
  • 2
    No every month has 30 days – Adil Malik Feb 20 '14 at 16:45
  • This doesn't add 30 days. It adds 30 times 86,400 seconds, which is something totally different. That kind of code is incredibly bad advice. – gnasher729 Dec 17 '14 at 00:19
  • It is true that this gives wrong result in the case of DST transitions. *Leap seconds* however are *not* a problem, because the Unix time does not count them. – Martin R Jan 25 '15 at 16:56
  • Don't do it this way nowadays, use dateComponent. – Peter Johnson Sep 26 '16 at 13:14
  • @PeterJohnson despite the title, the pseudo code in the question clearly asks how to add 30 days to a date. You're basically asking me to re-write my answer to match the *four* other answers – there's no need for a fifth. – Abhi Beckert Sep 29 '16 at 23:36
  • My comment was to others that follow. You should be adding 30 days using datecomponent, not by calculating how many minutes and seconds there will usually be (which will sometimes be incorrect). – Peter Johnson Sep 30 '16 at 00:19
  • what if you need to add a year you will miss a lot of days – Amr Angry Jan 09 '18 at 22:45