Swift ios date as milliseconds Double or UInt64? - swift

I'm not iOS developer but started learning Swift.
I try to convert some logic from Android project to iOS.
I have the following method:
func addGroupItemSample(sample : WmGroupItemSample){ // some custom class
var seconds: NSTimeInterval = NSDate().timeIntervalSince1970
var cuttDate:Double = seconds*1000;
var sampleDate: UInt64 = sample.getStartDate(); // <-- problematic place
if(sampleDate > cuttDate){
// ....
}
}
From the method above you can see that sample.getStartDate() returns type UInt64.
I thought it's like long in Java: System.currentTimeMillis()
But current time in milliseconds defined as Double.
Is it a proper way to mix Double and UInt64 or do I need to represent all milliseconds as Double only?
Thanks,

in iOS it is better to use double, but if you want to easy port your code and keep it consistent you can try this:
func currentTimeMillis() -> Int64{
let nowDouble = NSDate().timeIntervalSince1970
return Int64(nowDouble*1000)
}

Swift does not allow comparing different types.
seconds is a Double floating point value in seconds with sub-second accuracy.
sampleDate is a UInt64 but the units are not given.
sampleDate needs be converted to a Double floating point value with units of seconds.
var sampleDate: Double = Double(sample.getStartDate())
Then they can be compared:
if(sampleDate > cuttDate){}

Here's an alternative version, for Swift 3:
/// Method to get Unix-style time (Java variant), i.e., time since 1970 in milliseconds. This
/// copied from here: http://stackoverflow.com/a/24655601/253938 and here:
/// http://stackoverflow.com/a/7885923/253938
/// (This should give good performance according to this:
/// http://stackoverflow.com/a/12020300/253938 )
///
/// Note that it is possible that multiple calls to this method and computing the difference may
/// occasionally give problematic results, like an apparently negative interval or a major jump
/// forward in time. This is because system time occasionally gets updated due to synchronization
/// with a time source on the network (maybe "leap second"), or user setting the clock.
public static func currentTimeMillis() -> Int64 {
var darwinTime : timeval = timeval(tv_sec: 0, tv_usec: 0)
gettimeofday(&darwinTime, nil)
return (Int64(darwinTime.tv_sec) * 1000) + Int64(darwinTime.tv_usec / 1000)
}

func get_microtime() -> Int64{
let nowDouble = NSDate().timeIntervalSince1970
return Int64(nowDouble*1000)
}
Working fine

Simple one-line code to get time token in UInt64
let time = UInt64(Date().timeIntervalSince1970 * 1000)
print(time) <----- prints time in UInt64
Additional tip:
Looking for timestamp with 10 Digit milliseconds since 1970 for API call then
let timeStamp = Date().timeIntervalSince1970
print(timeStamp) <-- prints current time stamp

Related

CMLogItem timestamp: Why so complicated?

I receive a CMLogItem from a CoreMotion query in swift (could be accelerometer, gyroscope). Now, I want to get the timestamp of that sample, preferably as a Date() object. CMLogItems have a property .timestamp of type TimeInterval.
The documentation tells me the following:
The CMLogItem class defines a read-only timestamp property that
records the time a motion-event measurement was taken.
However, I am not sure how to convert this timestamp to a Date() object because I dont know what the timestamp is referring to.
Another documentation says:
The timestamp is the amount of time in seconds since the device
booted.
But this seems really weird and I dont understand why apple would create such an inconsistent and complicated API.
Proper answer is:
extension CMLogItem {
static let bootTime = Date(timeIntervalSinceNow: -ProcessInfo.processInfo.systemUptime)
func startTime() -> Date {
return CMLogItem.bootTime.addingTimeInterval(self.timestamp)
}
}
This gives us stable, monotonic results, which is not a case, when bootTime is computed every time startTime is called.
I think I figured it out.
The documentation is just wrong here.
It is not the "time in seconds since the device booted" — it is indeed the time since their reference date.
Fix:
extension CMLogItem {
func startTime() -> Date {
#if os(watchOS)
return Date(timeIntervalSinceReferenceDate: self.timestamp)
#else
let systemRebootTime = Date(timeIntervalSinceNow: -ProcessInfo.processInfo.systemUptime)
return systemRebootTime.addingTimeInterval(self.timestamp)
#endif
}
}

Swift - Type of variable returned from DispatchTime.now()

