¿Cómo agregar un mes a una NSDate?

81

¿Cómo agregar un mes al objeto NSDate?

NSDate *someDate = [NSDate Date] + 30Days.....;
o azran
fuente
1
¿Qué resultado desea si la fecha de inicio es el 31 de enero?
gnasher729

Respuestas:

138

Necesita utilizar 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
El ojo
fuente
¿Sabes cómo puedo comparar entre ahora y la fecha de destino? para comprobar si paso esta fecha?
o azran
1
Las comparaciones de fechas se realizan con las funciones NSDate compare, previousDate y laterDate; consulte la documentación de NSDate para ello: developer.apple.com/library/mac/#documentation/Cocoa/Reference/…
TheEye
1
@orazran puede comparar fechas con:, [date timeIntervalSinceDate:otherDate]que devolverá la diferencia entre ellas en segundos (menos de 0 para fechas pasadas, mayor que 0 para fechas futuras).
Abhi Beckert
126

Con iOS 8 y OS X 10.9 puede agregar NSCalendarUnitsusando NSCalendar:

C objetivo

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
fuente
Los ejemplos anteriores llaman a un método, no acceden a una propiedad.
Kevin
Swift 3: let date = Calendar.current.date (byAdding: .month, value: 1, to: Date ())
Maksym Bilan
Esta debería ser la respuesta aceptada. La respuesta actualmente aceptada es solo Objective-C y es demasiado detallada.
Colin Basnett
23

Para 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)!
    }
}
Parque Soohwan
fuente
1
¿Qué pasa si agrego 1 mes al 31 de enero, terminará el 2 de marzo o ...?
Michał Ziobro
13

Por ejemplo, para agregar 3 meses a la fecha actual en Swift:

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

En Swift 2.0:

let date = NSCalendar.currentCalendar().dateByAddingUnit(.Month, value: 3, toDate: NSDate(), options: [])
  • El nuevo OptionSetType estructura de le NSCalendarUnitpermite especificar más simplemente.Month
  • Los parámetros que toman OptionSetType(como el options:parámetro, que toma NSCalendarOptions) no pueden ser nil, así que pase un conjunto vacío ( []) para representar "sin opciones".
Aaron Brager
fuente
.MonthCalendarUnitestá en desuso, use.CalendarUnitMonth
Arnold
3

En 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
fuente
2

PARA SWIFT 3.0

aquí está la función, puede reducir días, mes, día en cualquier recuento como, por ejemplo, aquí, he reducido el año de la fecha actual del sistema en 100 años, puede hacerlo por día, mes también simplemente configure el contador y luego almacene los valores en matriz, y haga lo que quiera hacer con esa matriz

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)
}
aditya panse
fuente
1

Otras respuestas funcionan bien si su comportamiento deseado es agregar un mes y permitir el horario de verano. Esto produce resultados tales que:

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

Sin embargo, quería ignorar la hora perdida o ganada por DST, de modo que:

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

Entonces verifico si se pasa un límite de DST, y si es así, sumo o resto una hora en consecuencia:

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
    }

Prueba:

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

Para completar, el método .asDate () que estoy usando

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
fuente
1

¿Desea agregar un "mes" o exactamente 30 días o un día o un año según el usuario que seleccione automáticamente el cálculo hasta la fecha?

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

////mes

Gangireddy Rami Reddy
fuente
-3

¿Quiere agregar un "mes" o exactamente 30 días? Si son 30 días, hazlo así:

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

Nota: esto no tendrá en cuenta las transiciones del horario de verano ni los segundos intercalares. Use la respuesta de @ TheEye si lo necesita

Abhi Beckert
fuente
2
Esto fallaría si se usa durante un cambio de horario de verano o segundos intercalares
James Webster
@JamesWebster ese es un muy buen punto, agregué una nota que la incluía en mi respuesta. Los segundos de sumar / restar de bajo nivel todavía pertenecen como una de las respuestas. No siempre desea seguir cosas como el horario de verano, depende de para qué se esté utilizando la fecha.
Abhi Beckert
2
No, cada mes tiene 30 días
Adil Malik
Esto no agrega 30 días. Agrega 30 veces 86,400 segundos, que es algo totalmente diferente. Ese tipo de código es un consejo increíblemente malo.
gnasher729
Es cierto que esto da un resultado incorrecto en el caso de las transiciones DST. Los saltos de segundos , sin embargo son no un problema, ya que el tiempo de Unix no los cuenta.
Martin R