NSDate inizio giornata e fine giornata


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

}

Quando chiamo: [self endOfDay: [NSDate date]]; Ricevo il primo del mese ... Perché? Uso questi due metodi perché ho bisogno di un intervallo che va dal primo secondo della prima data (beginOfDay: date1) all'ultimo secondo della seconda data (endOfDay: Date2) ...


2
Se vuoi impostare le ore su zero UTC, un modo più semplice per ottenere timeIntervalSince ..., troncare le ore e quindi riconvertirle in NSDate. E questo funzionerà per un altro fuso orario se prima regoli l'intervallo di tempo in base ai secondi del fuso orario da GMT, quindi regola in modo opposto dopo il troncamento. (La fine della giornata è ovviamente 23: 59: 59.999 più tardi, che può essere ottenuta con una semplice aggiunta mentre si ha l'intervallo di tempo.)
Hot Licks

Specificare "fine giornata" come un tempo arbitrario prima della sua fine effettiva (un secondo in questo caso) sembra una ricetta per software glitch. Se usi 1 ms, i glitch saranno meno frequenti. Oppure potresti impiegare 23 ore in modo che eventuali bug abbiano maggiori probabilità di essere catturati. :-)
Edward Brey il

Risposte:


33

Vi manca NSDayCalendarUnitin

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

1
Ho uno strano comportamento per cui se aggiungo la componente giorno ottengo le 23:00 del giorno precedente.
Mike M

3
@Mike usa il fuso orario: components.timeZone = [NSTimeZone timeZoneWithName: @ "GMT"];
dimaxyu

@dimaxyu ha ragione. In breve è: components.timeZone = NSTimeZone (nome: "GMT")
Tom Bevelander

220

Inizio giornata / Fine giornata - 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, NSMonthCalendarUnitE NSDayCalendarUnitsono stati deprecati come di iOS 8. Usare NSCalendarUnitYear, NSCalendarUnitMonth, e NSCalendarUnitDayinvece!
T Vuoto

6
Per l'inizio della giornata, utilizza [[NSCalendar currentCalendar] startOfDayForDate: ...] per iOS8 +
GingerBreadMane

5
Questo restituisce startOfDay nel fuso orario corrente! NSDate dovrebbe essere in UTC, ma questo convertitore restituisce l'ora corretta per il fuso orario predefinito.
Tom Bevelander,

3
Perché endOfDay è opzionale? Ci sono situazioni in cui startOfDay non è nullo, mentre endOfDay potrebbe essere nullo?
Mansurov Ruslan

1
Quindi, a seconda di come lo usi, ti dispiace un secondo di intervallo tra la fine e l'inizio dei giorni developer.apple.com/documentation/foundation/nsdate/…
atlex2

29

Swift 5 Risposta semplice e più precisa.

Ora di inizio: 00:00:00

Ora di fine: 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
In che modo è diverso da let dateAtEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())?
Andres Canella

1
Nessuna differenza .
August Lin

21

In iOS 8+ questo è davvero conveniente; tu puoi fare:

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

Per ottenere la fine della giornata, utilizza i metodi NSCalendar per 23 ore, 59 minuti e 59 secondi, a seconda di come definisci la fine della giornata.

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

Date Math

Documentazione NSCalendar di Apple iOS . (Vedere la sezione: Calcoli calendari )

Metodi NSCalendar discussi da NSHipster .


17

Le mie estensioni Swift per 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
    }
}

Puoi semplicemente impostare il secondo su -1 e ottenere lo stesso senza usare dateByAddingTimeInterval
Ben Sinclair

per evitare problemi di fuso orario aggiungi: components.timeZone = NSTimeZone (nome: "GMT")
Tom Bevelander

12

Swift 5.1 - XCode 11 con Dateclasse invece di NSDatee Calenderinvece diNSCalender

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

Uso:

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

Ricevo l'errore di tipo non dichiarato Datequando lo provo nel parco giochi
John Doe,

1
Qui sta funzionando per me. Hai importato UIKit con import UIKit?
Ben

2
@Ben Date and Calendar non è in UIKit, è in Foundation, tuttavia UIKit importa Foundation
Arbitur

4

Non devi impostare i componenti su zero, ignorali semplicemente:

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

2
"Appena" disponibile:, [calendar startOfDayForDate:date]ma -endOfDayForDate:purtroppo no ...
Julian F. Weinert

4

Per me nessuna delle risposte qui e altrove su StackOverflow ha funzionato. Per iniziare oggi l'ho fatto.

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

Nota questo [gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];e [components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];.

Quando viene creato un calendario, viene inizializzato con il fuso orario corrente e quando la data viene estratta dai suoi componenti, poiché NSDate non ha fuso orario, la data del fuso orario corrente viene considerata come fuso orario UTC. Quindi è necessario impostare il fuso orario prima di estrarre i componenti e successivamente durante l'estrazione della data da questi componenti.


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 utilizzando * XCode8
Apple sta rimuovendo il NSdal nome della classe in modo che NSDatepossa essere scambiato con Date. Potresti ricevere un avviso del compilatore se provi a lanciarli dicendo che falliranno sempre, ma funzionano bene quando li esegui nel playground.

Ho sostituito il mio generato NSDatenel modello di dati di base con Datee funzionano ancora.

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 e versioni successive

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

Uso:

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

2

Un altro modo per ottenere risultati:

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

Objective-C

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

2

Per swift 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

Penso che il modo più succinto per farlo in Swift sia il seguente:

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

È perfetto! Grazie!
Baran Emre

1

Poiché iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+nella Fondazione è presente una funzione incorporata, che puoi utilizzare immediatamente. Non è necessario implementare le proprie funzioni.

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

Quindi puoi usarlo in questo modo:

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

Vale la pena ricordare che questo prende in considerazione il fuso orario del dispositivo. È possibile impostare .timeZonesu calendarse si vuole avere per esempio orario UTC.

Collegamento alle pagine di riferimento di Apple: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday .


1

Solo un altro modo tramite dateInterval(of:start:interval:for:)diCalendar

Al ritorno startDatecontiene l'inizio della giornata e intervalil numero di secondi della giornata.

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

Questo è quello che uso per 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())

Funziona come un fascino per me. Potresti aggiungerlo a un'estensione per le date di inizio e di fine Date, tuttavia tieni presente che l'aggiunta di un'estensione aumenta il tempo di compilazione (a meno che non sia nello stesso file della classe), quindi se ne hai bisogno solo in un posto o in una classe. .. non utilizzare un'estensione.


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

Solo per riferimento, un modo semplice per impostare l'inizio e la fine della giornata in Swift 4 ,

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

Le unità del calendario dovrebbero essere considerate come intervalli. A partire da iOS 10 Calendarha alcuni metodi carini per questo

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

È possibile utilizzare lo stesso metodo per ottenere l'inizio / la fine di qualsiasi componente del calendario (settimana / mese / anno ecc.)


Questo non è corretto. day?.endvaluta alle 00:00 di domani, non alle 23:59 di stasera.
Casey Wagner
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.