NSD วันที่เริ่มต้นของวันและจุดสิ้นสุดของวัน


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

}

เมื่อฉันโทร: [self endOfDay: [NSDate date]]; ฉันได้รับของเดือนแรก ... ทำไมเป็นอย่างนั้น ฉันใช้สองวิธีนี้เพราะฉันต้องการช่วงเวลาตั้งแต่วินาทีแรกของวันที่แรก (beginningOfDay: date1) ถึงวินาทีสุดท้ายของวันที่สอง (endOfDay: Date2) ...


2
หากคุณต้องการตั้งค่าชั่วโมงเป็นศูนย์เวลา UTC วิธีที่ง่ายกว่าในการรับ timeIntervalSince ... ตัดทอนชั่วโมงแล้วแปลงกลับเป็น NSDate และสิ่งนี้จะใช้ได้กับเขตเวลาอื่นหากคุณปรับช่วงเวลาด้วยวินาทีของเขตเวลาจาก GMT ก่อนแล้วจึงปรับในทางตรงกันข้ามหลังจากตัดทอน (เห็นได้ชัดว่าสิ้นสุดวันคือ 23: 59: 59.999 ในภายหลังซึ่งสามารถรับได้ด้วยการเพิ่มแบบง่ายๆในขณะที่คุณมีช่วงเวลา)
Hot Licks

การระบุ "สิ้นสุดวัน" เป็นเวลาที่กำหนดก่อนที่จะสิ้นสุดจริง (หนึ่งวินาทีในกรณีนี้) ดูเหมือนเป็นสูตรสำหรับซอฟต์แวร์ที่มีข้อผิดพลาด หากคุณใช้ 1 มิลลิวินาทีความผิดพลาดจะน้อยลง หรือคุณอาจใช้เวลา 23 ชั่วโมงเพื่อให้มีแนวโน้มที่จะถูกจับได้ :-)
Edward Brey

คำตอบ:


33

คุณหายไปNSDayCalendarUnitใน

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

1
ฉันมีพฤติกรรมแปลก ๆ ที่ถ้าฉันเพิ่มองค์ประกอบของวันฉันจะได้รับ 23:00 น. ของวันก่อนหน้า
Mike M

3
@ ไมค์ใช้เขตเวลา: components.timeZone = [NSTimeZone timeZoneWithName: @ "GMT"];
dimaxyu

@dimaxyu พูดถูก อย่างรวดเร็วของ: components.timeZone = NSTimeZone (ชื่อ: "GMT")
Tom Bevelander

224

เริ่มต้นวัน / สิ้นสุดวัน - 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, NSMonthCalendarUnitและNSDayCalendarUnitได้รับการคัดค้านเป็นของ iOS 8. ใช้NSCalendarUnitYear, NSCalendarUnitMonthและNSCalendarUnitDayแทน!
T Blank

6
สำหรับการเริ่มต้นวันใช้ [[NSCalendar currentCalendar] startOfDayForDate: ... ] สำหรับ iOS8 +
GingerBreadMane

5
สิ่งนี้ส่งคืน startOfDay ในเขตเวลาปัจจุบัน! NSDate คาดว่าจะอยู่ใน UTC แต่ตัวแปลงนี้จะส่งคืนเวลาที่แก้ไขสำหรับเขตเวลาเริ่มต้น
Tom Bevelander

3
เหตุใด endOfDay จึงเป็นทางเลือก มีสถานการณ์ใดบ้างที่ startOfDay ไม่ใช่ศูนย์ในขณะที่ endOfDay อาจเป็นศูนย์
Mansurov Ruslan

1
ดังนั้นขึ้นอยู่กับว่าคุณใช้สิ่งนี้อย่างไรคุณนึกถึงช่องว่างหนึ่งวินาทีระหว่างจุดจบและจุดเริ่มต้นของวันdeveloper.apple.com/documentation/foundation/nsdate/…
atlex2

29

Swift 5 คำตอบที่ง่ายและแม่นยำยิ่งขึ้น

เวลาเริ่ม: 00:00:00 น

เวลาสิ้นสุด: 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)

พิเศษ

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
วิธีนี้แตกต่างจากlet dateAtEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())?
Andres Canella

1
ไม่แตกต่าง .
สิงหาคม Lin

21

ใน iOS 8+ สิ่งนี้สะดวกมาก คุณทำได้:

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

หากต้องการสิ้นสุดวันจากนั้นใช้วิธีการ NSCalendar เป็นเวลา 23 ชั่วโมง 59 นาที 59 วินาทีขึ้นอยู่กับว่าคุณกำหนดจุดสิ้นสุดของวันอย่างไร

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

วันที่คณิตศาสตร์

เอกสาร Apple iOS NSCalendar (ดูหัวข้อ: การคำนวณตามปฏิทิน )

วิธีการ NSCalendar หารือ NSHipster


17

ส่วนขยาย Swift ของฉันสำหรับ 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
    }
}

คุณสามารถตั้งค่าวินาทีเป็น -1 และได้รับสิ่งเดียวกันโดยไม่ต้องใช้ dateByAddingTimeInterval
Ben Sinclair

เพื่อหลีกเลี่ยงปัญหาเขตเวลาให้เพิ่ม: components.timeZone = NSTimeZone (name: "GMT")
Tom Bevelander

13

