Adding and Subtracting times in Swift - ios

I've written some of this in pseudo code because I don't know the syntax for it. I'd like to have the timeLeftLabel.text reflect how many hours, minutes, and seconds are left until the 6 hours are up. My biggest problem is that I don't know how to add and subtract times. Can anyone help me?
var timer = NSTimer()
func timerResults() {
let theDate = NSDate()
var endTime = theDate //+ 6 hours
let timeLeft = endTime //- theDate
timeLeftLabel.text = "\(timeLeft)"
}
#IBOutlet weak var timeLeftLabel: UILabel!
#IBAction func IBbtnUpdateTap(sender: UIButton){
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("timerResults"), userInfo: nil, repeats: true)
}

Assuming your deployment target is iOS 8.0 or later, you should use NSDateComponentsFormatter to format your string. You want something like this:
class MyViewController : UIViewController {
#IBOutlet weak var timeLeftLabel: UILabel!
var targetDate: NSDate?
var labelUpdateTimer: NSTimer?
var timeLeftFormatter: NSDateComponentsFormatter?
#IBAction func startTimerButtonWasTapped() {
targetDate = NSDate(timeIntervalSinceNow: 6 * 60 * 60)
labelUpdateTimer = NSTimer.scheduledTimerWithTimeInterval(1,
target: self, selector: "labelUpdateTimerDidFire:", userInfo: nil, repeats: true)
timeLeftFormatter = NSDateComponentsFormatter()
timeLeftFormatter?.unitsStyle = .Abbreviated // gives e.g. "1h 20m 34s"
// You might prefer .Positional, which gives e.g. "1:20:34"
timeLeftFormatter?.allowedUnits = [ .Hour, .Minute, .Second ]
labelUpdateTimerDidFire(labelUpdateTimer!)
}
#objc func labelUpdateTimerDidFire(timer: NSTimer) {
let now = NSDate()
timeLeftLabel.text = timeLeftFormatter!.stringFromDate(now,
toDate: targetDate!)
if now.compare(targetDate!) != NSComparisonResult.OrderedAscending {
print("times up!")
labelUpdateTimer?.invalidate()
}
}
}

This will add 6 hours:
let future = now.dateByAddingTimeInterval(3600*6) // 1 hour is 3600 seconds
This will find the difference:
let difference = future.timeIntervalSinceDate(now)

Related

Reverse Time Label

I am looking for label which can give me functionality to count down reverse timer. I know there are Timer available to to count down, but I want reverse count down with Days, Hours, Minutes, Seconds like as following image.
Can anyone tell me how to implement this like as following image ?
Help will be appreciated. Thank You.
First you need to create an NSAttributedString with your time format requeriments something like this
func timeLeftExtended(date:Date) ->NSAttributedString{
let cal = Calendar.current
let now = Date()
let calendarUnits:NSCalendar.Unit = [NSCalendar.Unit.day, NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]
let components = (cal as NSCalendar).components(calendarUnits, from: now, to: date, options: [])
let fullCountDownStr = "\(components.day!.description)d " + "\(components.hour!.description)h " + "\(components.minute!.description)m " + "\(components.second!.description)s "
let mutableStr = NSMutableAttributedString(string: fullCountDownStr, attributes: [NSAttributedStringKey.foregroundColor:UIColor.white])
for (index,char) in mutableStr.string.enumerated()
{
if(char == "d" || char == "h" || char == "m" || char == "s")
{
mutableStr.removeAttribute(NSAttributedStringKey.foregroundColor, range: NSMakeRange(index, 1))
mutableStr.addAttributes([NSAttributedStringKey.foregroundColor : UIColor.lightGray], range: NSMakeRange(index, 1))
}
}
return mutableStr
}
After that you need to declare the label where you want to update your time left
#IBOutlet weak var lblTimeRemaining: UILabel!
And add a timer and a flag to know when your timer is working
fileprivate var timeWorking : Bool = false
var timer:Timer?
Here we setup our timer
func setupWith()
{
if(!timeWorking)
{
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateCountDown), userInfo: nil, repeats: true)
self.timeWorking = true
}
}
This method will be executed 1 time every second to update our count
#objc func updateCountDown()
{
self.lblTimeRemaining.attributedText = self.timeLeftExtended(date:Date.distantFuture)
}
RESULT

Count-Up and Count-Down Timer with Date() in Swift 4 should stop after a certain time period

