NS Data początku i końca dnia

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

}

Kiedy dzwonię: [self endOfDay: [NSDate date]]; Dostaję pierwszy dzień miesiąca ... Dlaczego tak jest? Używam tych dwóch metod, ponieważ potrzebuję interwału, który jest od pierwszej sekundy pierwszej daty (początek dnia: data1) do ostatniej sekundy drugiej daty (koniec dnia: data2) ...

user1028028
źródło
2
Jeśli chcesz ustawić godziny na zero czasu UTC, łatwiej jest uzyskać timeIntervalSince ..., skróć godziny, a następnie przekonwertuj je z powrotem na NSDate. I to zadziała dla innej strefy czasowej, jeśli najpierw dostosujesz interwał czasu o sekundy strefy czasowejFromGMT, a następnie dostosujesz odwrotny sposób po obcięciu. (Koniec dnia jest oczywiście 23: 59: 59.999 później, co można uzyskać za pomocą prostego dodawania, gdy masz przedział czasowy.)
Hot Licks
Określanie „końca dnia” jako jakiegoś arbitralnego czasu przed jego faktycznym końcem (w tym przypadku jednej sekundy) wydaje się być przepisem na błędne oprogramowanie. Jeśli użyjesz 1 ms, usterki będą rzadsze. Lub możesz wykorzystać 23 godziny, aby zwiększyć prawdopodobieństwo wykrycia błędów. :-)
Edward Brey

Odpowiedzi:

33

Brakuje NSDayCalendarUnitw

NSDateComponents *components = [cal components:( NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
JaanusSiim
źródło
1
Mam dziwne zachowanie, w którym po dodaniu składnika dziennego otrzymuję 23:00 poprzedniego dnia.
Mike M
3
@Mike używa strefy czasowej: components.timeZone = [NSTimeZone timeZoneWithName: @ "GMT"];
dimaxyu
@dimaxyu ma rację. W szybkim tempie: components.timeZone = NSTimeZone (nazwa: "GMT")
Tom Bevelander
221

Początek / koniec dnia - 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
Zelko
źródło
1
NSYearCalendarUnit, NSMonthCalendarUnitI NSDayCalendarUnitzostał wycofany z iOS 8. użytkowania NSCalendarUnitYear, NSCalendarUnitMonthi NSCalendarUnitDayzamiast tego!
T Blank
6
Na początek dnia użyj [[NSCalendar currentCalendar] startOfDayForDate: ...] dla iOS8 +
GingerBreadMane
5
Zwraca to początek dnia w bieżącej strefie czasowej! Oczekuje się, że NSDate będzie w czasie UTC, ale ten konwerter zwraca czas skorygowany dla domyślnej strefy czasowej.
Tom Bevelander,
3
Dlaczego endOfDay jest opcjonalne? Czy są jakieś sytuacje, w których startOfDay nie jest nil, a endOfDay może wynosić zero?
Mansurov Ruslan
1
Tak więc, w zależności od tego, jak tego użyjesz, masz na uwadze
jednosekundową przerwę
29

Szybki 5 Prosta i dokładniejsza odpowiedź.

Godzina rozpoczęcia: 00:00:00

Godzina zakończenia: 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)

Dodatkowy

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)
    }
}
August Lin
źródło
2
Czym się to różni od let dateAtEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())?
Andres Canella
1
Bez różnicy .
August Lin
21

W iOS 8+ jest to naprawdę wygodne; możesz to zrobić:

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

Aby uzyskać koniec dnia, po prostu używaj metod NSCalendar przez 23 godziny, 59 minut, 59 sekund, w zależności od tego, jak zdefiniujesz koniec dnia.

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

Dokumentacja Apple iOS NSCalendar . (Zobacz rozdział: Obliczenia kalendarze )

Metody NSCalendar omówione przez NSHipster .

Bryan Bryce
źródło
17

Moje rozszerzenia Swift dla 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
    }
}
Libor Zapletal
źródło
Możesz po prostu ustawić sekundę na -1 i uzyskać to samo bez użycia dateByAddingTimeInterval
Ben Sinclair
aby uniknąć problemów ze strefą czasową dodaj: components.timeZone = NSTimeZone (nazwa: "GMT")
Tom Bevelander
12

Swift 5.1 - XCode 11 z Dateklasą zamiast NSDatei CalenderzamiastNSCalender

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

Stosowanie:

    let myDate = Date()
    let startOfDate = myDate.startOfDay
    let endOfDate = myDate.endOfDay
