1

I am working on a bit of code at present which will return all the days in between 2 dates. The method will then return 2 dates, one date with the time set to the start of the day, and one at the end of the day. This is required for a api call I need to make which returns some data for that day.

However I am having an issue caused by daylight savings, as the clocks go back on the 26th, I am not getting the correct dates returned for 25th - 26th. Below is my code

func dateTesting()
    {
        let day = -86400

        let startDate = Date().addingTimeInterval(TimeInterval(day * 5))
        let endDate = Date()

        let tuples = daysBetweenDates(startDate: startDate, endDate: endDate)
        print(tuples)
    }

    func daysBetweenDates(startDate: Date, endDate: Date) -> [(startDate: Date, endDate: Date)]
    {
        let calendar = Calendar.current

        let components = calendar.dateComponents([.day, .month,.year], from: startDate)
        let components2 = calendar.dateComponents([.day,.month,.year], from: endDate)

        let daysDifferent = abs(components.day! - components2.day!)

        var tupleList:[(startDate: Date, endDate: Date)] = []

        let day = -86400
        for index in stride(from: daysDifferent, to: 0, by: -1) {
            let date = Date().addingTimeInterval(TimeInterval(day * index))
            let tuple = createFetchRequestDates(date: date)
            tupleList.append(tuple)
        }

        return tupleList
    }

    func createFetchRequestDates(date : Date) -> (startDate: Date, endDate: Date)
    {
        let calendar = Calendar.current
        var components = calendar.dateComponents([.hour, .minute, .day, .month, .year], from: date)
        var components2 = calendar.dateComponents([.hour, .minute, .day, .month, .year], from: date)

        components.hour = 1
        components.minute = 0

        components2.hour = 24
        components2.minute = 59

        let start = calendar.date(from: components)
        let end = calendar.date(from: components2)

        //debugging
        print(date)
        print(start!)
        print(end!)
        print(" ")

        let tuple = (startDate : start!, endDate : end!)

        return tuple
    }

In the createFetchRequestDates code, when I print out the codes for any non daylight savings day code, it works as expected, i.e.

2017-03-29 09:52:37 +0000
2017-03-29 00:00:00 +0000
2017-03-29 23:59:00 +0000

However when the code is called between the 25th-26th when daylight savings occurred, the following is printed

2017-03-25 09:52:37 +0000
2017-03-25 01:00:00 +0000
2017-03-26 00:59:00 +0000

2017-03-26 09:52:37 +0000
2017-03-26 01:00:00 +0000
2017-03-26 23:59:00 +0000

Does anyone know the best way to fix this? I want to make sure I get the correct start and end time of each day, and the clocks going back is causing a bit of an issue.

I could do an if statement to check if the particular date is daylight savings day, and then modify my components code for those particular days. However I was hoping there would perhaps be a cleaner approach.

Any help would be much appreciated

Edit:

Just to give another example of the problem

 let calendar = Calendar.current
        var components = calendar.dateComponents([.day, .month,.year], from: Date())
        var components2 = calendar.dateComponents([.day, .month,.year], from: Date())

        components.day = 26
        components.hour = 0
        components.minute = 0

        components2.day = 26
        components2.hour = 23
        components2.minute = 59

        print(calendar.date(from: components)!)
        print(calendar.date(from: components2)!)

This is printed out

2017-03-26 00:00:00 +0000
2017-03-26 22:59:00 +0000

I want it to print out 23:59:00, but the daylight savings knocks it back an hour unfortunately.

Edit 2:

Here is example of the updated code

func daysBetweenDates(startDate: Date, endDate: Date) -> [(startDate: Date, endDate: Date)]
    {
        let calendar = Calendar.current

        let components = calendar.dateComponents([.day, .month,.year], from: startDate)
        let components2 = calendar.dateComponents([.day,.month,.year], from: endDate)

        let daysDifferent = abs(components.day! - components2.day!)

        var tupleList:[(startDate: Date, endDate: Date)] = []

        for index in stride(from: daysDifferent, to: 0, by: -1) {

            let calendar = Calendar.current
            var components = calendar.dateComponents([.hour, .minute, .day, .month, .year], from: Date())

            components.day = components.day! - index

            let date = calendar.date(from: components)
            let tuple = createFetchRequestDates(date: date!)
            tupleList.append(tuple)
        }

        return tupleList
    }

So instead of subtracting 86400 seconds, I instead use components and just subtract one full day.

AdamM
  • 4,400
  • 5
  • 49
  • 95
  • 2
    **Don't** use 86400 seconds as the duration of a day. See http://stackoverflow.com/questions/32536612/swift-print-all-dates-between-two-nsdate for an example how to enumerate all days between 2 dates. – Martin R Mar 30 '17 at 10:03
  • Possible duplicate of [Swift: Print all dates between two NSDate()](http://stackoverflow.com/questions/32536612/swift-print-all-dates-between-two-nsdate) – Martin R Mar 30 '17 at 10:07
  • Tried those solutions as well, the daylight savings issue still occurs. – AdamM Mar 30 '17 at 10:31
  • Can you add your updated code? I am fairly sure that it should work correctly if you use `calendar.date(byAdding: .day, value: -1, to: date)` instead of subtracting 86400 seconds. – Martin R Mar 30 '17 at 10:35
  • Also note that printing a `Date` always uses UTC, not your local timezone. – Martin R Mar 30 '17 at 10:36
  • In the Belfast timezone, "2017-03-26 00:00:00" local time is "2017-03-26 00:00:00 UTC", and "2017-03-26 23:59:00" is "2017-03-26 22:59:00 UTC". So your results are *correct.* – Martin R Mar 30 '17 at 10:41
  • This code will be run in more than just Europe, so do I need to add in any additional checks? Different parts of the World can have different daylight savings. Do you think this will cause any issues? – AdamM Mar 30 '17 at 10:52
  • 1
    I do not see any. Just note that the calendrical calculations use the local timezone by default. – Martin R Mar 30 '17 at 10:54
  • Well, I am not sure if this deserves another answer. The calendrical calculations are already answered in http://stackoverflow.com/questions/32536612/swift-print-all-dates-between-two-nsdate, and the "UTC printing problem" has been answered repeatedly, such as http://stackoverflow.com/questions/8466744/getting-date-from-nsdate-date-off-by-a-few-hours, http://stackoverflow.com/questions/30083756/ios-nsdate-returns-incorrect-time, http://stackoverflow.com/questions/39937019/nsdate-or-date-shows-the-wrong-time. – Martin R Mar 30 '17 at 11:02

0 Answers0