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


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

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

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

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 .


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

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

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

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.


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

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

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

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


2

Cel C

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

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

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

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 .


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)

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.


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

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

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


To jest niepoprawne. day?.endewaluuje do godziny 12:00 jutro, a nie dzisiaj do 23:59.
Casey Wagner,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.