Ben
źródło
Otrzymuję błąd niezadeklarowany typ, Datekiedy próbuję go na placu zabaw
John Doe
1
Na mnie to działa. Czy zaimportowałeś UIKit z import UIKit?
Ben
2
@Ben Date and Calendar nie ma w UIKit, jest w Foundation, jednak UIKit importuje Foundation
Arbitur
4

Nie musisz ustawiać komponentów na zero, po prostu je zignoruj:

-(NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date];
    return [calendar dateFromComponents:components];
}
Maxim Lavrov
źródło
2
"Nowo" dostępne: [calendar startOfDayForDate:date]ale -endOfDayForDate:niestety nie ma ...
Julian F. Weinert
4

Dla mnie żadna z odpowiedzi tutaj i gdzie indziej nie działała na stackoverflow. Aby zacząć dzisiaj, zrobiłem to.

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

Zwróć uwagę na to [gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];i[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; .

Kiedy kalendarz jest tworzony, jest inicjowany z aktualną strefą czasową, a kiedy data jest pobierana z jego składników, ponieważ NSDate nie ma strefy czasowej, data z bieżącej strefy czasowej jest uważana za strefę czasową UTC. Musimy więc ustawić strefę czasową przed wyodrębnieniem komponentów i później podczas wyodrębniania daty z tych komponentów.

Vikram Rao
źródło
4

Szybki 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)
    }
Jaseem Abbas
źródło
4

Swift3 Korzystanie z * XCode8
Apple usuwa NSz nazwy klasy, aby NSDatemożna ją było zamienić na Date. Możesz otrzymać ostrzeżenie kompilatora, jeśli spróbujesz je przesłać, mówiąc, że zawsze się nie uda, ale działają dobrze, gdy uruchomisz je na placu zabaw.

Zastąpiłem wygenerowany NSDatew rdzeniu model danych Datei nadal działają.

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())!
  }
}
nieznany z nazwiska
źródło
4

W wersji Swift 3 i nowszych

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

Stosowanie:

var currentDayStart = Date().startOfDayDate
var currentDayEnd = Date().endOfDayDate
Gurjit Singh
źródło
2

Jeszcze jeden sposób na uzyskanie wyniku:

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];
k06a
źródło
2

Brakuje Ci NSDayCalendarUnitskładników.

LombaX
źródło
2

Cel C

NSCalendar * calendar = [NSCalendar currentCalendar];
NSDate * startDate = [calendar startOfDayForDate:[NSDate date]];
NSLog(@"start date is %@", startDate);
Johnny Rockex
źródło
2

Dla szybkiego 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!)")
Hardik Thakkar
źródło
2

Myślę, że najbardziej zwięzły sposób na zrobienie tego w Swift jest następujący:

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)
    }
}
closetCoder
źródło
To idealne! Dzięki!
Baran Emre
1

Ponieważ iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+w Fundacji jest wbudowana funkcja, z której można korzystać po wyjęciu z pudełka. Nie ma potrzeby wdrażania własnych funkcji.

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

Możesz więc użyć tego w ten sposób:

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

Warto pamiętać, że uwzględnia to strefę czasową urządzenia. Można ustawić .timeZonena calendarjeśli chcesz mieć np Strefa czasowa UTC.

Łącze do stron referencyjnych firmy Apple: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday .

Vive
źródło
1

Tylko inny sposób korzystania dateInterval(of:start:interval:for:)zCalendar

Po powrocie startDatezawiera początek dnia i intervalliczbę sekund w ciągu dnia.

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)
vadian
źródło
1

Oto, czego używam w 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())

U mnie działa jak urok. Możesz dodać to do rozszerzenia dla dat początkowych i końcowych w dniu Date, jednak pamiętaj, że dodanie rozszerzenia wydłuża czas kompilacji (chyba że w tym samym pliku co klasa), więc jeśli potrzebujesz go tylko w jednym miejscu lub w jednej klasie. .. nie używaj rozszerzenia.

Paul Peelen
źródło
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)!
    }
}
Benjamin Wen
źródło
0

Tylko w celach informacyjnych, prosty sposób na ustawienie początku i końca dnia w 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)")
Renish Dadhaniya
źródło
-1

Jednostki kalendarza należy traktować jako interwały. Od iOS 10 Calendarma kilka fajnych metod na to

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

Możesz użyć tej samej metody, aby uzyskać początek / koniec dowolnego elementu kalendarza (tydzień / miesiąc / rok itp.)

David Arve
źródło
To jest niepoprawne. day?.endewaluuje do godziny 12:00 jutro, a nie dzisiaj do 23:59.
Casey Wagner,