NSDate awal hari dan akhir hari

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

}

Ketika saya menelepon: [self endOfDay: [NSDate date]]; Saya mendapatkan yang pertama setiap bulan ... Mengapa begitu? Saya menggunakan dua metode ini karena saya memerlukan interval dari detik pertama dari tanggal pertama (startingOfDay: date1) hingga detik terakhir dari tanggal kedua (endOfDay: Date2) ...

pengguna1028028
sumber
2
Jika Anda ingin menyetel jam ke nol waktu UTC, cara yang lebih mudah untuk mendapatkan timeIntervalSince ..., potong jamnya, lalu ubah kembali ke NSDate. Dan ini akan berfungsi untuk zona waktu lain jika Anda terlebih dahulu menyesuaikan interval waktu dengan detikFromGMT zona waktu tersebut, lalu menyesuaikan dengan cara yang berlawanan setelah pemotongan. (Akhir hari jelas 23: 59: 59,999 kemudian, yang dapat diperoleh dengan penambahan sederhana saat Anda memiliki interval waktu.)
Hot Licks
Menentukan "akhir hari" sebagai waktu yang sewenang-wenang sebelum akhir sebenarnya (satu detik dalam kasus ini) tampak seperti resep untuk perangkat lunak yang bermasalah. Jika Anda menggunakan 1 md, gangguan akan berkurang. Atau Anda dapat menggunakan 23 jam agar setiap bug lebih mungkin tertangkap. :-)
Edward Brey

Jawaban:

33

Anda hilang NSDayCalendarUnitdi

NSDateComponents *components = [cal components:( NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
JaanusSiim
sumber
1
Saya memiliki perilaku yang aneh dimana jika saya menambahkan komponen hari saya mendapatkan 23:00 dari hari sebelumnya.
Mike M
3
@Mike menggunakan zona waktu: components.timeZone = [NSTimeZone timeZoneWithName: @ "GMT"];
dimaxyu
@dimaxyu benar. Dengan cepat: components.timeZone = NSTimeZone (nama: "GMT")
Tom Bevelander
220

Awal Hari / Akhir Hari - 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
sumber
1
NSYearCalendarUnit, NSMonthCalendarUnit, Dan NSDayCalendarUnittelah usang sebagai iOS 8. Gunakan NSCalendarUnitYear, NSCalendarUnitMonth, dan NSCalendarUnitDaysebagai gantinya!
T Blank
6
Untuk awal hari, penggunaan [[NSCalendar currentCalendar] startOfDayForDate: ...] untuk iOS8 +
GingerBreadMane
5
Ini mengembalikan startOfDay di zona waktu saat ini! NSDate diharapkan dalam UTC tetapi konverter ini mengembalikan waktu yang dikoreksi untuk zona waktu default.
Tom Bevelander
3
Mengapa endOfDay bersifat opsional? Apakah ada situasi di mana startOfDay tidak nihil, sedangkan endOfDay bisa nihil?
Mansurov Ruslan
1
Jadi, tergantung pada bagaimana Anda menggunakan ini, Anda memikirkan celah satu detik antara akhir dan awal hari developer.apple.com/documentation/foundation/nsdate/…
atlex2
29

Swift 5 Jawaban sederhana dan lebih tepat.

Waktu mulai: 00:00:00

Waktu berakhir: 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)

Tambahan

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)
    }
}
Agustus Lin
sumber
2
Apa bedanya dengan ini let dateAtEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())?
Andres Canella
1
Tidak ada perbedaan .
Agustus Lin
21

Di iOS 8+ ini sangat nyaman; Anda dapat melakukan:

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

Untuk mengetahui penghujung hari, cukup gunakan metode NSCalendar selama 23 jam, 59 menit, 59 detik, tergantung bagaimana Anda menentukan akhir hari.

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

Tanggal Matematika

Dokumentasi NSCalendar Apple iOS . (Lihat Bagian: Perhitungan Kalender )

Metode NSCalendar dibahas oleh NSHipster .

Bryan Bryce
sumber
17

Ekstensi Swift saya untuk NSDate:

Swift 1.2.0

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
sumber
Anda bisa menyetel detik ke -1 dan mendapatkan yang sama tanpa menggunakan dateByAddingTimeInterval
Ben Sinclair
untuk menghindari masalah zona waktu tambahkan: components.timeZone = NSTimeZone (nama: "GMT")
Tom Bevelander
12

Swift 5.1 - XCode 11 dengan Datekelas, bukan NSDatedan Calendersebagai gantiNSCalender

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

