Subtracting time in swift - ios

I have 2 NSDate object thats shows 24hour time. Is there a way I can subtract those two times and put the result in a label. Ive searched for a method but couldn't find one. The only thing I could find was cover it to a double with timeIntervalFromDate method, which returns a double and I need the 24hour representation of that.

It just returns an NSTimeInterval that is typedef double NSTimeInterval is a representation in seconds.
Doing the math to know how may hours are in x seconds, you just need to divide the retuned interval to 3600 seconds and round the result.
I've build a simple extension to be used in swift to help in calendrical calculation, you can find it here: AFSwiftDateExtension

This function may solve your problem:
func hoursFrom(earlierDate : NSDate, laterDate:NSDate) -> Int
{
return NSCalendar.currentCalendar().components(NSCalendarUnit.CalendarUnitHour, fromDate: earlierDate, toDate: laterDate, options: nil).hour
}
Adapted from this related question.

extension NSTimeInterval {
var time:String {
return String(format:"%02d:%02d:%02d", Int((self/3600.0)%24), Int((self/60.0)%60), Int((self)%60))
}
}
println(30.time) // "00:00:30"
println(60.time) // "00:01:00"
println(600.time) // "00:10:00"
println(3600.time) // "01:00:00"

Related

Swift: Trying to make a app that counts down the time from the present until one hour later [duplicate]

This question already has answers here:
How can I make a countdown timer like in a music player?
(2 answers)
Closed 7 years ago.
I'm trying to make an app that tell us the rest of time from the present time till one hour later.
This is the code but now it only has a function that tell us the countdown time by decreasing one second from the present time.
I'm thinking that I haven't definite the definition of the "cnt"
so that's why I'm thinking it doesn't work.
Can somebody tell me the reason and a solution?
import UIKit
class ViewController: UIViewController {
var cnt : Int = 0
var timer : NSTimer!//NSTimerというデフォルト機能から引っ張る
var myInt:Int = 0
override func viewDidLoad() {
let myDate: NSDate = NSDate()
let myCalendar: NSCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let myComponents = myCalendar.components([.Year, .Hour, .Minute, .Second],
fromDate: myDate) // myDate、すなわちNSDateから要素として引っ張り出してる
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "onUpdate:", userInfo: nil, repeats: true)//カウントダウンのインターバル
timer.fire()
var myStr: String = "\(myComponents.hour)"
myStr += "\(myComponents.minute)"
myStr += "\(myComponents.second)"
myInt = Int(myStr)! // toInt()がSwift2より無効になったようです。myInt=Str(my components,hour,minute,second)=現時刻
}
func onUpdate(timer : NSTimer){
cnt += 1//cnt+1=cnt,
let count = myInt - cnt //残り時間=現在時刻ー現在時刻に1時間足した時刻
print(count) // println()は、Swift2よりDeprecatedになりました。
}
}
It is difficult to understand what you're asking, but I will do my best.
In your viewDidLoad method, you're setting myInt to the integer representation of myStr. If the time is 18:30:50, myInt will be equal to 183050. That is not an appropriate representation of the time. Time is base 60, integers are base 10, for one thing. If you want to represent time as a single number, you can use timeIntervalSinceDate, or timeIntervalSinceReferenceDate or timeIntervalSince1970 to get the NSTimeInterval (ie. fractional seconds) representation of the date relative to a certain epoch either of your choosing or one built into Foundation.
Subtracting 1 from myInt each time the timer fires isn't going to give you an indication of the time remaining.
Also, NSTimer is not an accurate way to keep time. You should instead save the start date as a property and determine the time remaining based on timeIntervalSinceDate
e.g.
func onUpdate(timer : NSTimer){
let currentTime = NSDate()
let timeElapsed = currentTime.timeIntervalSinceDate(myDate)
println(timeElapsed)
}
If you want to show time elapsed in minutes, you can divide it by 60. You can look into NSDateComponentsFormatter to easily get a string representation of time intervals.
If you want the countdown to stop after an hour, then check for when timeElapsed is over 3600.
If you want it to show a countdown from 1 hour, then subtract the timeElapsed from 3600.

In Swift, how can I get an NSDate from a dispatch_time_t?

