I Can't Change label.text with Timer in Swift 3 - swift

#IBOutlet var timeLabel: UILabel!
var timer = Timer()
let now = Date()
let userCalendar = Calendar.current
let formatter = DateFormatter()
func printTime() {
formatter.dateFormat = "MM/dd/yy hh/mm/ss a"
let startTime = now
let endTime = formatter.date(from: "01/01/17 00/00/00 a")
let difference = userCalendar.dateComponents([.month, .day, .year, .hour, .minute, .second], from: startTime, to: endTime!)
timeLabel.text = "Yılbaşına \(difference.month!) ay, \(difference.day!) gün, \(difference.hour!) saat, \(difference.minute!) dakika, \(difference.second!) saniye kaldı"
print("hello world")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(ViewController.printTime),
userInfo: nil,
repeats: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
When it is running
I am using Xcode 8 with Swift 3. When I run this code it is writes to console "hello world" every second but it is not update label when timer is running. I want to countdown for label for every second.

Try this:
DispatchQueue.main.after(when: .now() + 1.0) { //after one second
timeLabel.text = "Yılbaşına \(difference.month!) ay, \(difference.day!) gün, \(difference.hour!) saat, \(difference.minute!) dakika, \(difference.second!) saniye kaldı"
}

I solved. First I delete "let now = Date()" line and I changed "let startTime = Date()

Related

reset date to next hour after top of hour is reached

I Want My swift code to count down to the nearest top of the hour. So if the time is 146 the user code should count down 14 minutes. Right now My code below counts down to a spefic day and time. I just want it to count down to the nearest hour when the app is running.
import UIKit
class ViewController: UIViewController {
#IBOutlet var timerLabel: UILabel!
var timer: Timer!
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(UpdateTime), userInfo: nil, repeats: true)
}
#objc func UpdateTime() {
let userCalendar = Calendar.current
// Set Current Date
let date = Date()
let components = userCalendar.dateComponents([.hour, .minute, .month, .year, .day], from: date)
let currentDate = userCalendar.date(from: components)!
// Set Event Date
var eventDateComponents = DateComponents()
eventDateComponents.year = 2021
eventDateComponents.month = 01
eventDateComponents.day = 01
eventDateComponents.hour = 01
eventDateComponents.minute = 00
eventDateComponents.timeZone = TimeZone(abbreviation: "GMT")
let eventDate = userCalendar.date(from: eventDateComponents)!
let timeLeft = userCalendar.dateComponents([.day, .hour, .minute, ], from: currentDate, to: eventDate)
timerLabel.text = "\(timeLeft.day!)d \(timeLeft.hour!)h \(timeLeft.minute!)m "
endEvent(currentdate: currentDate, eventdate: eventDate)
}
func endEvent(currentdate: Date, eventdate: Date) {
if currentdate >= eventdate {
timerLabel.text = "Happy New Year!"
// Stop Timer
timer.invalidate()
}
}
}
edit/update:
My goal in my swift code is when the top of the hour is reached. After trying to implement #Leo's answer it prints "Top of Hour" and it does the problem is that It only does it one time. As long as the app is open I want it to print "Top of Hour" at every hour. So I need to reset the end date which is what I tried to do at
let date = Date()
end = date.nextHour
That does not let the code compile. So I have to reset the end var to the next hour.
No need to update the user interface 10 times per second. As it is it will drain the device's battery much faster than needed while it should only run once a minute. You can change your timer timeInterval to 1 second and schedule it to fire at the next even second. To get the next even hour and the next even minute you can use Calendar method
func nextDate(after date: Date, matching components: DateComponents, matchingPolicy: Calendar.MatchingPolicy, repeatedTimePolicy: Calendar.RepeatedTimePolicy = .first, direction: Calendar.SearchDirection = .forward) -> Date?
Just create two computed properties extending Date and pass zero for minute or nanosecond components:
extension Date {
var nextHour: Date {
Calendar.current.nextDate(after: self, matching: DateComponents(minute: 0), matchingPolicy: .strict)!
}
var nextSecond: Date {
Calendar.current.nextDate(after: self, matching: DateComponents(nanosecond: 0), matchingPolicy: .strict)!
}
var minute: Int {
Calendar.current.component(.minute, from: self)
}
}
Now add a property to your view controller to keep a reference of the end date. Note that there is no need to declare your timer as optional:
var end: Date?
var timer = Timer()
And create a DateComponentsFormatter to create a localized description of the remaining time:
extension Formatter {
static let minutesRemaining: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.formattingContext = .standalone
formatter.unitsStyle = .short
formatter.allowedUnits = [.minute, .second]
formatter.includesTimeRemainingPhrase = true
return formatter
}()
}
Now you just setup the end date and to schedule your timer to fire at the next even minute:
override func viewDidLoad() {
super.viewDidLoad()
// get the current date
let date = Date()
// set the end date
end = date.nextHour
// schedule the timer to fire at the next even second and set its interval to 1 second
timer = .init(fireAt: date.nextSecond, interval: 1, target: self, selector: #selector(updateUI), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: .common)
updateUI()
}
#objc func updateUI() {
if Date().minute == 0 || Date() > end {
end = Date().nextHour
timerLabel.text = "beginning of hour"
print("beginning of hour")
} else {
// update the remaining time (for a perfect sync we need to subtract a second from the current time)
let text = Formatter.minutesRemaining.string(from: Date().addingTimeInterval(-1), to: end) ?? ""
timerLabel.text = text
print(text)
}
}