If I need to save the value of DispatchTime.now() to access it outside of the function in which it was called, what is the variable type?
Edit: the variable type is DispatchTime but I see no way to save that value as a variable so I can pass it along to another view controller in prepare(for segue) or use it across functions.
var t = DispatchTime [Expected member name or constructor call after type name]
var t = DispatchTime() [missing argument for parameter 'uptimeNanoseconds' in call]
var t = DispatchTime.self (no error, but when later trying t = DispatchTime.now() ['Cannot assign value of type 'DispatchTime' to type 'DispatchTime.Type'])
You can store DispatchTime as a variable. However if you need to store it somewhere outside the app's memory (some cache etc) you should take a look at this property of DispatchTime:
public let rawValue: dispatch_time_t
This is it's raw value in nanoseconds. From documentation (https://developer.apple.com/reference/dispatch/dispatch_time_t) you can see that it's of type UInt64. And to make everything even better, you can initialize DispatchTime with this method:
DispatchTime(uptimeNanoseconds: <UInt64>)
That way you can store the raw value of your DispatchTime anywhere you want.
Figured out how to do this, but no longer using DispatchTime in my project.
Can set the variable like this:
var t = DispatchTime(uptimeNanoseconds: 0)
And then later fill the variable with the current time: t = DispatchTime.now()
This method was not giving me a correct number of seconds when trying to use:
let nanoTime = endingTime.uptimeNanoseconds - startTime.uptimeNanoseconds
let timeInterval = Double(nanoTime) / 1_000_000_000
I've instead gone back to using CFAbsoluteTime() variables and setting their value to CFAbsoluteTimeGetCurrent() upon start and stop.
That way totalTime = endTime - startTime gives me the correct number of seconds

In Swift what exactly is the difference between a function that returns a value and one that does not?

Here is some code that I am using in my program
func getDate() {
getTimeRightNow()
date = timeRightNow
sendDate()
print("date was sent")
}
func getTimeRightNow() {
timeRightNow = NSDate().timeIntervalSince1970
}
The function getDate() calls getTimeRightNow() which then gets the current NSDate and sets it equal to a variable timeRightNow. I then take timeRightNow and set date equal to it which I then pass along for further use.
Below, I have a second version. This time I instead have the getTimeRightNow() function return a value of type Double...
func getDate() {
date = getTimeRightNow()
sendDate()
print("date was sent")
}
func getTimeRightNow()-> Double {
timeRightNow = NSDate().timeIntervalSince1970
return timeRightNow
}
Both versions seems to work exactly the same. I guess the second version lets me type one less line, is that the only advantage that it offers? Is the second version considered "best practice"? In the second version, is there any chance that the sendDate() function gets called BEFORE the getTimeRightNow() function finishes and sets a value for date? How about in the first version, is there any chance that timeRightNow gets set equal to date BEFORE the getTimeRightNow() function finishes and sets a proper NSDate for timeRightNow?
Having trouble understanding this, appreciate the help
The difference between the function that has a return value and one that does not is that it returns a value. That can be really practical.
let aDate = myRandomDate()
let anotherDate = myRandomDate()
You would not be able to do this with a function that does not return a value.

How to add conformance to _Incrementable in NSDate

I am trying to add conformance to ForwardIndexType in NSDates so I can make a Range<NSDate>, in order to do it I must implement public func successor() -> Self from _Incrementable.
My implementation is really simple and aims to state the date that succeeds another one is the one exactly one second after it, that's not what is being asked here.
extension NSDate: ForwardIndexType {
public func successor() -> Self {
return NSDate(timeInterval: 1, sinceDate: self)
}
}
The error I'm getting is
Cannot convert return expression of type 'NSDate' to return type 'Self'
I've tried adding as Self or as! Self but the compiler does not allow me since converting from NSDate to Self always succeeds in that case. Replacing Self by NSDate also does not do the trick.
How can I do it the right way?
As several comments have said, you should not do this even if it's possible. NSDate does not have a logical "next." Inventing one risks side effects. Extensions of public types are global. What happens if you say "the next date is the next second" and another extension says "the next date is the next day?" Both are equally reasonable (and equally incorrect). Never add extensions that are likely to collide with different meanings if others did them too.
You said your goal is:
I want to create a set of n random dates in a given interval. I wanted to shuffle a range and select the first n values
That's no problem at all. First, as you say, you want "in a given interval." Excellent. That's a ClosedInterval<NSDate>. To get that, NSDate must be Comparable. There's nothing wrong with adding that extension. Anyone who implemented it reasonably would have to implement it this way.
extension NSDate: Comparable {}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
}
Now you want to convert this to a range of integral seconds, not a range of dates. Then shuffle the elements in that range, pull off the first n values, and map those back to dates. We'll assume you already have Nate Cook's shuffle code.
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
// For convenience we're going to assume that the range is no larger than 68 years.
// If you need ranges larger than that, it's a bit more work and probably the subject
// of a second question. (See https://stackoverflow.com/a/34388108/97337 for the basis.)
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
let offsets = (0...intervalSize).shuffle()
return Array(offsets.map { interval.start.dateByAddingTimeInterval(NSTimeInterval($0)) }.prefix(count))
}
And you can even use it with ... or ..<to define your intervals:
// 100 second-interval dates from the last hour
randomDatesInInterval(NSDate(timeIntervalSinceNow: -3600)...NSDate(), count: 100)
.forEach { print($0) }
Note that this algorithm is a bit slow and memory intensive if n is dramatically smaller than the number of seconds in the interval. We have to create what could be a pretty enormous array of numbers in order to do it the way you requested. If you don't care about duplicates, then it's all much simpler:
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
return (1...count).map { _ in
let offset = arc4random_uniform(intervalSize)
return interval.start.dateByAddingTimeInterval(Double(offset))
}
If the interval is dramatically larger than n, then the chance of duplicates is low. If you still want to avoid duplicates without having to allocate that huge initial array, consider a Set:
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
var offsets = Set<UInt32>()
while offsets.count < count {
offsets.insert(arc4random_uniform(intervalSize))
}
return offsets.sort().map { interval.start.dateByAddingTimeInterval(NSTimeInterval($0)) }
}
The trade-off of a Set is that this approach is very slow if n is of similar magnitude to the number of seconds in the interval. In that case, the shuffle is much more efficient.
Try this, change Self to NSDate, remove ForwardIndexType protocol
extension NSDate: _Incrementable {
public func successor() -> Self {
return self.dynamicType.init(timeInterval: 1, sinceDate: self)
}
}
use in code like,
var date = NSDate()
date = date.successor()
let newDate = date.successor()
In ForwardIndexType protocol, there are methods like, advancedBy: and distanceTo:, you are implementing method successor, just implement protocol _Incrementable. this will work.

