NSD ngày đầu ngày và cuối ngày


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

}

Khi tôi gọi: [self endOfDay: [NSDate date]]; Tôi nhận được đầu tiên của tháng ... Tại sao vậy? Tôi sử dụng hai phương pháp này vì tôi cần một khoảng thời gian từ giây đầu tiên của ngày đầu tiên (beginOfDay: date1) đến giây cuối cùng của ngày thứ hai (endOfDay: Date2) ...


2
Nếu bạn muốn đặt giờ thành 0 giờ UTC, một cách dễ dàng hơn để lấy timeIntervalSince ..., hãy cắt bớt giờ, sau đó chuyển đổi trở lại NSDate. Và điều này sẽ hoạt động cho một múi giờ khác nếu trước tiên bạn điều chỉnh khoảng thời gian bằng giâyFromGMT của múi giờ, sau đó điều chỉnh theo cách ngược lại sau khi cắt bớt. (Kết thúc ngày rõ ràng là 23: 59: 59,999 sau, có thể được nhận bằng bổ sung đơn giản trong khi bạn có khoảng thời gian.)
Hot Licks

Việc chỉ định "cuối ngày" là một số thời gian tùy ý trước khi kết thúc thực tế (trong trường hợp này là một giây) có vẻ giống như một công thức cho phần mềm trục trặc. Nếu bạn sử dụng 1 ms, sự cố sẽ ít thường xuyên hơn. Hoặc bạn có thể sử dụng 23 giờ để mọi lỗi có nhiều khả năng bị bắt hơn. :-)
Edward Brey

Câu trả lời:


33

Bạn đang thiếu NSDayCalendarUnittrong

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

1
Tôi có một hành vi lạ là nếu tôi thêm thành phần ngày, tôi nhận được 23:00 của ngày hôm trước.
Mike M,

3
Múi giờ sử dụng @Mike: components.timeZone = [NSTimeZone timeZoneWithName: @ "GMT"];
dimaxyu

@dimaxyu nói đúng. Nhanh chóng của nó: components.timeZone = NSTimeZone (tên: "GMT")
Tom Bevelander

220

Bắt đầu ngày / Cuối ngày - 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, NSMonthCalendarUnitNSDayCalendarUnitđã bị phản đối như iOS 8. Sử dụng NSCalendarUnitYear, NSCalendarUnitMonthNSCalendarUnitDaythay vào đó!
T Blank

6
Để bắt đầu ngày mới, hãy sử dụng [[NSCalendar currentCalendar] startOfDayForDate: ...] cho iOS8 +
GingerBreadMane

5
Điều này trả về startOfDay trong múi giờ hiện tại! NSDate dự kiến ​​sẽ là UTC nhưng công cụ chuyển đổi này trả về thời gian đã sửa cho múi giờ mặc định.
Tom Bevelander

3
Tại sao endOfDay là tùy chọn? Có bất kỳ tình huống nào mà startOfDay không phải là nil, trong khi endOfDay có thể là nil không?
Mansurov Ruslan

1
Vì vậy, tùy thuộc vào cách bạn sử dụng điều này, bạn lưu ý khoảng cách một giây giữa đầu và đầu ngày developer.apple.com/documentation/foundation/nsdate/…
atlex2

29

Swift 5 Câu trả lời đơn giản và chính xác hơn.

Thời gian bắt đầu: 00:00:00

Thời gian kết thúc: 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)

Thêm

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
Làm thế nào là điều này khác với let dateAtEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())?
Andres Canella

1
Không khác nhau .
Tháng 8 Lin

21

Trong iOS 8+, điều này thực sự thuận tiện; bạn có thể làm:

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

Để có được thời gian cuối ngày, chỉ cần sử dụng các phương pháp NSCalendar trong 23 giờ, 59 phút, 59 giây, tùy thuộc vào cách bạn xác định thời gian cuối ngày.

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

Toán ngày tháng

Tài liệu Apple iOS NSCalendar . (Xem Phần: Tính toán lịch )

Các phương pháp NSCalendar được NSHipster thảo luận .


17

Tiện ích mở rộng Swift của tôi cho 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
    }
}

Bạn chỉ có thể thiết lập thứ hai để -1 và nhận được cùng mà không sử dụng dateByAddingTimeInterval
Bến Sinclair