UIPickerView selected time to run code

I have added in a UIPickerView and currently have it store the selected time as a string. I want the app to carry out a simple line of code when the time that was selected on the pickerview is the time in the real world. Here is the code that I have added.
For the Clock, used to find the real world time:
let clockString: String = formatADate()
func formatADate() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
dateFormatter.dateFormat = "hh:mm:ss a"
let date = NSDate()
let output = dateFormatter.string(from: date as Date)
print(output)
return output
}
Here is the code for the UIPickerView:
#IBOutlet var dateTimeDisplay: UILabel!
#IBOutlet var datePicker: UIDatePicker!
#IBAction func datePickerchanged(_ sender: Any) {
setDateAndTime()
}
func setDateAndTime() {
let formatter = DateFormatter()
formatter.dateFormat = "hh:mm:ss a"
_ = formatter.string(from: datePicker.date)
str = dateFormatter.string(from: (datePicker?.date)!)
dateTimeDisplay.text = str
}
And here is what I want to happen when the selected time and the real world time match up:
takePhoto = true
When the pick date the start one timer function
call the function in picker
var timercount = Timer()
viewdidload()
{
timercount = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(Check), userInfo: nil, repeats: true)
}
Func Check()
{
let nowdate = NSDate()//two date declare global Var
let date2 = datePicker?.date //chek the Time How Much Time Remain
let elapsed = date2?.timeIntervalSince(nowdate as Date)
if Int(elapsed!) == 0
{
takePhoto = true
}
}

Swift countdown timer- displays days hours seconds remaining

