NSDate начало и конец дня

    -(NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:( NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];

    [components setHour:0];
    [components setMinute:0];
    [components setSecond:0];

    return [cal dateFromComponents:components];

}

-(NSDate *)endOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:(  NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];

    [components setHour:23];
    [components setMinute:59];
    [components setSecond:59];

    return [cal dateFromComponents:components];

}

когда я звоню: [self endOfDay:[дата NSDate]]; Я получаю первое число месяца ... Почему так? Я использую эти два метода, потому что мне нужен интервал от первой секунды первой даты (beginningOfDay:date1) до последней секунды второй даты (endOfDay:Date2) ...

16 ответов


вам не хватает NSDayCalendarUnit на

NSDateComponents *components = [cal components:( NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];

Начало Дня / Конец Дня - Swift 4

  // Extension

extension Date {
    var startOfDay: Date {
        return Calendar.current.startOfDay(for: self)
    }

    var endOfDay: Date {
        var components = DateComponents()
        components.day = 1
        components.second = -1
        return Calendar.current.date(byAdding: components, to: startOfDay)!
    }

    var startOfMonth: Date {
        let components = Calendar.current.dateComponents([.year, .month], from: startOfDay)
        return Calendar.current.date(from: components)!
    }

    var endOfMonth: Date {
        var components = DateComponents()
        components.month = 1
        components.second = -1
        return Calendar.current.date(byAdding: components, to: startOfMonth)!
    }
}

// End of day = Start of tomorrow minus 1 second
// End of month = Start of next month minus 1 second

в iOS 8+ это действительно удобно; вы можете сделать:

let startOfDay = NSCalendar.currentCalendar().startOfDayForDate(date)

чтобы получить конец дня, просто используйте методы NSCalendar в течение 23 часов, 59 минут, 59 секунд, в зависимости от того, как вы определяете конец дня.

// Swift 2.0
let components = NSDateComponents()
components.hour = 23
components.minute = 59
components.second = 59
let endOfDay = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: startOfDay, options: NSCalendarOptions(rawValue: 0))

Дата Math

Яблоко iOS NSCalendar документации. (См. Раздел:Календарным Расчетам)

методы NSCalendar, обсуждаемые NSHipster.


мои расширения Swift для NSDate:

Swift 1.2

extension NSDate {

    func beginningOfDay() -> NSDate {
        var calendar = NSCalendar.currentCalendar()
        var components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: self)
        return calendar.dateFromComponents(components)!
    }

    func endOfDay() -> NSDate {
        var components = NSDateComponents()
        components.day = 1
        var date = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: self.beginningOfDay(), options: .allZeros)!
        date = date.dateByAddingTimeInterval(-1)!
        return date
    }
}

Swift 2.0

extension NSDate {

    func beginningOfDay() -> NSDate {
        let calendar = NSCalendar.currentCalendar()
        let components = calendar.components([.Year, .Month, .Day], fromDate: self)
        return calendar.dateFromComponents(components)!
    }

    func endOfDay() -> NSDate {
        let components = NSDateComponents()
        components.day = 1
        var date = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: self.beginningOfDay(), options: [])!
        date = date.dateByAddingTimeInterval(-1)
        return date
    }
}

Swift 4 Простой и более точный ответ.

время начала: 00:00:00

время окончания: 23:59:59.5

var date = Date() // current date or replace with a specific date
var calendar = Calendar.current
let dateAtMidnight = calendar.startOfDay(for: date)
let dateAtEnd = calendar.date(bySettingHour: 23, minute: 59, second: 59, of: date)

Swift 4-XCode 9 С Date класс вместо NSDate и Calender вместо NSCalender

extension Date {

    var startOfDay : Date {
        let calendar = Calendar.current
        let unitFlags = Set<Calendar.Component>([.year, .month, .day])
        let components = calendar.dateComponents(unitFlags, from: self)
        return calendar.date(from: components)!
   }

    var endOfDay : Date {
        var components = DateComponents()
        components.day = 1
        let date = Calendar.current.date(byAdding: components, to: self.startOfDay)
        return (date?.addingTimeInterval(-1))!
    }
}

использование:

    let myDate = Date()
    let startOfDate = myDate.startOfDay
    let endOfDate = myDate.endOfDay

вам не нужно настраивать компоненты на ноль, просто игнорируйте их:

-(NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date];
    return [calendar dateFromComponents:components];
}

Swift 3

  class func today() -> NSDate {
        return NSDate()
    }

    class func dayStart() -> NSDate {
          return NSCalendar.current.startOfDay(for: NSDate() as Date) as NSDate
    }

    class func dayEnd() -> NSDate {
        let components = NSDateComponents()
        components.day = 1
        components.second = -1
        return NSCalendar.current.date(byAdding: components as DateComponents, to: self.dayStart() as Date)
    }

для меня ни один из ответов здесь, и еще где на сайте StackOverflow работает. Чтобы начать сегодня, я сделал это.

NSCalendar * gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 
[gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];    
NSDateComponents *components = [gregorian components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:[NSDate date]]; 
[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; 
NSDate *beginningOfToday = [gregorian dateFromComponents:components];

Примечание этот [gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; и [components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];.

при создании календаря он инициализируется текущим часовым поясом, а при извлечении даты из его компонентов, поскольку nsdate не имеет часового пояса, дата из текущего часового пояса считается часовым поясом UTC. Поэтому нам нужно установить часовой пояс перед извлечением компонентов и позже при извлечении даты из этих компонентов.


Swift3 используя * XCode8
Apple удаляет NS от имени класса, так что NSDate можно поменять местами на Date. Вы можете получить предупреждение компилятора, если вы попытаетесь бросить их, говоря, что они всегда будут терпеть неудачу, но они работают нормально, когда вы запускаете их на игровой площадке.

Я заменил мой сгенерированный NSDate в основной модели данных с Date и они все еще работают.

extension Date {
  func startTime() -> Date {
    return Calendar.current.startOfDay(for: self)
  }

  func endTime() -> Date {
    var components = DateComponents()
    components.day = 1
    components.second = -1
    return Calendar.current.date(byAdding: components, to: startTime())!
  }
}

еще один способ получить результат:

NSDate *date = [NSDate date];

NSDateComponents *components = [[NSDateComponents alloc] init];
components.day = [[NSCalendar currentCalendar] ordinalityOfUnit:(NSCalendarUnitDay) inUnit:(NSCalendarUnitEra) forDate:date];
NSDate *dayBegin = [[NSCalendar currentCalendar] dateFromComponents:components];

components.day += 1;
NSDate *dayEnd = [[NSCalendar currentCalendar] dateFromComponents:components];

вы упускаете NSDayCalendarUnit в этих компонентах.


С iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ в фундаменте есть встроенная функция, которую вы можете использовать из коробки. Нет необходимости реализовывать собственные функции.

public func startOfDay(for date: Date) -> Date

таким образом, вы можете использовать его таким образом:

let midnightDate = Calendar(identifier: .gregorian).startOfDay(for: Date())

стоит помнить, что это принимает во внимание часовой пояс устройства. Вы можете установить .timeZone on calendar если вы хотите иметь, например, зону UTC.

ссылка на справочные страницы Apple: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday.


просто другой способ использования dateInterval(of:start:interval:for:) of Calendar

о возврате startDate содержит начало дня и interval количество секунд в день.

func startAndEnd(of date : Date) -> (start : Date, end : Date) {
    var startDate = Date()
    var interval : TimeInterval = 0.0
    Calendar.current.dateInterval(of: .day, start: &startDate, interval: &interval, for: date)
    var endDate = startDate.addingTimeInterval(interval-1)
    return (start : startDate, end : endDate)
}

let (start, end) = startAndEnd(of: Date())
print(start, end)

extension Date {
    func stringFrom(dateFormat: String) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = dateFormat
        return formatter.string(from: self)
    }

    func firstSecondInDay() -> Date {
        let dayStr = self.stringFrom(dateFormat: "yyyy-MM-dd")
        let firstSecondStr = "\(dayStr) 00:00:00"
        let format = DateFormatter()
        format.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return format.date(from: firstSecondStr)!
    }

    func lastSecondInDay() -> Date {
        let dayStr = self.stringFrom(dateFormat: "yyyy-MM-dd")
        let laseSecondStr = "\(dayStr) 23:59:59"
        let format = DateFormatter()
        format.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return format.date(from: laseSecondStr)!
    }
}

С

NSCalendar * calendar = [NSCalendar currentCalendar];
NSDate * startDate = [calendar startOfDayForDate:[NSDate date]];
NSLog(@"start date is %@", startDate);