ios Swift - trouble setting time with seconds at zero [duplicate] - ios

I have a date picker that returns me a NSdate value. And I want to have a date value of seconds set to 0. I have the code to do it in objective c as
NSTimeInterval time = floor([date timeIntervalSinceReferenceDate] / 60.0) * 60.0;
return [NSDate dateWithTimeIntervalSinceReferenceDate:time];
where date is the datepicker's date. So how to realise this in swift?

It is almost identical in Swift:
let date = NSDate()
let ti = floor(date.timeIntervalSinceReferenceDate/60.0) * 60.0
let date1 = NSDate(timeIntervalSinceReferenceDate: ti)
The same can be achieved with NSCalendar methods:
let cal = NSCalendar.currentCalendar()
var date2 : NSDate?
cal.rangeOfUnit(.Minute, startDate: &date2, interval: nil, forDate: date)
and this has the great advantage that it can easily be adapted for
larger time units like days, months, etc. which do not have a fixed
length (e.g. a day can have 23, 24, or 25 hours in regions with
daylight saving time).

Related

iOS Core Motion how to convert timestamp to Date?

I'm examining CMRecordedAccelerometerData and it has a timestamp, defined as:
The timestamp is the amount of time in seconds since the device
booted.
How do I convert timestamp from device last boot to NSDate?
For example, the system provides a CMRecordedAccelerometerData object with a timestamp value of: 1030958.895134
If I use any of the available reference frames (1970, reference date), I will get a wrong date, not in 2019. I want the real date when the event was recorded.
This answer comes a bit late I guess, but, first, you can get the boot time by subtracting the uptime ProcessInfo.processInfo.systemUptime from now, but otherwise from iOS 9+ ProcessInfo.processInfo.systemUptime has the date property startDate, which should be what you were after in the first place.
The timestamp is a TimeInterval, a typealias for Double that represents duration as a number of seconds. So you can convert TimeInterval to a Date by using NSDate's (timeIntervalSince1970:).
let myTimeInterval:TimeInterval = 1574660642
let dateNow = NSDate(timeIntervalSince1970: myTimeInterval) //will print "Nov 24, 2019 at 9:44 PM"
If you need to the date relative to the current date with the TimeInterval, you can use (timeInterval:since:).
var date = Date()
let timestampOfLastBoot: TimeInterval = 1572628813
let currentTimestamp: TimeInterval = NSDate().timeIntervalSince1970
let dateOfTimeStamp = Date(timeInterval: timestampOfLastBoot-currentTimestamp, since: date) //will print "Nov 1, 2019 at 10:20 AM"

Swift 2.1 DatePicker setDate does not set date to current day and specified time

I am trying to set the minimum date to the current day on the date picker and then for the sake of user experience, set the time to 7pm or 19:00. For some reason it doesn't seem to be working. The minimum date setting works but the time doesn't get set. If I remove the minimum date line, the time gets set to 7pm, but strangely, the date gets set to Monday, Jan 1. Which isn't even this year.
Here's my code below:
datePicker.minimumDate = NSDate()
let calendar:NSCalendar = NSCalendar.currentCalendar()
let components = calendar.components([NSCalendarUnit.Hour, NSCalendarUnit.Minute], fromDate: NSDate())
components.hour = 19
components.minute = 00
datePicker.setDate(calendar.dateFromComponents(components)!, animated: true)
What am I doing wrong here?
Split that last line into:
let date = calendar.dateFromComponents(components)!
datePicker.setDate(date, animated: true)
Then look at the value of date. You'll find it is probably January 1, 2000 at the desired time.
Fix this by adding the year, month, and day components to:
let components = calendar.components([NSCalendarUnit.Hour, NSCalendarUnit.Minute], fromDate: NSDate())
In other words, you need:
let components = calendar.components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute], fromDate: NSDate())

where is timeIntervalSince1970 property in swift

I am trying to get the current milliseconds and according to all the questions on Google, i should use timeIntervalSince1970 property of NSDate
however i already did this:
var startTime = NSData()
and then
startTime. timeIntervalSince1970
and
startTime. timeIntervalSince1970()
but it seems there is no property anymore, right?
if yes, what is the replacement please?
The error is: NSDate not NSData.
Also there should not be space after the "."?
var startTime = NSDate()
let interval = startTime.timeIntervalSince1970
From Apple docs:
var timeIntervalSince1970: NSTimeInterval { get }
This property’s value is negative if the date object is earlier than January 1, 1970 at 12:00 a.m. GMT.

How to get weekly range