Pemakaian:

    let myDate = Date()
    let startOfDate = myDate.startOfDay
    let endOfDate = myDate.endOfDay
Ben
sumber
Saya mendapatkan jenis kesalahan yang tidak dideklarasikan Dateketika saya mencobanya di taman bermain
John Doe
1
Ini bekerja untuk saya di sini. Apakah Anda mengimpor UIKit dengan import UIKit?
Ben
2
@Ben Tanggal dan Kalender tidak ada di UIKit, di Yayasan, tetapi UIKit mengimpor Yayasan
Arbitur
4

Anda tidak perlu menyiapkan komponen ke nol, abaikan saja:

-(NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date];
    return [calendar dateFromComponents:components];
}
Maxim Lavrov
sumber
2
"Baru" tersedia:, [calendar startOfDayForDate:date]tetapi -endOfDayForDate:sayangnya tidak ada ...
Julian F. Weinert
4

Bagi saya tidak ada jawaban di sini dan di mana pun pada stackoverflow bekerja. Untuk memulai hari ini saya melakukan ini.

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

Catat ini [gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];dan [components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];.

Saat kalender dibuat, kalender diinisialisasi dengan zona waktu saat ini dan ketika tanggal diambil dari komponennya, karena NSDate tidak memiliki zona waktu, tanggal dari zona waktu saat ini dianggap sebagai zona waktu UTC. Jadi kita perlu menyetel zona waktu sebelum mengekstrak komponen dan nanti saat mengekstrak tanggal dari komponen ini.

Vikram Rao
sumber
4

Cepat 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
sumber
4

Swift3 Menggunakan * XCode8
Apple menghapus NSdari nama kelas sehingga NSDatedapat ditukar ke Date. Anda mungkin mendapatkan peringatan kompiler jika Anda mencoba mentransmisikannya dengan mengatakan bahwa mereka akan selalu gagal, tetapi berfungsi dengan baik saat Anda menjalankannya di taman bermain.

Saya mengganti NSDatemodel data inti yang saya hasilkan dengan Datedan mereka masih berfungsi.

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())!
  }
}
John Doe
sumber
4

Di Swift 3 ke atas

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

Pemakaian:

var currentDayStart = Date().startOfDayDate
var currentDayEnd = Date().endOfDayDate
Gurjit Singh
sumber
2

Satu cara lagi untuk mendapatkan hasil:

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
sumber
2

Anda hilang NSDayCalendarUnitdi komponen.

LombaX
sumber
2

Objective-C

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

Untuk cepat 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
sumber
2

Menurut saya, cara paling ringkas untuk melakukan ini di Swift adalah sebagai berikut:

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
sumber
Itu sempurna! Terima kasih!
Baran Emre
1

Karena iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ada fungsi bawaan di Foundation, yang dapat Anda gunakan di luar kotak. Tidak perlu mengimplementasikan fungsi sendiri.

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

Jadi Anda bisa menggunakannya dengan cara ini:

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

Perlu diingat, bahwa ini mempertimbangkan zona waktu perangkat. Anda dapat mengatur .timeZonetentang calendarjika Anda ingin memiliki misalnya UTC zona.

Tautan ke halaman referensi Apple: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday .

Vive
sumber
1

Hanya cara lain menggunakan dateInterval(of:start:interval:for:)dariCalendar

Saat kembali startDateberisi awal hari dan intervaljumlah detik dalam hari.

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
sumber
1

Inilah yang saya gunakan untuk 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())

Bekerja seperti pesona bagi saya. Anda dapat menambahkan ini ke ekstensi untuk tanggal mulai dan akhir pada Date, namun perlu diingat bahwa menambahkan ekstensi akan menambah waktu kompilasi (kecuali dalam file yang sama dengan kelas), jadi jika Anda hanya membutuhkannya di satu tempat atau di satu kelas. .. jangan gunakan ekstensi.

Paul Peelen
sumber
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
sumber
0

Hanya untuk referensi, cara sederhana untuk mengatur Awal dan Akhir hari di 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
sumber
-1

Unit kalender harus dianggap sebagai interval. Pada iOS 10 Calendarmemiliki beberapa metode bagus untuk ini

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

Anda dapat menggunakan metode yang sama, untuk mendapatkan awal / akhir dari setiap komponen kalender (minggu / bulan / tahun dll)

David Arve
sumber
Ini salah day?.endmengevaluasi ke 12:00 AM besok, bukan 11:59 malam ini.
Casey Wagner