để tránh các vấn đề về múi giờ, hãy thêm: components.timeZone = NSTimeZone (tên: "GMT")
Tom Bevelander

12

Swift 5.1 - XCode 11 với Datelớp thay vì NSDateCalenderthay vì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))!
    }
}

Sử dụng:

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

Tôi nhận được lỗi không khai báo loại Datekhi tôi thử nó ở sân chơi
John Doe

1
Nó làm việc cho tôi ở đây. Bạn đã nhập UIKit với import UIKit?
Ben

2
@Ben Date and Calendar không có trong UIKit, nó nằm trong Foundation, tuy nhiên UIKit nhập Foundation
Arbitur 17/12/18

4

Bạn không cần phải thiết lập các thành phần bằng 0, chỉ cần bỏ qua chúng:

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

2
"Mới" có sẵn:, [calendar startOfDayForDate:date]nhưng không có -endOfDayForDate:, rất tiếc ...
Julian F. Weinert,

4

Đối với tôi không có câu trả lời nào ở đây và những nơi khác trên stackoverflow hoạt động. Để bắt đầu ngày hôm nay, tôi đã làm điều này.

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

Lưu ý điều này [gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];.

Khi lịch được tạo, lịch sẽ được khởi tạo với múi giờ hiện tại và khi ngày được trích xuất từ ​​các thành phần của nó, vì NSDate không có múi giờ, ngày từ múi giờ hiện tại được coi là múi giờ UTC. Vì vậy, chúng ta cần đặt múi giờ trước khi giải nén các thành phần và sau đó khi trích xuất ngày từ các thành phần này.


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 Sử dụng * XCode8
Apple sẽ xóa tên NSkhỏi tên lớp để NSDatecó thể hoán đổi thànhDate . Bạn có thể nhận được cảnh báo trình biên dịch nếu bạn cố truyền chúng nói rằng chúng sẽ luôn thất bại, nhưng chúng hoạt động tốt khi bạn chạy chúng trong sân chơi.

Tôi đã thay thế NSDatemô hình dữ liệu cốt lõi được tạo của mình bằng Datevà chúng vẫn hoạt động.

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

Trong Swift 3 trở lên

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

Sử dụng:

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

2

Một cách nữa để nhận được kết quả:

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

Bạn đang thiếu NSDayCalendarUnittrong các thành phần.


2

Objective-C

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

2

Đối với nhanh 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

Tôi nghĩ cách ngắn gọn nhất để làm điều này trong Swift là như sau:

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

Thật hoàn hảo! Cám ơn!
Baran Emre

1

iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+có một chức năng được tích hợp sẵn trong Foundation, bạn có thể sử dụng ngay lập tức. Không cần thực hiện các chức năng riêng.

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

Vì vậy, bạn có thể sử dụng nó theo cách này:

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

Cần phải nhớ rằng điều này có tính đến múi giờ của thiết bị. Bạn có thể .timeZonebật calendarnếu bạn muốn có vùng UTC chẳng hạn.

Liên kết đến các trang tham khảo của Apple: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday .


1

Chỉ là một cách sử dụng dateInterval(of:start:interval:for:)củaCalendar

Ngược lại startDatechứa đầu ngày và intervalsố giây trong ngày.

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

Đây là những gì tôi sử dụng cho 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())

Công việc như một cái duyên đối với tôi. Bạn có thể thêm phần mở rộng này vào phần mở rộng cho ngày bắt đầu và ngày kết thúc Date, tuy nhiên, hãy nhớ rằng việc thêm phần mở rộng sẽ làm tăng thời gian biên dịch (trừ khi trong cùng một tệp với lớp), vì vậy nếu bạn chỉ cần nó ở một nơi hoặc trong một lớp. .. không sử dụng tiện ích mở rộng.


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

Chỉ để tham khảo, cách đơn giản để đặt Bắt đầu và Kết thúc một ngày trong 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

Đơn vị lịch nên được coi là khoảng thời gian. Kể từ iOS 10 Calendarcó một số phương pháp hay cho việc này

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

Bạn có thể sử dụng cùng một phương pháp, để bắt đầu / kết thúc bất kỳ thành phần lịch nào (tuần / tháng / năm, v.v.)


Điều này là không đúng. day?.endđánh giá là 12:00 sáng ngày mai, không phải 11:59 tối nay.
Casey Wagner
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.