Swift number formatting

I am just starting to get to know Swift but I am having a serious problem with number formatting at an extremely basic level.
For example, I need to display an integer with at least 2 digits (e.g. 00, 01, 02, 03, 04, 05 ...). The normal syntax I'd expect would be something like:
println(" %02i %02i %02i", var1, var2, var3);
...but I don't find any clear instruction for how to achieve this in Swift. I find it really hard to believe that I need to create a custom function to do that. The same for returning a float or double value to a fixed number of decimal places.
I've found links to a couple of similar questions (Precision String Format Specifier In Swift & How to use println in Swift to format number) but they seem to mix objective C and even talk about Python and using unity libraries. Is there no Swift solution to this basic programming need? Is it really true that something so fundamental has been completely overlooked in Swift?
You can construct a string with a c-like formatting using this constructor:
String(format: String, arguments:[CVarArgType])
Sample usage:
var x = 10
println(String(format: "%04d", arguments: [x])) // This will print "0010"
If you're going to use it a lot, and want a more compact form, you can implement an extension like this:
extension String {
func format(arguments: [CVarArgType]) -> String {
return String(format: self, arguments: arguments)
}
}
allowing to simplify its usage as in this example:
"%d apples cost $%03.2f".format([4, 4 * 0.33])
Here's a POP solution to the problem:
protocol Formattable {
func format(pattern: String) -> String
}
extension Formattable where Self: CVarArg {
func format(pattern: String) -> String {
return String(format: pattern, arguments: [self])
}
}
extension Int: Formattable { }
extension Double: Formattable { }
extension Float: Formattable { }
let myInt = 10
let myDouble: Double = 0.01
let myFloat: Float = 1.11
print(myInt.format(pattern: "%04d")) // "0010
print(myDouble.format(pattern: "%.2f")) // "0.01"
print(myFloat.format(pattern: "$%03.2f")) // "$1.11"
print(100.format(pattern: "%05d")) // "00100"
You can still use good ole NSLog("%.2f",myFloatOrDouble) too :D
There is a simple solution I learned with "We <3 Swift", which is so easy you can even use without Foundation, round() or Strings, keeping the numeric value.
Example:
var number = 31.726354765
var intNumber = Int(number * 1000.0)
var roundedNumber = Double(intNumber) / 1000.0
result: 31.726