Hello I am very new to swift and I was trying to create an app that counts down to an event on a specific date. I want it to show the number of days hours and seconds left until the specified date but I cannot figure out how to do this.
Please help!
Swift 4
var releaseDate: NSDate?
var countdownTimer = Timer()
func startTimer() {
let releaseDateString = "2018-09-16 08:00:00"
let releaseDateFormatter = DateFormatter()
releaseDateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
releaseDate = releaseDateFormatter.date(from: releaseDateString)! as NSDate
countdownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
}
#objc func updateTime() {
let currentDate = Date()
let calendar = Calendar.current
let diffDateComponents = calendar.dateComponents([.day, .hour, .minute, .second], from: currentDate, to: releaseDate! as Date)
let countdown = "Days \(diffDateComponents.day ?? 0), Hours \(diffDateComponents.hour ?? 0), Minutes \(diffDateComponents.minute ?? 0), Seconds \(diffDateComponents.second ?? 0)"
print(countdown)
}
This works like a charm:
var releaseDate: NSDate?
override func viewDidLoad() {
super.viewDidLoad()
let releaseDateString = "2016-03-02 22:00:00"
let releaseDateFormatter = NSDateFormatter()
releaseDateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
releaseDate = releaseDateFormatter.dateFromString(releaseDateString)!
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "countDownDate", userInfo: nil, repeats: true)
}
func countDownDate() {
let currentDate = NSDate()
let diffDateComponents = NSCalendar.currentCalendar().components([NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second], fromDate: currentDate, toDate: releaseDate!, options: .MatchFirst)
let countdown = "Months: \(diffDateComponents.month), Days: \(diffDateComponents.day), Hours: \(diffDateComponents.hour), Minutes: \(diffDateComponents.minute), Seconds: \(diffDateComponents.second)"
print(countdown)
}
Swift 3
var releaseDate: Date?
override func viewDidLoad() {
super.viewDidLoad()
let releaseDateFormatter = DateFormatter()
releaseDateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
releaseDate = releaseDateFormatter.date(from:releaseDateString!)!
Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.countDownDate), userInfo: nil, repeats: true)
}
func countDownDate() {
let date = Date()
let calendar = Calendar.current
let diffDateComponents = calendar.dateComponents([.day, .hour, .minute, .second], from: date, to: releaseDate!)
let countdown = "Days \(diffDateComponents.day), Hours: \(diffDateComponents.hour), Minutes: \(diffDateComponents.minute), Seconds: \(diffDateComponents.second)"
print(countdown)
}
This is what I had to do for my app.
import UIKit
import Foundation
var timer = Timer()
var currentTime = Date()
var compareTime = Date().addingTimeInterval(-21600)
func setupButtonTitle()
{
if UserDefaults.standard.object(forKey: "count6") == nil
{
button.setTitle("PRESS", for: .normal)
button.backgroundColor = .green
}
else
{
button.setTitle("PRESS" + "\nIN " + "\(startTimer()))" , for: .normal)
}
button.addTarget(self, action: #selector(buttonTap), for: .touchUpInside)
}
func startTimer()
{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(sixHourCountdown), userInfo: nil, repeats: true)
}
#objc func sixHourCountdown()
{
let timeStarted = UserDefaults.standard.object(forKey: "count6")
let timeStart = timeStarted as! Date
let diffComponents = Calendar.current.dateComponents([.hour, .minute, .second], from: compareTime, to: timeStart)
let hour = diffComponents.hour!
let minute = diffComponents.minute!
let second = diffComponents.second!
let timeRemaining = String(format: "%02d:%02d:%02d", hour, minute, second)
compareTime += 1
if hour == 0 && minute == 0 && second == 0 || timeStart < compareTime
{
button.setTitle("PRESS", for: .normal)
button.backgroundColor = .green
timer.invalidate()
}
else
{
button.setTitle("PRESS IN" + "\n\(timeRemaining)", for: .normal)
}
}
#objc func buttonTap()
{
if button.currentTitle != "PRESS"
{
button.backgroundColor = .red
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute:
{
button.backgroundColor = .yellow
})
}
if button.currentTitle == "PRESS" && button.backgroundColor == .green
{
UserDefaults.standard.set(currentTime, forKey: "count6")
let otherVC = OTHERVC()
self.navigationController?.pushViewController(otherVC, animated: true)
}
}
override func viewDidLoad() {
super.viewDidLoad()
setupButtonTitle()

How can I extract number of years, months, and days since a date in Swift

How can I extract number of years, months, and days since a date in Swift.
So far I have the follow code in a class file named DatePickerController.
class DatePickerController: UIViewController {
#IBOutlet var datePicker:UIDatePicker!
#IBOutlet var dateDisplay: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func datePickerChanged(sender: AnyObject) {
setDate()
}
let dateFormatter = NSDateFormatter()
// MARK: - Date Format
func setDate() {
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
dateDisplay.text = dateFormatter.stringFromDate(datePicker.date)
}
}
I will create separate UILables for year, month, and day right.
Like you said, you will need UILabel's for each of the date components. You can then extract the components using custom date formatting strings instead of using NSDateFormatterStye.ShortStyle. This gives you the most flexibility. The formatting strings follow a unicode standard.
I can't test the code in the context of your project, but if you add the labels and connect them correctly to Xcode, I believe that this code will do exactly what you want:
class DatePickerController: UIViewController {
#IBOutlet var datePicker:UIDatePicker!
#IBOutlet var dayDisplay: UILabel!
#IBOutlet var monthDisplay: UILabel!
#IBOutlet var yearDisplay: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func datePickerChanged(sender: AnyObject) {
setDate()
}
let dateFormatter = NSDateFormatter()
// MARK: - Date Format
func setDate() {
dateFormatter.dateFormat = "dd"
dayDisplay.text = dateFormatter.stringFromDate(datePicker.date)
dateFormatter.dateFormat = "MM"
monthDisplay.text = dateFormatter.stringFromDate(datePicker.date)
dateFormatter.dateFormat = "yyyy"
yearDisplay.text = dateFormatter.stringFromDate(datePicker.date)
}
}
You can use NSCalendar to get the NSDateComponents between two dates. In Swift 3:
let components = Calendar.current.dateComponents([.day, .month, .year], from: date1, to: date2)
let dayString = "\(components.day!)"
let monthString = "\(components.month!)"
let yearString = "\(components.year!)"
Or in Swift 2:
let components = NSCalendar.currentCalendar().components([.Day, .Month, .Year], fromDate: date1, toDate: date2, options: [])
let dayString = "\(components.day)"
let monthString = "\(components.month)"
let yearString = "\(components.year)"
Perhaps easier, if you'd like to have a single string that represents the elapsed time between these two dates, you'd use NSDateComponentsFormatter, e.g., in Swift 3:
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.day, .month, .year]
formatter.unitsStyle = .full
let string = formatter.string(from: date1, to: date2)
Or in Swift 2:
let formatter = NSDateComponentsFormatter()
formatter.allowedUnits = [.Day, .Month, .Year]
formatter.unitsStyle = .Full
let string = formatter.stringFromDate(date1, toDate: date2)
This string is localized, too.
You can use NSDateComponents to retrieve year, month and day by using method components(fromDate: toDate: options:) of NSCalender
Example
let date = NSDate(timeIntervalSinceNow: -123123123)
extension NSDate {
func intereval(date:NSDate) -> (year: Int, month:Int, day:Int) {
let calender = NSCalendar.currentCalendar()
let components = calender.components([.Year, .Month, .Day], fromDate: date, toDate: self, options:.MatchStrictly)
return (components.year, components.month, components.day)
}
}
let component = NSDate().intereval(date)
print(component.year)
print(component.month)
print(component.day)
import Foundation
let now = NSDate()
now.description.characters.split {
" -".characters.contains($0)
}.enumerate().forEach {
print($0.0,String($0.1))
}
/*
0 2015
1 12
2 26
3 19:34:33
4 +0000
*/