I'm new to developing iOS apps and I am facing problem getting a weekly date range.
Basically, what I was trying to achieve is to get a list of items between a specified range of date between daily, weekly and monthly. Daily would be fixing the date whereas monthly just change the month. But I couldn't achieve weekly like from (7/12/14) which is a Sunday to (13/12/14) Saturday, and (14/12/14) Sunday to (20/12/14) Saturday where Sunday is the first weekday.
let now = NSDate()
var startDate: NSDate? = nil
var duration: NSTimeInterval = 0
// or .DayCalendarUnit, .MonthCalendarUnit
NSCalendar.currentCalendar().rangeOfUnit(.WeekCalendarUnit, startDate: &startDate, interval: &duration, forDate: now);
let endDate = startDate?.dateByAddingTimeInterval(duration)

How to set seconds to zero for NSDate

I'm trying to get NSDate from UIDatePicker, but it constantly returns me a date time with trailing 20 seconds. How can I manually set NSDate's second to zero?
NSDate is immutable, so you cannot modify its time. But you can create a new date object that snaps to the nearest minute:
NSTimeInterval time = floor([date timeIntervalSinceReferenceDate] / 60.0) * 60.0;
NSDate *minute = [NSDate dateWithTimeIntervalSinceReferenceDate:time];
Edit to answer Uli's comment
The reference date for NSDate is January 1, 2001, 0:00 GMT. There have been two leap seconds added since then: 2005 and 2010, so the value returned by [NSDate timeIntervalSinceReferenceDate] should be off by two seconds.
This is not the case: timeIntervalSinceReferenceDate is exactly synchronous to the wall time.
When answering the question I did not make sure that this is actually true. I just assumed that Mac OS would behave as UNIX time (1970 epoch) does: POSIX guarantees that each day starts at a multiple of 86,400 seconds.
Looking at the values returned from NSDate this assumption seems to be correct but it sure would be nice to find a definite (documented) statement of that.
You can't directly manipulate the NSTimeInterval since that is the distance in seconds since the reference date, which isn't guaranteed to be a 00-second-time when divided by 60. After all, leap seconds may have been inserted to adjust for differences between solar time and UTC. Each leap second would throw you off by 1. What I do to fix the seconds of my date to 0 is:
NSDate * startDateTime = [NSDate date];
NSDateComponents * startSeconds = [[NSCalendar currentCalendar] components: NSSecondCalendarUnit fromDate: startDateTime];
startDateTime = [NSDate dateWithTimeIntervalSinceReferenceDate: [startDateTime timeIntervalSinceReferenceDate] -[startSeconds second]];
This takes care of leap seconds. I guess an even cleaner way would be to use -dateByAddingComponents:
NSDate * startDateTime = [NSDate date];
NSDateComponents * startSeconds = [[NSCalendar currentCalendar] components: NSSecondCalendarUnit fromDate: startDateTime];
[startSeconds setSecond: -[startSeconds second]];
startDateTime = [[NSCalendar currentCalendar] dateByAddingComponents: startSeconds toDate: startDateTime options: 0];
That way you're guaranteed that whatever special things -dateByAddingComponents: takes care of is accounted for as well.
Here is a Swift extension for anyone who is interested:
extension Date {
public mutating func floorSeconds() {
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: self)
self = calendar.date(from: components) ?? self // you can handle nil however you choose, probably safe to force unwrap in most cases anyway
}
}
Example usage:
let date = Date()
date.floorSeconds()
Using DateComponents is much more robust than adding a time interval to a date.
Although this is an old question and Uli has given the "correct" answer, the simplest solution IMHO is to just subtract the seconds from the date, as obtained from the calendar. Mind that this may still leave milliseconds in place.
NSDate *date = [NSDate date];
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSCalendarUnitSecond
fromDate:date];
date = [date dateByAddingTimeInterval:-comp.second];
NSDate records a single moment in time. If what you want to do is store a specific day, don't use NSDate. You'll get lots of unexpected head-aches related to time-zones, daylight savings time e.tc.
One alternative solution is to store the day as an integer in quasi-ISO standard format, like 20110915 for the 15th of September, 2011. This is guaranteed to sort in the same way as NSDate would sort.
Here is an extension to do this in Swift:
extension NSDate {
func truncateSeconds() -> NSDate {
let roundedTime = floor(self.timeIntervalSinceReferenceDate / 60) * 60
return NSDate(timeIntervalSinceReferenceDate: roundedTime)
}
}
Also Swift ...
extension Date {
func floored() -> Date {
let flooredSeconds = DateComponents(second: 0, nanosecond: 0)
return Calendar.current.nextDate(after: self,
matching: flooredSeconds,
matchingPolicy: .strict,
direction: Calendar.SearchDirection.backward)!
}
}

Resources