NSDate Tagesanfang und Tagesende


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

}

Wenn ich anrufe: [self endOfDay: [NSDate date]]; Ich bekomme den ersten des Monats ... Warum ist das so? Ich benutze diese beiden Methoden, weil ich ein Intervall benötige, das von der ersten Sekunde des ersten Datums (beginOfDay: date1) bis zur letzten Sekunde des zweiten Datums (endOfDay: Date2) reicht ...


2
Wenn Sie die Stunden auf Null UTC-Zeit setzen möchten, können Sie auf einfachere Weise timeIntervalSince ... abrufen, die Stunden abschneiden und dann wieder in NSDate konvertieren. Und dies funktioniert für eine andere Zeitzone, wenn Sie zuerst das Zeitintervall um die SekundenFromGMT der Zeitzone anpassen und dann nach dem Abschneiden die entgegengesetzte Richtung einstellen. (Ende des Tages ist offensichtlich 23: 59: 59.999 später, was mit einfacher Addition erhalten werden kann, während Sie das Zeitintervall haben.)
Hot Licks

Die Angabe von "Tagesende" als eine beliebige Zeit vor dem tatsächlichen Ende (in diesem Fall eine Sekunde) scheint ein Rezept für fehlerhafte Software zu sein. Wenn Sie 1 ms verwenden, sind die Störungen weniger häufig. Oder Sie könnten 23 Stunden verwenden, damit Fehler mit größerer Wahrscheinlichkeit erkannt werden. :-)
Edward Brey

Antworten:


33

Sie fehlen NSDayCalendarUnitin

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

1
Ich habe ein seltsames Verhalten, bei dem ich 23:00 des vorherigen Tages erhalte, wenn ich die Tageskomponente hinzufüge.
Mike M

3
@Mike use timezone: components.timeZone = [NSTimeZone timeZoneWithName: @ "GMT"];
Dimaxyu

@ Dimaxyu ist richtig. In Kürze ist seine: components.timeZone = NSTimeZone (Name: "GMT")
Tom Brinkkemper

220

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

1
NSYearCalendarUnit, NSMonthCalendarUnitUnd NSDayCalendarUnithaben als von iOS 8. Verwendung als veraltet NSCalendarUnitYear, NSCalendarUnitMonthund NSCalendarUnitDaystatt!
T Blank

6
Verwenden Sie für den Start des Tages [[NSCalendar currentCalendar] startOfDayForDate: ...] für iOS8 +
GingerBreadMane

5
Dies gibt den startOfDay in der aktuellen Zeitzone zurück! NSDate wird voraussichtlich in UTC sein, aber dieser Konverter gibt die für die Standardzeitzone korrigierte Zeit zurück.
Tom Brinkkemper

3
Warum ist endOfDay optional? Gibt es Situationen, in denen startOfDay nicht Null ist, während endOfDay Null sein könnte?
Mansurov Ruslan

1
Je nachdem, wie Sie dies verwenden, haben Sie also eine Sekunde Zeit zwischen den Enden und Anfängen der Tage. Developer.apple.com/documentation/foundation/nsdate/…
atlex2

29

Swift 5 Einfache und präzisere Antwort.

Startzeit: 00:00:00

Endzeit: 23: 59: 59,5

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

Extra

let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: noon)!
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: noon)!
let specificDate = Date("2020-01-01")

extension Date {
    init(_ dateString:String) {
        let dateStringFormatter = DateFormatter()
        dateStringFormatter.dateFormat = "yyyy-MM-dd"
        dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale
        let date = dateStringFormatter.date(from: dateString)!
        self.init(timeInterval:0, since:date)
    }
}

2
Wie unterscheidet sich das von let dateAtEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())?
Andres Canella

1
Kein Unterschied .
August Lin

21

In iOS 8+ ist dies sehr praktisch. du kannst tun:

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

Um das Ende des Tages zu erhalten, verwenden Sie einfach die NSCalendar-Methoden für 23 Stunden, 59 Minuten und 59 Sekunden, je nachdem, wie Sie das Ende des Tages definieren.

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

Datum Math

Apple iOS NSCalendar-Dokumentation . (Siehe Abschnitt: Kalenderberechnungen )

Von NSHipster diskutierte NSCalendar-Methoden .


16

Meine Swift-Erweiterungen für 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
    }
}

Sie können nur die Sekunde auf -1 setzen und das gleiche erhalten, ohne dateByAddingTimeInterval
Ben Sinclair

Um Zeitzonenprobleme zu vermeiden, fügen Sie Folgendes hinzu: components.timeZone = NSTimeZone (Name: "GMT")
Tom Brinkkemper

12

Swift 5.1 - XCode 11 mit DateKlasse anstelle von NSDateund Calenderanstelle vonNSCalender

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

Verwendung:

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

Ich erhalte den nicht deklarierten Fehlertyp, Datewenn ich ihn auf dem Spielplatz versuche
John Doe

1
Es funktioniert hier für mich. Haben Sie UIKit mit importiert import UIKit?
Ben

2
@ Ben Datum und Kalender ist nicht in UIKit, es ist in Foundation, jedoch importiert UIKit Foundation
Arbitur

4

Sie müssen die Komponenten nicht auf Null setzen, sondern ignorieren sie einfach:

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