"Walltime" is a little-known time format used by Grand Central Dispatch. Apple talks about it here:
https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/
There are some things it's really handy for, though, but it's a sticky wicket. It's hard to make it play nice with other time formats, which is what my question's about.
I can make a walltime by turning an NSDate into a timespec, and then using with dispatch_walltime:
let now = NSDate().timeIntervalSince1970
let nowWholeSecsFloor = floor(now)
let nowNanosOnly = now - nowWholeSecsFloor
let nowNanosFloor = floor(nowNanosOnly * Double(NSEC_PER_SEC))
var thisStruct = timespec(tv_sec: Int(nowWholeSecsFloor),
tv_nsec: Int(nowNanosFloor))
let wallTime = dispatch_walltime(& thisStruct, 0)
But lord love a duck, I can't figure out how to get it back into an NSDate. Here's my try:
public func toNSDate(wallTime: dispatch_time_t)->NSDate {
let wallTimeAsSeconds = Double(wallTime) / Double(NSEC_PER_SEC)
let date = NSDate(timeIntervalSince1970: wallTimeAsSeconds)
return date
}
The resulting NSDate is not just off, but somewhat hilariously off, like five hundred years or something. As Martin R pointed out, the problem is that dispatch_time_t is an opaque value, with an undocumented representation of time.
Does anyone know how to do this?
EDIT: if the process of creating the walltime is confusing, this is basically what's going on:
NSDate defines time with a Double, and everything after the decimal point is the nanoseconds. dispatch_time, which can create a walltime, defines time with UInt64, so you have to convert between Double and UInt64 to use it. To do that conversion you need to use a timespec, which takes seconds and nanoseconds as separate arguments, each of which must be Int.
A whole lotta convertin' going on!
The real answer is: you can't.
In the "time.h" header file it is stated:
/*!
* #typedef dispatch_time_t
*
* #abstract
* A somewhat abstract representation of time; where zero means "now" and
* DISPATCH_TIME_FOREVER means "infinity" and every value in between is an
* opaque encoding.
*/
typedef uint64_t dispatch_time_t;
So dispatch_time_t uses an undocumented "abstract" representation of time, which
may even change between releases.
That being said, let's have some fun and try to figure out what
a dispatch_time_t really is. So we have a look at "time.c", which contains the implementation of
dispatch_walltime():
dispatch_time_t
dispatch_walltime(const struct timespec *inval, int64_t delta)
{
int64_t nsec;
if (inval) {
nsec = inval->tv_sec * 1000000000ll + inval->tv_nsec;
} else {
nsec = (int64_t)_dispatch_get_nanoseconds();
}
nsec += delta;
if (nsec <= 1) {
// -1 is special == DISPATCH_TIME_FOREVER == forever
return delta >= 0 ? DISPATCH_TIME_FOREVER : (dispatch_time_t)-2ll;
}
return (dispatch_time_t)-nsec;
}
The interesting part is the last line: it takes the negative value of the
nanoseconds, and this value is cast back to an (unsigned) dispatch_time_t. There are also some special cases.
Therefore, to reverse the conversion, we have to negate the
dispatch_time_t and take that as nanoseconds:
public func toNSDate(wallTime: dispatch_time_t)->NSDate {
// Tricky part HERE:
let nanoSeconds = -Int64(bitPattern: wallTime)
// Remaining part as in your question:
let wallTimeAsSeconds = Double(nanoSeconds) / Double(NSEC_PER_SEC)
let date = NSDate(timeIntervalSince1970: wallTimeAsSeconds)
return date
}
And indeed, this converts the walltime correctly back to the original
NSDate, at least when I test it in an OS X application.
But again: don't do it! You would rely on an undocumented representation which could change between OS releases. There may also
be special cases that are not considered in the above code.
Also the representation in the iOS runtime could be different, I did
not try that.
You have been warned!

How should I represent/store a song duration as a property? I want to use a common song duration format such as "HH:MM:SS"