I am quite new to Swift and already learned a lot using the questions here.
In one of my first projects I try to write a soccer playtime timer app. The first timer is counting up after the whistle button is pressed showing the minutes played and the second timer is counting down to zero showing the minutes left to play. This works so far.
Now both timers should stop automatically when the halftime is over, so that I can start a third overtime timer. So far the invalidate statement of the timer is not working - both timers keep running. There seems to be something wrong with my if-statements, but at the moment I have no clue what. So any help would be very appreciated.
var countUpClock: Timer?
var countDownClock: Timer?
private var formatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.allowedUnits = [.minute, .second]
formatter.zeroFormattingBehavior = .pad
return formatter
}()
func runPlaytimeClocks() {
let startTime = Date()
let countTime = Date() + 2700 //45min of playtime
if startTime <= countTime {
countUpClock = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
self?.timePlayed.text = self?.formatter.string(from: startTime, to: Date())
}
}
else {
countUpClock?.invalidate()
}
if startTime <= countTime {
countDownClock = Timer.scheduledTimer(withTimeInterval: -1.0, repeats: true) { [weak self] _ in
self?.timetoPlay.text = self?.formatter.string(from: Date(), to: countTime)
}
}
else {
countDownClock?.invalidate()
}
Thank you very much for the replies.
I found exactly what I was looking for here: http://ioscake.com/swift-nstimer-in-background.html
I adapted the solution to my for clocks (CountUpClock, CountDownClock, OvertimeClock, HalftimeClock).
Do you have any suggestions what would be the best solution to start the second halftime of the soccer game?
So far the CountUpClock starts again at 0:00 when I press the whistle button after the halftime break. But it should keep running from minute 45:00 to 90:00 - while the CountDownClock should counting down from 45:00 to 0:00 again.
What would be the best solution for such a behaviour?
import UIKit
import UserNotifications
private let stopTimeKey = "stopTimeKey"
class ViewController: UIViewController {
//Outlets
#IBOutlet weak var timePlayed: UILabel!
#IBOutlet weak var timeToPlay: UILabel!
#IBOutlet weak var overtime: UILabel!
#IBOutlet weak var halftime: UILabel!
#IBOutlet weak var halftimeButton: UIButton!
private var stopTime: Date?
override func viewDidLoad() {
super.viewDidLoad()
registerForLocalNotifications()
stopTime = UserDefaults.standard.object(forKey: stopTimeKey) as? Date
if let time = stopTime {
if time > Date() {
startTimers(time, includeNotification: false)
} else {
notifyTimerCompleted()
}
}
}
private func registerForLocalNotifications() {
if #available(iOS 10, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
guard granted && error == nil else {
// display error
print("\(String(describing: error))")
return
}
}
} else {
let types: UIUserNotificationType = [.badge, .sound, .alert]
let settings = UIUserNotificationSettings(types: types, categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
}
}
//Actions
#IBAction func whistleButtonTapped(_ sender: UIButton) {
overtimeClock?.invalidate()
overtimeClock = nil
halftimeClock?.invalidate()
halftimeClock = nil
overtime.text = "00:00"
halftime.text = "00:00"
halftimeButton.isHidden = true
//add 10 seconds per halftime to try out
let time = Date() + 10
if time > Date() {
startTimers(time)
} else {
timeToPlay.text = "error"
}
}
#IBAction func halftimeButton(_ sender: UIButton) {
halftimeButtoPressed()
}
// Code for different Timers
private var countDownClock: Timer?
private var countUpClock: Timer?
var overtimeClock: Timer?
var halftimeClock: Timer?
private func startTimers(_ stopTime: Date, includeNotification: Bool = true) {
// save `stopTime` in case app is terminated
UserDefaults.standard.set(stopTime, forKey: stopTimeKey)
self.stopTime = stopTime
// start Timer
countDownClock = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(handleCountDownTimer(_:)), userInfo: nil, repeats: true)
countUpClock = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(handleCountUpTimer(_:)), userInfo: nil, repeats: true)
guard includeNotification else { return }
// start local notification (so we're notified if timer expires while app is not running)
if #available(iOS 10, *) {
let content = UNMutableNotificationContent()
content.title = "Overtime is starting soon"
content.body = "In 5 seconds the overtime will start"
content.sound = UNNotificationSound.default()
//5 seconds warning before overtime starts
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: stopTime.timeIntervalSinceNow - 5, repeats: false)
let notification = UNNotificationRequest(identifier: "timer", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(notification)
} else {
let notification = UILocalNotification()
//5 seconds warning before overtime starts
notification.fireDate = stopTime - 5
notification.alertBody = "Overtime is starting soon"
UIApplication.shared.scheduleLocalNotification(notification)
}
}
private func stopTimer() {
countDownClock?.invalidate()
countDownClock = nil
countUpClock?.invalidate()
countUpClock = nil
}
private func halftimeButtoPressed() {
overtimeClock?.invalidate()
overtimeClock = nil
startHalftimeClock()
halftimeButton.isHidden = true
}
private let dateComponentsFormatter: DateComponentsFormatter = {
let _formatter = DateComponentsFormatter()
_formatter.allowedUnits = [.minute, .second]
_formatter.unitsStyle = .positional
_formatter.zeroFormattingBehavior = .pad
return _formatter
}()
#objc func handleCountDownTimer(_ timer: Timer) {
let now = Date()
if stopTime! > now {
timeToPlay.text = dateComponentsFormatter.string(from: now, to: stopTime!)
} else {
stopTimer()
notifyTimerCompleted()
startOvertimeClock()
halftimeButton.isHidden = false
}
}
#objc func handleCountUpTimer(_ timer: Timer) {
//add 10 seconds per halftime to try out
let now = Date() + 10
if now > stopTime! {
timePlayed.text = dateComponentsFormatter.string(from: stopTime!, to: now)
} else {
stopTimer()
notifyTimerCompleted()
}
}
//Overtime Clock
#objc func startOvertimeClock() {
let startOvertime = Date()
overtimeClock = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
self?.overtime.text = self?.dateComponentsFormatter.string(from: startOvertime, to: Date())
}
}
//Halftime Clock
#objc func startHalftimeClock() {
let startHalftime = Date()
halftimeClock = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
self?.halftime.text = self?.dateComponentsFormatter.string(from: startHalftime, to: Date())
}
}
private func notifyTimerCompleted() {
timeToPlay.text = "End"
timePlayed.text = "End"
}
}

