【问题标题】:How to add one month to an NSDate?如何为 NSDate 添加一个月?
【发布时间】:2011-11-14 09:59:35
【问题描述】:

如何向 NSDate 对象添加月份?

NSDate *someDate = [NSDate Date] + 30Days.....;

【问题讨论】:

  • 如果开始日期是 1 月 31 日,您想要什么结果?

标签: ios iphone objective-c nsdate


【解决方案1】:

你需要使用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

【讨论】:

  • 你知道我如何比较现在和命运的日期吗?检查我是否通过了这个日期?
  • 日期比较是通过 NSDate 函数 compare、earlierDate 和 laterDate 完成的 - 请参阅 NSDate 文档:developer.apple.com/library/mac/#documentation/Cocoa/Reference/…
  • @orazran 您可以将日期与:[date timeIntervalSinceDate:otherDate] 进行比较,这将以秒为单位返回它们之间的差异(过去日期小于 0,未来日期大于 0)。
【解决方案2】:

在 iOS 8 和 OS X 10.9 中,您可以使用 NSCalendar 添加 NSCalendarUnits

目标-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: 让 date = Calendar.current.date(byAdding: .month, value: 1, to: Date())
  • 这应该是公认的答案。当前接受的答案仅是 Objective-C,而且过于冗长。
【解决方案3】:

对于 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)!
    }
}

【讨论】:

  • 如果我将 1 个月添加到 1 月 31 日,它将在 3 月 2 日结束,或者...?
【解决方案4】:

例如,在 Swift 中将 3 月份添加到当前日期:

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: [])
  • NSCalendarUnit 的新OptionSetType 结构让您可以更简单地指定.Month
  • 采用OptionSetType的参数(如options:参数,采用NSCalendarOptions)不能为nil,所以传入一个空集([])表示“无选项”。

【讨论】:

  • .MonthCalendarUnit 已弃用,请使用 .CalendarUnitMonth
【解决方案5】:

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

【讨论】:

    【解决方案6】:

    适用于 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)
    }
    

    【讨论】:

      【解决方案7】:

      如果您希望的行为是增加一个月并允许夏令时,其他答案也可以正常工作。这会产生这样的结果:

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

      但是我想忽略 DST 损失或获得的小时数,例如:

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

      所以我检查是否通过了 DST 边界,如果是,则相应地增加或减少一个小时:

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

      【讨论】:

        【解决方案8】:

        您是否要根据用户选择自动计算日期来添加“月”或正好 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]];
        

        ////月

        【讨论】:

          【解决方案9】:

          您要添加“月”还是正好 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 的答案

          【讨论】:

          • 如果在 DST 更改或闰秒等期间使用,这将失败。
          • @JamesWebster 这是一个很好的观点,我已经在我的答案中添加了一个包含它的注释。低级加/减秒仍然属于答案之一。您并不总是想遵循 DST 之类的内容,这取决于日期的用途。
          • 没有每个月有30天
          • 这不会增加 30 天。它增加了 30 倍 86,400 秒,这是完全不同的。这种代码是非常糟糕的建议。
          • 确实,在 DST 转换的情况下,这会给出错误的结果。 闰秒不是问题,因为 Unix 时间不计算它们。
          猜你喜欢
          • 1970-01-01
          • 2011-08-01
          • 1970-01-01
          • 2021-01-12
          • 2011-06-04
          • 2011-07-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多