NSDate beginning of day and end of day

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


}

When I call : [self endOfDay:[NSDate date]]; I get the first of the month ... Why is that? I use this two methods because I need an interval that is from the first second of the first date (beginningOfDay:date1) to the last second of the second date (endOfDay:Date2) ...

68499 次浏览

你错过了 NSDayCalendarUnit

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

组件中缺少 NSDayCalendarUnit

Start Of Day / End Of Day — Swift 5.7

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 startOfWeek: Date {
Calendar.current.dateComponents([.calendar, .yearForWeekOfYear, .weekOfYear], from: self).date!
}
    

var endOfWeek: Date {
var components = DateComponents()
components.weekOfYear = 1
components.second = -1
return Calendar.current.date(byAdding: components, to: startOfWeek)!
}
    

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 week = Start of next week minus 1 second
// End of month = Start of next month minus 1 second

您不必将组件设置为零,只需忽略它们:

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

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

还有一种方法可以得到结果:

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

对我来说,这里没有任何答案,其他的在堆栈溢出工作。为了今天的开始,我做了这个。

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 时区。因此,我们需要在提取组件之前和之后从这些组件提取日期时设置时区。

在 iOS8 + 中这真的很方便,你可以这样做:

let startOfDay: Date = Calendar.current.startOfDay(for: Date())

要得到一天的结束,只需使用日历方法23小时,59分钟,59秒,这取决于您如何定义一天的结束。

// Swift 5.0
let components = DateComponents(hour: 23, minute: 59, second: 59)
let endOfDay = Calendar.current.date(byAdding: components, to: startOfDay)

日期数学

苹果 iOS NSCalendar 文档 (见部分: 历法计算)

NSHipster 讨论的 NSCalendar 方法。

只是使用 CalendardateInterval(of:start:interval:for:)和专用的 日期间隔结构的另一种方法

On return startDate contains the start of the day and interval the number of seconds in the day.

func dateInterval(of date : Date) -> DateInterval {
var startDate = Date()
var interval : TimeInterval = 0.0
Calendar.current.dateInterval(of: .day, start: &startDate, interval: &interval, for: date)
return DateInterval(start: startDate, duration: interval-1)
}


let interval = dateInterval(of: Date())
print(interval.start, interval.end)

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

Swift 5.1 - XCode 11 with Date class instead of NSDate and Calender instead of 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

Swift3 Using *XCode8
苹果正在从类名中删除 NS,这样 NSDate就可以换成 Date。如果您试图强制转换它们,您可能会收到编译器警告,说它们总是会失败,但是当您在操场上运行它们时,它们工作得很好。

我用 Date代替了我在核心数据模型中生成的 NSDate,它们仍然可以工作。

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

由于 iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+有一个内置的功能在基金会,这是你可以使用开箱即用。不需要实现自己的函数。

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

So you can use it this way:

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

值得记住的是,这需要考虑设备的时区。你可以设置 .timeZonecalendar,如果你想有例如协调世界时区。

链接到苹果参考页面: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday

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

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

目标 C

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

为了迅捷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!)")

仅供参考,在 Swift 4 中设置 Start and End of the day 的简单方法,

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

这就是我在 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的开始和结束日期的扩展中,但是要记住,添加一个扩展会增加编译时间(除非在与类相同的文件中) ,所以如果你只需要它在一个地方或在一个类中... 不要使用扩展。

日历单位应该被认为是间隔

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

您可以使用相同的方法来获取任何日历组件(周/月/年等)的开始/结束

这里需要注意的是,没有一个单一的时间点可以被定义为结束(假设我们有一个开始)。以上将给一秒前结束一天(23:59:59)。

在 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

我认为在 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) ?? self
}
}

在 Swift 5.3中,Calendar.current.startOfDay ()和 Calendar.current.date (bySettingHour: ,minutes: ,second: ,of:)都是特定于时区的。如果您希望您的日期正常化为同一时间,而不管时区,您应该使用 GMT 时间这样。

// Normalize time of aDate to 12:00 GMT
let aDate = Date()
let twelveGMT = 12 + TimeZone.current.secondsFromGMT() / 3600
let normalizedDate = Calendar.current.date(bySettingHour: twelveGMT, minute: 0, second: 0, of: aDate)

由于 Calendar结构包含 startOfDay(for:),我发现最好将 endOfDay(for:)方法封装在 Calendar的扩展中,而不是在 Date中。

下面的代码可以放在 Playground 文件中以便快速执行。

import Foundation


extension Calendar {


func endOfDay(for date: Date) -> Date {


// Get the start of the date argument.
let dayStart = self.startOfDay(for: date)


// Add one day to the start of the day
// in order to get the start of the following day.
guard let nextDayStart = self.date(byAdding: .day, value: 1, to: dayStart) else {
preconditionFailure("Expected start of next day")
}


// Create date components that will subtract a single
// second from the start of the next day. This will
// allow you to get the last hour, last minute, and last
// second of the previous day, which is the day for the
// date argument that was passed to this method.
var components = DateComponents()
components.second = -1


// Add the date components to the date for the next
// day, which will perform the subtraction of the single
// second. This will return the end of the day for the date
// that was passed into this method.
guard let dayEnd = self.date(byAdding: components, to: nextDayStart) else {
preconditionFailure("Expected end of day")
}


// Simply return the date value.
return dayEnd
}


}

要查看格式化的日期,请创建一个 DateFormatter并打印输出。

let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .long
Calendar.current.endOfDay(for: Date()) // "Dec 31, 2020 at 11:59 PM"

更新@Zelko 的回答以获取日历:

extension Date {


func startOfDay(in calendar: Calendar = .current) -> Date {
calendar.startOfDay(for: self)
}


func endOfDay(in calendar: Calendar = .current) -> Date {
var components = DateComponents()
components.day = 1
components.second = -1
return calendar.date(byAdding: components, to: startOfDay(in: calendar))!
}


func startOfMonth(in calendar: Calendar = .current) -> Date {
let components = calendar.dateComponents([.year, .month], from: startOfDay(in: calendar))
return calendar.date(from: components)!
}


func endOfMonth(in calendar: Calendar = .current) -> Date {
var components = DateComponents()
components.month = 1
components.second = -1
return calendar.date(byAdding: components, to: startOfMonth(in: calendar))!
}
}

注:

当你的应用程序支持更多的区域时,使用正确的日历是非常重要的