NSDate beginning of day and end of day

IosNsdateNsdatecomponents

Ios Problem Overview


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

Ios Solutions


Solution 1 - Ios

Start Of Day / End Of Day — 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

Solution 2 - Ios

Swift 5 Simple and more precise answer.

Start time: 00:00:00

End time: 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)

Extra

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

Solution 3 - Ios

You are missing NSDayCalendarUnit in

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

Solution 4 - Ios

In iOS 8+ this is really convenient; you can do:

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

To get the end of day then just use the Calendar methods for 23 hours, 59 mins, 59 seconds, depending on how you define end of day.

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

Date Math

Apple iOS NSCalendar Documentation. (See Section: Calendrical Calculations)

NSCalendar methods discussed by NSHipster.

Solution 5 - Ios

My Swift extensions for 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
    }
}

Solution 6 - Ios

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

Usage:

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

Solution 7 - Ios

I think the most succinct way to do this in Swift is as follows:

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

Solution 8 - Ios

In Swift 3 and above

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

Usage:

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

Solution 9 - Ios

You don't have to set up the components to zero, just ignore them:

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

Solution 10 - Ios

For me none of the answers here and else where on stackoverflow worked. To get start of today i did this.

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

Note this [gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; and [components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];.

When a calendar is created it gets initialised with current timezone and when date is extracted from its components, since NSDate has no timezone, the date from current timezone is considered as UTC timezone. So we need to set the timezone before extracting components and later when extracting date from these components.

Solution 11 - Ios

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

Solution 12 - Ios

Swift3 Using *XCode8
Apple is removing the NS from the class name so that NSDate can be swapped out to Date. You may get a compiler warning if you try to cast them saying they will always fail, but they work fine when you run them in the playground.

I replaced my generated NSDate in core data model with Date and they still work.

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

Solution 13 - Ios

Objective-C

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

Solution 14 - Ios

You are missing NSDayCalendarUnit in the components.

Solution 15 - Ios

One more way to get result:

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

Solution 16 - Ios

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

Solution 17 - Ios

In Swift 5.3, both Calendar.current.startOfDay() and Calendar.current.date(bySettingHour:, minute:, second:, of:) are timezone specific. If you want your date to normalize to the same time regardless of timezone, you should use GMT time like this.

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

Solution 18 - Ios

Updating @Zelko's Answer to get the calendar:

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

Note:

It is very important to use the correct calendar when your app supports more regions

Solution 19 - Ios

Just another way using dateInterval(of:start:interval:for:) of Calendar and the dedicated DateInterval struct

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)

Solution 20 - Ios

Since iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ there is a built in function in the Foundation, which you can use out of the box. No need to implement own functions.

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

So you can use it this way:

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

It's worth to remember, that this takes upon consideration the device time zone. You can set .timeZone on calendar if you want to have eg UTC zone.

Link to the Apple reference pages: https://developer.apple.com/reference/foundation/nscalendar/1417161-startofday.

Solution 21 - Ios

This is what I use for 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())

Works like a charm for me. You could add this to an extension for start and end dates on Date, however keep in mind that adding an extension increases compile time (unless in the same file as the class), so if you only need it at one place or in one class... don't use an extension.

Solution 22 - Ios

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

Solution 23 - Ios

Just for reference, simple way to set Start and End of the day in 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)")

Solution 24 - Ios

Since the Calendar struct contains startOfDay(for:), I find it best to encapsulate an endOfDay(for:) method within an extension on Calendar rather than within Date.

The following code can be placed within a Playground file for quick execution.

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
    }

}

To see the formatted date, create a DateFormatter and print the output.

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

Solution 25 - Ios

Calendar units should be thought of as intervals. As of iOS 10 Calendar has some nice methods for this

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

You can use the same method, to get the start/end of any calendar component (week/month/year etc)

The caveat here is that there isn't a single point in time that can be defined as the end (given that we have a start). The above will give one second before the end of the day (23:59:59).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1028028View Question on Stackoverflow
Solution 1 - IosZelkoView Answer on Stackoverflow
Solution 2 - IosAugust LinView Answer on Stackoverflow
Solution 3 - IosJaanusSiimView Answer on Stackoverflow
Solution 4 - IosBryan BryceView Answer on Stackoverflow
Solution 5 - IosLibor ZapletalView Answer on Stackoverflow
Solution 6 - IosBenView Answer on Stackoverflow
Solution 7 - IosclosetCoderView Answer on Stackoverflow
Solution 8 - IosGurjit SinghView Answer on Stackoverflow
Solution 9 - IosMaxim LavrovView Answer on Stackoverflow
Solution 10 - IosVikram RaoView Answer on Stackoverflow
Solution 11 - IosJaseem AbbasView Answer on Stackoverflow
Solution 12 - IosJohn DoeView Answer on Stackoverflow
Solution 13 - IosJohnny RockexView Answer on Stackoverflow
Solution 14 - IosLombaXView Answer on Stackoverflow
Solution 15 - Iosk06aView Answer on Stackoverflow
Solution 16 - IosHardik ThakkarView Answer on Stackoverflow
Solution 17 - IosAppleSauce007View Answer on Stackoverflow
Solution 18 - IosMojtaba HosseiniView Answer on Stackoverflow
Solution 19 - IosvadianView Answer on Stackoverflow
Solution 20 - IosNatView Answer on Stackoverflow
Solution 21 - IosPaul PeelenView Answer on Stackoverflow
Solution 22 - IosBenjaminView Answer on Stackoverflow
Solution 23 - IosRenish DadhaniyaView Answer on Stackoverflow
Solution 24 - IosNick KohrnView Answer on Stackoverflow
Solution 25 - IosDavid ArveView Answer on Stackoverflow