NSTimer to to 4 digit label update

I just made a stopwatch with a tutorial but what I would like to do is to update my 00:00 label as 1 second increasing such as 00:01, 00:02: 00:03 and to do the same for minutes. Is there anyway of doing that? Thanks in advance!
Then you have to get the date which will start the counting from which is the current date when a particular event occurs, let's say we will start the timer when the view appears, so implement viewWillAppear as follows:
var currentDate = NSDate()
override func viewWillAppear(animated: Bool) {
currentDate = NSDate()
var timer: NSTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateLabel", userInfo: nil, repeats: true)
timer.fire()
}
and implement the updateLabel function:
func updateLabel() {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
var elapsedSeconds: NSTimeInterval = -self.currentDate.timeIntervalSinceNow
let minutes: Int = Int(elapsedSeconds)/60
let seconds: Int = Int(elapsedSeconds) - (minutes*60)
self.timeLabel.text = String(format: "%02d:%02d", minutes, seconds)
})
}
When formatting time elapsed, NSDateComponentsFormatter is another option:
var start: CFAbsoluteTime!
override func viewDidLoad() {
super.viewDidLoad()
start = CFAbsoluteTimeGetCurrent()
NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "handleTimer:", userInfo: nil, repeats: true)
}
lazy var formatter: NSDateComponentsFormatter = {
let _formatter = NSDateComponentsFormatter()
_formatter.allowedUnits = .CalendarUnitMinute | .CalendarUnitSecond
_formatter.zeroFormattingBehavior = .Pad
return _formatter
}()
func handleTimer(timer: NSTimer) {
let elapsed = CFAbsoluteTimeGetCurrent() - start
label.text = formatter.stringFromTimeInterval(elapsed)
}
Admittedly, that will give you the time elapsed in 0:00 format, not 00:00 format.
This is Objective-C, but you'll get the idea:
-(void) updateTotalTime
{
int forHours = timeInSeconds / 3600,
remainder = timeInSeconds % 3600,
forMinutes = remainder / 60,
forSeconds = remainder % 60;
[elapsedTime setString:[NSString stringWithFormat:NSLocalizedString(#"elapsedTime", nil)
,forHours
,forMinutes
,forSeconds]];
}
and in my Localizable.strings:
"elapsedTime" = "Time: %02d:%02d:%02d";

Stuck: Analog Clock in Swift iOS

I'm new to swift (and coding in general), and I've been working on an analog watch project. I've gotten to a place where I'm stuck. None of the println() commands are putting anything out to the console unless they arrive before the function "func setTime(){...} ". Not sure what's happening there. And I can't seem to get the hands to rotate with the math I found here. I'm trying to convert it from obj-c to swift. (I know the bottom section is very wrong at the moment) I keep messing with it (the bottom section) but I don't get any rotation.
Any help would be appreciated. I feel like I'm close.
var theTimer:NSTimer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
println(viewDidLoad)
func setTime(){
println("set time")
self.theTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "set time", userInfo: nil, repeats: false)
let date = NSDate()
let outputFormatter = NSDateFormatter()
outputFormatter.dateFormat = "hh:mm:ss"
let newDateString:NSString = outputFormatter.stringFromDate(date)
println(newDateString)
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute | .CalendarUnitSecond, fromDate: date)
var hour = components.hour
var minute = components.minute
var second = components.second
println(hour)
println(minute)
println(second)
**var secAngle = (6 * second)
var minAngle = (6 * minute)
var hourAngle = (30 * hour + minute / 2)
self.secsImage.transform = CGAffineTransformMakeRotation( CGFloat(secAngle) )
self.minsImage.transform = CGAffineTransformMakeRotation( CGFloat(Double(minAngle)) )
self.hoursImage.transform = CGAffineTransformMakeRotation( CGFloat(Double(hourAngle)) )**
println(secAngle)
println(minAngle)
println(hourAngle)
}
}
You have declared your setTime function inside your viewDidLoad function, and you have never called it. Also, your the selector for your NSTimer is not correct - it needs to be the name of the function and it needs to be a Selector, not just a string.
You should move the setTime function declaration out of viewDidLoad and I would suggest setting it up in viewWillAppear -
var theTimer:NSTimer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
println(viewDidLoad)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.setTime()
self.theTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("setTime"), userInfo: nil, repeats: true)
}
func setTime(){
println("set time")
let date = NSDate()
let outputFormatter = NSDateFormatter()
outputFormatter.dateFormat = "hh:mm:ss"
let newDateString:NSString = outputFormatter.stringFromDate(date)
println(newDateString)
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute | .CalendarUnitSecond, fromDate: date)
var hour = components.hour
var minute = components.minute
var second = components.second
println(hour)
println(minute)
println(second)
var secAngle = (6 * second)
var minAngle = (6 * minute)
var hourAngle = (30 * hour + minute / 2)
self.secsImage.transform = CGAffineTransformMakeRotation( CGFloat(secAngle) )
self.minsImage.transform = CGAffineTransformMakeRotation( CGFloat(Double(minAngle)) )
self.hoursImage.transform = CGAffineTransformMakeRotation( CGFloat(Double(hourAngle)) )**
println(secAngle)
println(minAngle)
println(hourAngle)
}
If you are new to programming, you may want to consider running through some basic coding tutorials on the web.

