Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 3 Easy way to truncate Date to start of the day/month/year

Is there any easy way to truncate date like we can do in Oracle Database? For example, I need to set value starting from midnight. In Oracle I can do TRUNC(SYSDATE). But I cannot see similar way to do it in Swift. I checked StackOverflow and saw some examples with DateFormatter, Date Components with converting Date to String. I have also seen this question, but didn't understand how to handle Date (not NSDate) type and i

But I don't need String values. And I would like to avoid converting to string and back to Date. I just want to get three values:

Start of the current date (just like we do TRUNC(SYSDATE) in Oracle)

Start of the month (just like we do TRUNC(SYSDATE, 'MONTH') in Oracle)

Start of the year (just like we do TRUNC(SYSDATE, 'YEAR') in Oracle)

I tried this, but it does not return midnight:

let comp: DateComponents = Calendar.current.dateComponents([.year, .month, .day], from: Date())
let truncated = Calendar.current.date(from: comp)!

enter image description here

What should I do?

like image 283
DJ-Glock Avatar asked Jun 14 '17 20:06

DJ-Glock


2 Answers

Calendar has dedicated methods:

  • Start of the day

      let truncated = Calendar.current.startOfDay(for: Date())
    
  • Start of the month

      let now = Date()
      var startOfMonth = now
      var timeInterval : TimeInterval = 0.0
      Calendar.current.dateInterval(of: .month, start: &startOfMonth, interval: &timeInterval, for: now)
    
      print(startOfMonth)
    
  • Start of the year

      let now = Date()
      var startOfYear = now
      var timeInterval : TimeInterval = 0.0
      Calendar.current.dateInterval(of: .year, start: &startOfYear, interval: &timeInterval, for: now)
    
      print(startOfYear)
    

Or as Date extension

extension Date {
    
    func startOf(_ dateComponent : Calendar.Component) -> Date {
        var calendar = Calendar.current
        calendar.timeZone = TimeZone(secondsFromGMT: 0)!
        var startOfComponent = self
        var timeInterval : TimeInterval = 0.0
        calendar.dateInterval(of: dateComponent, start: &startOfComponent, interval: &timeInterval, for: now)
        return startOfComponent
    }
}

let now = Date()

let startOfDay = now.startOf(.day)
let startOfMonth = now.startOf(.month)
let startOfYear = now.startOf(.year)

Regarding the time zone issue you can set the time zone of the current calendar accordingly.

like image 171
vadian Avatar answered Oct 20 '22 13:10

vadian


Note the +0000 at the end of the time in your sample.

The start of the day where? I updated the sample to show what you want.

var comp: DateComponents = Calendar.current.dateComponents([.year, .month, .day], from: Date())
comp.timeZone = TimeZone(abbreviation: "UTC")!
let truncated = Calendar.current.date(from: comp)!
print(truncated)

It prints 2017-06-14 00:00:00 +0000. Again, note the +0000 at the end.

By default the timezone is set to be the current timezone and the hour, minute, and second are 0 in that timezone.


I will assume that you want the current timezone. With that stipulation, your code is correct.

like image 30
Jeffery Thomas Avatar answered Oct 20 '22 15:10

Jeffery Thomas