3

First my date is in string format as : "06-04-2017 06:28:17 PM"

And then i converted to Date() using:

let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy hh:mm:ss a"
formatter.timeZone = TimeZone(abbreviation: "GMT")
let startdate = formatter.date(from: sdate!)
print(startdate)

This is the output Date from above: startdate = 2017-04-06 18:28:17 +0000

But when I try to set my minute to value 0 with the following code . I get my day changed .

let calender = Calendar.current
calendar.timeZone = TimeZone(abbreviation: "UTC")!
let date =  calender.date(bySettingHour: Int(hour)!, minute: 00, second: 00, of: startdate!)
print(date)

OUTPUT: 2017-04-07 12:15:00 +0000

My timezone is +5:45 , after I am setting that timezone . I am getting the same bug .

Any help . Highly appreciated.

With the following code I get the date same :

let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy hh:mm:ss a"
formatter.timeZone = TimeZone(abbreviation: "GMT")
let startdate = formatter.date(from: sdate!)
print(startdate)

**But I can't set it's minute to 0 here. **

user3804063
  • 809
  • 1
  • 14
  • 32
  • First don't print the Date and don't mess with the timeZone – Leo Dabus Jun 06 '17 at 19:52
  • If you need to check your date description use `yourDate.description(withLocale: .current)` – Leo Dabus Jun 06 '17 at 19:54
  • @LeoDabus that didn't help – user3804063 Jun 06 '17 at 20:00
  • What exactly do you need and why ? midnight at your current location or at zero seconds from GMT? – Leo Dabus Jun 06 '17 at 20:01
  • BTW if you need a date time insensitive you should use noon instead of midnight. And it should be noon at the current timezone – Leo Dabus Jun 06 '17 at 20:02
  • check this https://stackoverflow.com/a/28016692/2303865 and https://stackoverflow.com/a/37759264/2303865 – Leo Dabus Jun 06 '17 at 20:04
  • Again you shouldn't change your dateFormatter timezone. Just remove `formatter.timeZone = TimeZone(abbreviation: "GMT")` from your code. Considering that if you have a date string without the timezone info it is inferred that this date is at current timezone which is the default for DateFormatter timezone property – Leo Dabus Jun 06 '17 at 21:30
  • You shouldn't mess with your calendar timezone neither – Leo Dabus Jun 06 '17 at 21:33

4 Answers4

7

Swift 5

This solution just zeros the minute and second without messing with the hour.

extension Date {

    func startOfHour() -> Date?
    {
        let calendar = Calendar.current

        var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: self)

        components.minute = 0
        components.second = 0

        return calendar.date(from: components)
    }

}

Use:

Date().startOfHour

Printout:

Date: 2019-09-05 15:09:57 +0000

Date Start of Hour: Optional(2019-09-05 15:00:00 +0000)

trishcode
  • 3,299
  • 1
  • 18
  • 25
3

First, your question is missing the part where you get the hour parameter passed in the second snippet.

Second, you should use the right method from calendar to just set one component :

let roundedDate = Calendar.current.date(bySetting: .minute, value: 0, of: <# youDateObject #>)
Dulgan
  • 6,674
  • 3
  • 41
  • 46
  • 1
    Note that this method can result in changes to higher or coupled components as well. Setting `.minute` to `0` can for example cause an incrementation of `.hour`. – Breiby Apr 28 '21 at 11:15
1

Sorry I'm writing from the mobile so the code could be not the exact one but you will find the functions easily.

Before you print the date, convert it to date components using calendar; then set the dateComponents.minute value to 0 and reconvert it into a date:

let dateComponents = Calendar.current.dateComponents(fromDate: yourDate)
dateComponents.minute = 0
let finishedDate = Calendar.current.date(fromComponents: dateComponents)
print(finishedDate)

Oh yeah and I recommend to set the time zone to TimeZone.current unless you want to use a specific time zone only!

Caleb Kleveter
  • 11,170
  • 8
  • 62
  • 92
Carl Henretti
  • 457
  • 2
  • 7
  • 17
0

I don't get what your goal is with those timezones. If you just want to round the date you have as a string down to the latest full hour, this would be a way to get there:

extension Date {

    public init?(fromStringToBeRounded dateString: String) {
        let formatter = DateFormatter()
        formatter.dateFormat = "dd-MM-yyyy hh:mm:ss a"
        if let startdate = formatter.date(from: sdate) {
            let components = Calendar.current.dateComponents([.year, .month, .day, .hour], from: startdate)
            if let adjustedDate = Calendar.current.date(from: components) {
                self = adjustedDate
            } else { return nil }
        } else { return nil }
    }

}

let sdate = "06-04-2017 06:28:17 PM"
Date(fromStringToBeRounded: sdate)! // In production code you better safely unwrap this

Let me know what your intent is with the timezone conversion and I'll happily adjust the code above.

Benno Kress
  • 2,637
  • 27
  • 39