Swift 5.1 - XCode 11พร้อมDateคลาสแทนNSDateและCalenderแทนที่จะเป็นNSCalender

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

การใช้งาน:

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

ฉันได้รับข้อผิดพลาดที่ไม่ได้ประกาศDateเมื่อฉันลองใช้ในสนามเด็กเล่น
John Doe

1
มันทำงานให้ฉันที่นี่ คุณนำเข้า UIKit ด้วยimport UIKitหรือไม่?
เบ็น

2
วันที่และปฏิทินของ @ Ben ไม่ได้อยู่ใน UIKit ซึ่งอยู่ในมูลนิธิอย่างไรก็ตาม UIKit นำเข้ามูลนิธิ
Arbitur

4

คุณไม่จำเป็นต้องตั้งค่าส่วนประกอบให้เป็นศูนย์เพียงแค่เพิกเฉย:

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

2
"ใหม่" พร้อมใช้งาน: [calendar startOfDayForDate:date]แต่ไม่มี-endOfDayForDate:แต่น่าเสียดาย ...
Julian F. Weinert

4

สำหรับฉันไม่มีคำตอบที่นี่และที่อื่นใน stackoverflow ทำงานได้ เพื่อเริ่มต้นวันนี้ฉันทำสิ่งนี้

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

สังเกตสิ่งนี้[gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];และ[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];.

เมื่อสร้างปฏิทินปฏิทินจะเริ่มต้นด้วยเขตเวลาปัจจุบันและเมื่อวันที่ถูกดึงออกจากส่วนประกอบเนื่องจาก NSDate ไม่มีเขตเวลาวันที่จากเขตเวลาปัจจุบันจะถือเป็นเขตเวลา UTC ดังนั้นเราจึงต้องกำหนดเขตเวลาก่อนที่จะแยกส่วนประกอบและในภายหลังเมื่อแยกวันที่ออกจากส่วนประกอบเหล่านี้


4

สวิฟต์ 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โดยใช้* XCode8
Apple กำลังลบNSชื่อคลาสออกเพื่อให้NSDateสามารถเปลี่ยนเป็นDateสามารถสลับออกไปคุณอาจได้รับคำเตือนเกี่ยวกับคอมไพเลอร์หากคุณพยายามแคสต์โดยบอกว่าพวกเขาจะล้มเหลวเสมอ แต่จะทำงานได้ดีเมื่อคุณเรียกใช้งานในสนามเด็กเล่น

ฉันแทนที่NSDateรูปแบบข้อมูลหลักที่สร้างขึ้นด้วย แต่Dateก็ยังใช้งานได้

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

ใน Swift 3 ขึ้นไป

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

การใช้งาน:

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

3

ฉันคิดว่าวิธีที่รวบรัดที่สุดใน Swift มีดังนี้:

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

สมบูรณ์แบบ! ขอบคุณ!
Baran Emre

2

อีกวิธีหนึ่งในการรับผลลัพธ์:

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

วัตถุประสงค์ -C

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

2

เพื่อความรวดเร็ว 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!)")

1

เนื่องจากiOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+มีฟังก์ชันในตัวใน Foundation ซึ่งคุณสามารถใช้งานได้ทันที ไม่จำเป็นต้องใช้ฟังก์ชันของตัวเอง

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

ดังนั้นคุณสามารถใช้วิธีนี้:

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

ควรจำไว้ว่าสิ่งนี้ต้องคำนึงถึงเขตเวลาของอุปกรณ์ด้วย คุณสามารถตั้งค่า.timeZoneบนcalendarถ้าคุณต้องการที่จะมีเช่นโซน UTC

เชื่อมโยงไปยังหน้าเว็บอ้างอิงแอปเปิ้ล: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday


1

เพียงวิธีใช้อื่นdateInterval(of:start:interval:for:)ของCalendar

ในผลตอบแทนstartDateประกอบด้วยการเริ่มต้นของวันและintervalจำนวนวินาทีในวันนั้น

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

นี่คือสิ่งที่ฉันใช้กับ 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())

ใช้งานได้เหมือนมีเสน่ห์สำหรับฉัน คุณสามารถเพิ่มสิ่งนี้ลงในส่วนขยายสำหรับวันที่เริ่มต้นและวันที่สิ้นสุดDateได้อย่างไรก็ตามโปรดทราบว่าการเพิ่มส่วนขยายจะเพิ่มเวลาในการคอมไพล์ (เว้นแต่จะอยู่ในไฟล์เดียวกับคลาส) ดังนั้นหากคุณต้องการเพียงที่เดียวหรือในคลาสเดียว .. อย่าใช้นามสกุล.


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

เพียงสำหรับการอ้างอิงวิธีง่ายๆในการตั้งค่าเริ่มต้นและสิ้นสุดของวันในสวิฟท์ 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

หน่วยปฏิทินควรคิดเป็นช่วงเวลา เนื่องจาก iOS 10 Calendarมีวิธีการที่ดีสำหรับสิ่งนี้

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

คุณสามารถใช้วิธีการเดียวกันเพื่อเริ่มต้น / สิ้นสุดองค์ประกอบปฏิทินใด ๆ (สัปดาห์ / เดือน / ปี ฯลฯ )


สิ่งนี้ไม่ถูกต้อง day?.endประเมินเป็น 00:00 น. วันพรุ่งนี้ไม่ใช่ 23.59 น. คืนนี้
Casey Wagner
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.