2
"Neu" verfügbar : [calendar startOfDayForDate:date], aber es gibt -endOfDayForDate:leider keine ...
Julian F. Weinert

4

Für mich hat keine der Antworten hier und sonst wo auf Stackoverflow funktioniert. Um heute loszulegen, habe ich das gemacht.

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

Beachten Sie dies [gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];und [components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];.

Wenn ein Kalender erstellt wird, wird er mit der aktuellen Zeitzone initialisiert. Wenn das Datum aus seinen Komponenten extrahiert wird, wird das Datum aus der aktuellen Zeitzone als UTC-Zeitzone betrachtet, da NSDate keine Zeitzone hat. Daher müssen wir die Zeitzone vor dem Extrahieren von Komponenten und später beim Extrahieren des Datums aus diesen Komponenten festlegen.


4

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

4

Swift3 Verwenden von * XCode8
Apple entfernt das NSaus dem Klassennamen, NSDatedamit es ausgetauscht werden kann Date. Möglicherweise erhalten Sie eine Compiler-Warnung, wenn Sie versuchen, sie zu besetzen, dass sie immer fehlschlagen. Sie funktionieren jedoch einwandfrei, wenn Sie sie auf dem Spielplatz ausführen.

Ich habe mein NSDateim Kerndaten generiertes Modell durch ersetzt Dateund sie funktionieren immer noch.

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

4

In Swift 3 und höher

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

    var endOfDayDate: Date {
        let nextDayDate = Calendar.current.date(byAdding: .day, value: 1, to: self.startOfDayDate)!
        return nextDayDate.addingTimeInterval(-1)
    }
}

Verwendung:

var currentDayStart = Date().startOfDayDate
var currentDayEnd = Date().endOfDayDate

2

Ein weiterer Weg, um ein Ergebnis zu erzielen:

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


2

Ziel c

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

2

Für schnelle 4

    var calendar = Calendar.current
    calendar.timeZone = NSTimeZone(abbreviation: "UTC")! as TimeZone
    let dateAtMidnight = calendar.startOfDay(for: Date())

    //For End Date
    var components = DateComponents()
    components.day = 1
    components.second = -1

    let dateAtEnd = calendar.date(byAdding: components, to: dateAtMidnight)

    print("dateAtMidnight :: \(dateAtMidnight)")
    print("dateAtEnd :: \(dateAtEnd!)")

2

Ich denke, der prägnanteste Weg, dies in Swift zu tun, ist folgender:

extension Date {
    func startOfDay() -> Date {
        return Calendar.current.startOfDay(for: self)
    }
    func endOfDay() -> Date {
        return Calendar.current.date(bySettingHour: 23, minute: 59, second 59, of: self)
    }
}

Das ist perfekt! Vielen Dank!
Baran Emre

1

Da iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+es in der Foundation eine eingebaute Funktion gibt, die Sie sofort nutzen können. Keine Notwendigkeit, eigene Funktionen zu implementieren.

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

Sie können es also folgendermaßen verwenden:

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

Es ist zu beachten, dass dies die Zeitzone des Geräts berücksichtigt. Sie können festlegen , .timeZoneaufcalendar , wenn Sie zB UTC Zone haben wollen.

Link zu den Apple-Referenzseiten: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday .


1

Nur eine andere Art der Verwendung dateInterval(of:start:interval:for:)vonCalendar

Bei der Rückkehr startDateenthält der Beginn des Tages und intervaldie Anzahl der Sekunden am Tag.

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)

1

Folgendes verwende ich für Swift 4.2:

    let calendar = Calendar.current
    let fromDate = calendar.startOfDay(for: Date())
    let endDate = calendar.date(bySettingHour: 23, minute: 59, second: 59, of: Date())

Funktioniert wie ein Zauber für mich. Sie können dies zu einer Erweiterung für Start- und Enddatum Datehinzufügen. Beachten Sie jedoch, dass das Hinzufügen einer Erweiterung die Kompilierungszeit verlängert (außer in derselben Datei wie die Klasse). Wenn Sie sie also nur an einer Stelle oder in einer Klasse benötigen. .. keine Erweiterung verwenden.


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

0

Nur als Referenz, einfache Möglichkeit, Start und Ende des Tages in Swift 4 festzulegen ,

var comp: DateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date())
comp.hour = 0
comp.minute = 0
comp.second = 0
comp.timeZone = TimeZone(abbreviation: "UTC")!


//Set Start of Day
let startDate : Date = Calendar.current.date(from: comp)!
print(“Day of Start : \(startDate)")


//Set End of Day
comp.hour = 23
comp.minute = 59
comp.second = 59

let endDate : Date = Calendar.current.date(from:comp)!
print("Day of End : \(endDate)")

-1

Kalendereinheiten sollten als Intervalle betrachtet werden. Ab iOS 10 Calendargibt es dafür einige nette Methoden

let day = Calendar.autoupdatingCurrent.dateInterval(of: .day, for: Date())
day?.end
day?.start

Sie können dieselbe Methode verwenden, um den Anfang / das Ende einer Kalenderkomponente (Woche / Monat / Jahr usw.) abzurufen.


Das ist falsch. day?.endwird morgen um 00:00 Uhr ausgewertet, heute Abend nicht um 23:59 Uhr.
Casey Wagner
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.