Як додати місяць до NSDate?


Відповіді:


139

Вам потрібно використовувати 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

ти знаєш, як я можу порівняти від тепер до дати долі? щоб перевірити, чи передаю цю дату?
або Азран

1
Порівняння дат виконується за допомогою функцій NSDate порівняння, більш ранніхДата та пізнішихДат - див. Документацію до НСДат для цього: developer.apple.com/library/mac/#documentation/Cocoa/Reference/…
TheEye

1
@orazran ви можете порівняти дати з:, [date timeIntervalSinceDate:otherDate]який поверне різницю між ними в секундах (менше 0 для минулих дат, більше 0 для майбутніх дат).
Абхі Бекерт,

127

В iOS 8 та OS X 10.9 ви можете додавати NSCalendarUnitsза допомогою NSCalendar:

Завдання-C

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

Стрімкий 3

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

Стрімкий 2

let cal = NSCalendar.currentCalendar()
let date = cal.dateByAddingUnit(.Month, value: 1, toDate: NSDate(), options: [])

Наведені вище приклади викликають метод, не отримуючи доступ до властивості.
Кевін,

Swift 3: let date = Calendar.current.date (byAdding: .month, value: 1, to: Date ())
Максим Білан

Це має бути прийнятою відповіддю. Наразі прийнята відповідь призначена лише для Objective-C і є надмірно детальною.
Колін Баснетт

23

Для швидкої 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)!
    }
}

1
Що станеться, якщо я додаю 1 місяць до 31 січня, це закінчиться 2 березня або ...?
Міхал Зіобро,

13

Наприклад, щоб додати 3місяці до поточної дати в Swift:

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

У Swift 2.0:

let date = NSCalendar.currentCalendar().dateByAddingUnit(.Month, value: 3, toDate: NSDate(), options: [])
  • Нова OptionSetTypeструктура NSCalendarUnitдозволяє вам більш просто вказати.Month
  • Параметри, які приймають OptionSetType(як options:параметр, який бере NSCalendarOptions), не можуть бути nil, тому передайте порожній набір ( []), щоб представити "немає опцій".

.MonthCalendarUnitзастаріло, використовуйте.CalendarUnitMonth
Арнольд

3

У 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))

2

ДЛЯ SWIFT 3.0

ось функція, ви можете зменшити дні, місяць, день будь-яким підрахунком, як, наприклад, тут, я зменшив рік поточної системної дати на 100 років, ви можете зробити це за день, місяць, а також просто встановити лічильник, а потім зберегти значення у масиві, і робіть із цим масивом все, що хочете

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)
}

1

Інші відповіді добре працюють, якщо бажана поведінка додає місяць і дозволяє переходити на літній час. Це дає такі результати, що:

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

Однак я хотів проігнорувати годину, втрачену або отриману за літнім часом, таку, що:

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

Тому я перевіряю, чи передано межу літнього часу, і якщо так, додайте або відніміть годину відповідно:

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
    }

Тест:

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)
}

Для повноти використовую метод .asDate ()

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()!
    }
}

1

Ви хочете додати "місяць" або рівно 30 днів або один день або один рік на основі автоматичного вибору користувачем розрахунку на сьогоднішній день.

  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]];

//// місяць


-3

Ви хочете додати "місяць" або рівно 30 днів? Якщо це 30 днів, ви робите це так:

// 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

Примітка: це не враховуватиме переходу на літній час та високосних секунд. Використовуйте відповідь @ TheEye, якщо вам це потрібно


2
Це не вдасться, якщо використовувати його через перехід на літній час або стрибкові секунди тощо
Джеймс Вебстер,

@JamesWebster, це дуже хороший момент, я додав примітку, що включає її, до своєї відповіді. Низький рівень додавання / віднімання секунд все ще залишається однією з відповідей. Не завжди потрібно дотримуватися таких речей, як літній час, це залежить від того, для якої дати використовується.
Абхі Бекерт,

2
Жоден місяць не має 30 днів
Аділ Малік,

Це не додає 30 днів. Це додає 30 разів 86 400 секунд, що є абсолютно іншим. Такий код - неймовірно погана порада.
gnasher729

Це правда, що це дає неправильний результат у разі переходів на літній час. Високосні секунди, однак, не є проблемою, оскільки час Unix їх не враховує.
Martin R
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.