Swift: Cannot convert value of type 'NSDate' to expected argument type 'NSDateComponents'

Anyone know how i can solve this? I get this error:
¨cannot convert value of type 'NSDate' to expected argument type 'NSDateComponents'¨ on line:
The error occurred at the line:
let competitionDay = userCalendar.dateFromComponents(competitionDate)!
This is a more complete excerpt of the code:
func Date() {
// Here we set the current date
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Hour, .Minute, .Second, .Nanosecond], fromDate: date)
let hour = components.hour
let minutes = components.minute
let month = components.month
let year = components.year
let day = components.day
let currentDate = calendar.dateFromComponents(components)
// here we set the due date. When the timer is supposed to finish
// final Calendar value
let userCalendar = NSCalendar.currentCalendar()
let competitionDate:NSDate = myDatePicker.date
competitionDate.timeIntervalSinceNow
let competitionDay = userCalendar.dateFromComponents(competitionDate)!
// Here we compare the two dates
competitionDay.timeIntervalSinceDate(currentDate!)
let dayCalendarUnit = calendar.components([NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute], fromDate: date)
//here we change the seconds to hours,minutes and days
let competitionDayDifference = calendar.components([.Day, .Hour, .Minute],
fromDate: currentDate!, toDate: competitionDay, options: NSCalendarOptions())
//finally, here we set the variable to our remaining time
let daysLeft = competitionDayDifference.day
let hoursLeft = competitionDayDifference.hour
let minutesLeft = competitionDayDifference.minute
In your original question you were calling dateFromComponents, which converts a NSDateComponents to a NSDate, but supplied it a competitionDate, which is already a NSDate. And the compiler was simply informing you of this error.
--
As an aside, you populate a NSDateComponents with the .Hour, .Minute, .Second, and .Nanosecond from a NSDate, but then proceed to try to save references to the components.year and components.month and components.day even though you didn't specify that those components should be included in the NSDateComponents.
--
Below you say:
It's a Countdown app and i had it running until i wanted a DatePicker to choose the date i am counting down. The competitionDate is the due date
If that's indeed what you want, then perhaps NSDateComponents isn't needed at all. I'd probably just use NSDateComponentsFormatter method stringFromDate:toDate: to show the user a nice string representation of the amount of time between two NSDate objects.
For example:
class ViewController: UIViewController {
#IBOutlet weak var datePicker: UIDatePicker!
#IBOutlet weak var label: UILabel!
weak var timer: NSTimer?
let formatter: NSDateComponentsFormatter = {
let _formatter = NSDateComponentsFormatter()
_formatter.allowedUnits = [.Year, .Month, .Day, .Hour, .Minute, .Second]
_formatter.unitsStyle = .Full
return _formatter
}()
override func viewDidLoad() {
super.viewDidLoad()
datePicker.date = NSDate().dateByAddingTimeInterval(1000) // initialize it to whatever you want
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "didFireTimer:", userInfo: nil, repeats: true)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
timer?.invalidate()
}
func didFireTimer(timer: NSTimer) {
label.text = formatter.stringFromDate(NSDate(), toDate: datePicker.date)
}
}