Updating time function every second in NSDate() - Swift

I have a function that gives me a time when the app is opened but I don't want it to be static I want it to be dynamic, updating every second. I thought of it being in a loop, but I don't know how to go about doing it. Doing a loop could work but if you have a better way of doing it please answer. Here is my function:
func timeNowString() -> NSString {
let date = NSDate()
var outputFormat = NSDateFormatter()
outputFormat.locale = NSLocale(localeIdentifier:"en_US")
outputFormat.dateFormat = "HH:mm:ss"
let timeString = outputFormat.stringFromDate(date)
return timeString;
}
Question: How do I make this function dynamic? So it goes and updates every second instead of it being a static label.
If you have any questions please comment down below.
Try this. You'll need to add a label and a button and hook them up to the textLabel and start IBAction. You can modify this to add hours (just minutes/seconds here) and add a timer.invalidate() where you need it.
import UIKit
class ViewController: UIViewController {
#IBOutlet var timeLabel: UILabel!
#IBAction func start(sender: AnyObject) {
var timer = NSTimer()
if !timer.valid {
let selector : Selector = "countTime"
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target:self, selector: selector, userInfo: nil, repeats: true)
startTime = NSDate.timeIntervalSinceReferenceDate()
}
let timeNow = timeNowString() as String
for item in timeNow {
time = timeNow.componentsSeparatedByString(":")
}
}
var time = [String]()
var startTime = NSTimeInterval()
override func viewDidLoad() {
super.viewDidLoad()
}
func countTime() {
var currentTime = NSDate.timeIntervalSinceReferenceDate()
var elapsedTime: NSTimeInterval = currentTime - startTime
var adjustedTime = Int(elapsedTime) + 3600*time[0].toInt()! + 60*time[1].toInt()! + time[0].toInt()!
var hours = Int(Double(adjustedTime)/3600.0)
let minutes = Int(Double(adjustedTime - hours*3600)/60.0)
let seconds = adjustedTime - hours*3600 - minutes*60
let startHours = hours > 9 ? String(hours):"0" + String(hours)
let startMinutes = minutes > 9 ? String(minutes):"0" + String(minutes)
let startSeconds = seconds > 9 ? String(seconds):"0" + String(seconds)
timeLabel.text = "\(startHours):\(startMinutes):\(startSeconds)"
}
func timeNowString() -> NSString {
let date = NSDate()
var outputFormat = NSDateFormatter()
outputFormat.locale = NSLocale(localeIdentifier:"en_US")
outputFormat.dateFormat = "HH:mm:ss"
let timeString = outputFormat.stringFromDate(date)
return timeString;
}
}

Resources