I have a custom class called Song. Each instance of this class needs to have a property which represents its duration, and I want that duration in a normal "songy" format like HH:MM:SS. The Song instances will be receiving data, such as duration, from JSON network calls, and they also might be persisted via Core Data or some other method.
What are my options to store this duration? Do I need to store it has a string like
self.duration = #"0:2:14";
or
self.duration = #"0.2.14";
Would storing it as a NSNumber of NSDate be better? If so, how do I convert it to those types? If I need to store it as a string, is there a better way to convert it into a number/time interval than splitting the colons?
You should store the duration in seconds (or milliseconds if you want to be that exact) as an integer. Then convert that to a pretty format when displaying the time, for example through a method -(NSString*)displayDuration
If you declare your duration property like this
#property (nonatomic) int duration;
then you could write a method to get an NSString for display:
- (NSString*)displayDuration {
int remainingDuration = self.duration;
int seconds = remainingDuration%60;
remainingDuration/=60;
int minutes = remainingDuration%60;
remainingDuration/=60;
int hours = remainingDuration;
return [NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
}
Use NSDateComponent
let cal = NSCalendar.currentCalendar()
let comps = cal.components([.Day, .Hour, .Minute], fromDate: self, toDate: otherDate, options: [])
return (comps.day , comps.hour , comps.minute)
where self is a NSDate and otherDate is also a NSDate (this was implemented as an extension to NSDate)
Add components as you like (here are only days, hour, minutes)
The example code returns a tuple. Accessible via .0, .1, .2 allowing string formatting in whatever way necessary.
Code is in Swift 2

ios minutes to time

I want to go from minutes as an int (eg 92) to a string of 1:32. Is there a fancy way to do this using objc or I'm I stuck with figuring it out the old-fashioned way?
I do not believe there is a function to do this, but it is simple enough to do on your own.
int hour = minutes / 60;
int min = minutes % 60;
NSString *timeString = [NSString stringWithFormat: %#"%d:%02d", hour, min];
The '02' will pad the results so there are always two digits in the minutes place. It may be useful to look at the NSDate Class Reference as it may save you time if you want to do calculations on the result.
I think you can find the answer here: NSTimeInterval to NSDate
The int you talking about should be NSTimeInterval (that is just double), convert it to a NSDate object and then format it using the NSDateFormatter with: HH:mm.
It can also could be more useful "extend" using categories NSDate object
#interface NSDate (Minutes)
and put there a method convert minutes to HH:mm (maybe could be better to move the format string as method parameter) so you never more need think about it.

iPhone: How to get current milliseconds?

What is the best way to get the current system time milliseconds?
If you're looking at using this for relative timing (for example for games or animation) I'd rather use CACurrentMediaTime()
double CurrentTime = CACurrentMediaTime();
Which is the recommended way; NSDate draws from the networked synch-clock and will occasionally hiccup when re-synching it against the network.
It returns the current absolute time, in seconds.
If you want only the decimal part (often used when syncing animations),
let ct = CACurrentMediaTime().truncatingRemainder(dividingBy: 1)
[[NSDate date] timeIntervalSince1970];
It returns the number of seconds since epoch as a double. I'm almost sure you can access the milliseconds from the fractional part.
I benchmarked all the other answers on an iPhone 4S and iPad 3 (release builds). CACurrentMediaTime has the least overhead by a small margin. timeIntervalSince1970 is far slower than the others, probably due to NSDate instantiation overhead, though it may not matter for many use cases.
I'd recommend CACurrentMediaTime if you want the least overhead and don't mind adding the Quartz Framework dependency. Or gettimeofday if portability is a priority for you.
iPhone 4S
CACurrentMediaTime: 1.33 µs/call
gettimeofday: 1.38 µs/call
[NSDate timeIntervalSinceReferenceDate]: 1.45 µs/call
CFAbsoluteTimeGetCurrent: 1.48 µs/call
[[NSDate date] timeIntervalSince1970]: 4.93 µs/call
iPad 3
CACurrentMediaTime: 1.25 µs/call
gettimeofday: 1.33 µs/call
CFAbsoluteTimeGetCurrent: 1.34 µs/call
[NSDate timeIntervalSinceReferenceDate]: 1.37 µs/call
[[NSDate date] timeIntervalSince1970]: 3.47 µs/call
In Swift we can make a function and do as follows
func getCurrentMillis()->Int64{
return Int64(NSDate().timeIntervalSince1970 * 1000)
}
var currentTime = getCurrentMillis()
Though its working fine in Swift 3.0 but we can modify and use the Date class instead of NSDate in 3.0
Swift 3.0
func getCurrentMillis()->Int64 {
return Int64(Date().timeIntervalSince1970 * 1000)
}
var currentTime = getCurrentMillis()
To get milliseconds for current date.
Swift 4+:
func currentTimeInMilliSeconds()-> Int
{
let currentDate = Date()
let since1970 = currentDate.timeIntervalSince1970
return Int(since1970 * 1000)
}
So far I found gettimeofday a good solution on iOS (iPad), when you want to perform some interval evaluation (say, framerate, timing of a rendering frame...) :
#include <sys/time.h>
struct timeval time;
gettimeofday(&time, NULL);
long millis = (time.tv_sec * 1000) + (time.tv_usec / 1000);
Swift 2
let seconds = NSDate().timeIntervalSince1970
let milliseconds = seconds * 1000.0
Swift 3
let currentTimeInMiliseconds = Date().timeIntervalSince1970.milliseconds
It may be useful to know about CodeTimestamps, which provide a wrapper around mach-based timing functions. This gives you nanosecond-resolution timing data - 1000000x more precise than milliseconds. Yes, a million times more precise. (The prefixes are milli, micro, nano, each 1000x more precise than the last.) Even if you don't need CodeTimestamps, check out the code (it's open source) to see how they use mach to get the timing data. This would be useful when you need more precision and want a faster method call than the NSDate approach.
http://eng.pulse.me/line-by-line-speed-analysis-for-ios-apps/
// Timestamp after converting to milliseconds.
NSString * timeInMS = [NSString stringWithFormat:#"%lld", [#(floor([date timeIntervalSince1970] * 1000)) longLongValue]];
I needed a NSNumber object containing the exact result of [[NSDate date] timeIntervalSince1970]. Since this function was called many times and I didn't really need to create an NSDate object, performance was not great.
So to get the format that the original function was giving me, try this:
#include <sys/time.h>
struct timeval tv;
gettimeofday(&tv,NULL);
double perciseTimeStamp = tv.tv_sec + tv.tv_usec * 0.000001;
Which should give you the exact same result as [[NSDate date] timeIntervalSince1970]
CFAbsoluteTimeGetCurrent()
Absolute time is measured in seconds relative to the absolute reference date of Jan 1 2001 00:00:00 GMT. A positive value represents a date after the reference date, a negative value represents a date before it. For example, the absolute time -32940326 is equivalent to December 16th, 1999 at 17:54:34. Repeated calls to this function do not guarantee monotonically increasing results. The system time may decrease due to synchronization with external time references or due to an explicit user change of the clock.
This is basically the same answer as posted by #TristanLorach, just recoded 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)
}
Try this :
NSDate * timestamp = [NSDate dateWithTimeIntervalSince1970:[[NSDate date] timeIntervalSince1970]];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"YYYY-MM-dd HH:mm:ss.SSS"];
NSString *newDateString = [dateFormatter stringFromDate:timestamp];
timestamp = (NSDate*)newDateString;
In this example, dateWithTimeIntervalSince1970 is used in combination of the formatter #"YYYY-MM-dd HH:mm:ss.SSS" that will return the date with year, month, day and the time with hours, minutes, seconds, and milliseconds. See the example : "2015-12-02 04:43:15.008". I used the NSString to be sure that the format will be has written before.
func currentmicrotimeTimeMillis() -> Int64{
let nowDoublevaluseis = NSDate().timeIntervalSince1970
return Int64(nowDoublevaluseis*1000)
}
let timeInMiliSecDate = Date()
let timeInMiliSec = Int (timeInMiliSecDate.timeIntervalSince1970 * 1000)
print(timeInMiliSec)
This is what I used for Swift
var date = NSDate()
let currentTime = Int64(date.timeIntervalSince1970 * 1000)
print("Time in milliseconds is \(currentTime)")
used this site to verify accuracy http://currentmillis.com/
NSTimeInterval time = ([[NSDate date] timeIntervalSince1970]); //double
long digits = (long)time; //first 10 digits
int decimalDigits = (int)(fmod(time, 1) * 1000); //3 missing digits
/*** long ***/
long timestamp = (digits * 1000) + decimalDigits;
/*** string ***/
NSString *timestampString = [NSString stringWithFormat:#"%ld%03d",digits ,decimalDigits];
[NSDate timeIntervalSinceReferenceDate] is another option, if you don't want to include the Quartz framework. It returns a double, representing seconds.

Resources