Replacing NSDate value if two NSDate objects aren't equal - xcode

basically I'm writing an app and I want some of its values to update weekly - so, using NSDate and NSUserDefaults I currently have this scenario set out:
let userDefaults = NSUserDefaults.standardUserDefaults()
var startOfWeek: NSDate?
The above is global^
var referenceDate = NSDate.timeIntervalSinceReferenceDate()
while referenceDate > 604800 {
if referenceDate > 604800 {
referenceDate -= 604800
}
This basically takes the amount of seconds that have elapsed since the 1st of Jan 2001 and subtracts 604800, which is the amount of seconds in a week, until you have an amount of seconds that is less than a week. This amount of seconds is basically the amount of seconds into the week, you're in.
After this I then create a variable which is just the negative of how many seconds into the week we are, a variable which is the current time and use them to create a new date object which is the start point for the week:
var weekTimer: NSTimeInterval = (-referenceDate)
var startOfWeek = userDefaults.objectForKey("startOfWeekKey") as? NSDate
var currentTime = NSDate(timeIntervalSinceNow: 0)
if startOfWeek == nil {
startOfWeek = NSDate(timeInterval: weekTimer, sinceDate: currentTime)
userDefaults.objectForKey("startOfWeekKey")
}
else {
}
So basically it creates a value for the start of the week and saves it to NSUserDefaults under the key "startOfWeekKey" if the value doesn't already exist. If the value does already exist, because it's already been saved, it's happy with this value and nothing happens.
Now, we create a new value to compare to our startOfWeek value so we can test if we enter a new week.
var startOfWeekCheck = NSDate(timeInterval: weekTimer sinceDate: currentTime)
Now we compare them:
if startOfWeek! == startOfWeekCheck {
}
else {
println("New week begins") //update other, irrelevant stuff here
startOfWeek = startOfWeekCheck
}
No matter what, new week begins is always printed, I added the following line to check what was happening:
println("\(startOfWeek!) \(startOfWeekCheck)")
And it prints the same value to the logs
I'm pretty unsure what to do at this point. Did I mess up? Can you not compare the two date objects like that? Is this a ridicuously inefficient manner to create a way to reset/change something once a week?
Note, this is not the exact code, I typed this all by hand because the code is on my macbook and I'm on my desktop, so if there are any typos / w/e don't worry about it, no compile errors on my mac.
Thanks!

This looks way too complicated. There is no need to do all the date calculations yourself. Especially because you do them wrong. Not every week has 604800 seconds. In many timezones you have one week per year which has 601200 seconds, and one week which has 608400 seconds. Also known as Daylight saving time. There are even countries that skipped a whole day in one year.
You have to use NSCalendar and NSDateComponents for correct date calculations.
But I would do it completely different:
Save the next refresh date in NSUserDefaults (default to distantPast)
If today >= next refresh date: refresh & write new refresh date.
Something like this:
let calendar = NSCalendar.currentCalendar()
// If nextRefreshDate was never written by us (i.e. first start of app) it will containt distantPast, which is in year 1 or so
NSUserDefaults.standardUserDefaults().registerDefaults(["nextRefreshDate" : NSDate.distantPast()])
// since we registered a default value we will always receive a valid NSDate object, so we can force unwrap
let nextRefreshDate = NSUserDefaults.standardUserDefaults().objectForKey("nextRefreshDate") as NSDate
// equivalent to: (nextRefreshDate < today) || (nextRefreshDate == today)
if nextRefreshDate.compare(NSDate()) != NSComparisonResult.OrderedDescending {
println("Refresh")
let refreshSuccess = true // get from your internet download code
if refreshSuccess {
// don't save the next refresh date until the refresh was actually sucessful. This makes sure that we refresh on next launch if this refresh fails for some reason
var startOfCurrentWeek: NSDate?
if calendar.rangeOfUnit(.CalendarUnitWeekOfMonth, startDate: &startOfCurrentWeek, interval: nil, forDate: NSDate()) {
if let startOfCurrentWeek = startOfCurrentWeek {
if let startOfNextWeek = calendar.dateByAddingUnit(.CalendarUnitWeekOfMonth, value: 1, toDate: startOfCurrentWeek, options: nil) {
NSUserDefaults.standardUserDefaults().setObject(startOfNextWeek, forKey: "nextRefreshDate")
println("Next refresh scheduled for \(startOfNextWeek)")
}
}
}
}
}
else {
println("No refresh necessary. Next refresh scheduled for \(nextRefreshDate)")
}

Related

How to make UIImage move every hour?

Hey so I'm working on a simple app and I want this image on a map to move closer hour by hour towards the user location. I can't figure out where to start, can anyone help?
Thanks!
Swift has a Timer class. There are several overloads for Timer.init. The newer block based one works like this:
let hour = TimeInterval(60 * 60) //60 seconds per min * 60 min per hour = 360 seconds per hour
let timer = Timer.init(timeInterval: hour, repeats: true) { timer in
//Do hourly update stuff here
}

Swift 2 get minutes and seconds from double

I am currently storing time in seconds (for example 70.149 seconds). How would I easily get the minutes and seconds? What I mean is 70.149 seconds is 1min and 10sec. How would I be able to do this easily in swift?
Here is an example of what I want to do.
let time:Double = 70.149 //This can be any value
let mins:Int = time.minutes //In this case it would be 1
let secs:Int = time.seconds //And this would be 10
How would I do this using Swift 2 OS X (not iOS)
Something like this:
let temp:Int = Int(time + 0.5) // Rounding
let mins:Int = temp / 60
let secs:Int = temp % 60
This would be a relatively simple solution. It's worth noting this would truncate partial seconds. You'd have to use floating point math on the third line and call trunc()/ceil()/floor() on the result before conversion to an Int if you wanted control over that.
let time:Double = 70.149 //This can be any value
let mins:Int = Int(time) / 60 //In this case it would be 1
let secs:Int = Int(time - Double(mins * 60)) //And this would be 10
Swift 5
The date components formatter has lots of advantages when displaying human readable text to a user. This function will take a double.
func humanReadable(time:Double) -> String {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .full
if let str = formatter.string(from: time) {
return str
}
return "" // empty string if number fails
}
// will output '1 minute, 10 seconds' for 70.149

How to set time to a variable without the date

I am trying to set a specific time to two variables but can't seem to correctly format the syntax. I want to be able to set Shift 1 and Shift 2 off of certain times indicated below.
I want to only be able to use these times in an IF statement so that a radio button can be checked by default. Day Shift button and a Night Shift button. If the current time is in between shift 1, then day shift button is checked.
Date.prototype.currentTime = function(){
return ((this.getHours()>12)?(this.getHours()-12):this.getHours()) +":"+ this.getMinutes()+((this.getHours()>12)?('PM'):'AM'); };
var d1= new Date();
var d2 = new Date();
d1.setHours(7);
d1.setMinutes(10);
d2.setHours(19);
d2.setMinutes(10);
alert(d1.currentTime());
alert(d2.currentTime());
Thanks Any help is appreciated.
You do not need to compare Date objects for your use,
just compare the hours as integers to the integer from now.getHours():
var now= new Date().getHours();
if(now>6 && now<19){
//check day shift button;
}
// else check niteshift button
You may try this:
http://jsfiddle.net/apq59j9u/
Date.prototype.currentTime = function(){
return ((this.getHours()>12)?(this.getHours()-12):this.getHours()) +":"+ this.getMinutes()+((this.getHours()>12)?('PM'):'AM'); };
var d1= new Date();
var d2 = new Date();
d1.setHours(7);
d1.setMinutes(10);
d2.setHours(19);
d2.setMinutes(10);
alert(d1.currentTime());
alert(d2.currentTime());
Getting the Data
There are a number of different ways to do this. First here is a way to get the data from the date object:
var d = new Date();
var n = d.toTimeString();
Unfortunately, this will output something like "12:30:30 GMT-0500 (Eastern Standard Time)"
You can also try the getHours() and getMinutes functions to get the hours and minutes in your current timezone.
var d = new Date();
var hours = d.getHours();
var minutes = d.getMinutes();
Setting the Data
This is pretty easy to do, just as getting the data from a date object. Use the following code to set the time to what you would like. Replace the numbers where you see 11 to conform to your needs.
NOTE: This time is in military style hours! 1 = 1am, 13 = 1pm, ect.
var d = new Date();
d.setHours(11);
d.setMinutes(11);
d.setSeconds(11);
Result: 11:11:11

Swift - using timers/system clock/background threads to do something in my application every hour

I'm using:
var alarm = NSUserNotification()
var currentTime = NSDate()
alarmTime = currentTime.dateByAddingTimeInterval(60)
alarm.deliveryDate = alarmTime
NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification(alarm)
To get a notification that will fire an hour from the current time, the problem is I want the app to automatically set up another alarm after the first one finishes. NSTimer doesn't seem like it will work because once the app goes to the background it kills the timer. What can I do to achieve this? Can I piggy back another method onto a NSUserNotification
Edit: it also needs to be dynamic, I can't just set the repeat variable of the notification because I need to be able to switch how far out the alarm will be each time it resets.
You just have to set your deliveryRepeatInterval and deliveryTimeZone, as follow:
// set your deliveryTimeZone to localTimeZone
alarm.deliveryTimeZone = NSTimeZone.localTimeZone()
// The date components that specify how a notification is to be repeated.
// This value may be nil if the notification should not repeat.
// alarm.deliveryRepeatInterval = nil
// The date component values are relative to the date the notification was delivered.
// If the calendar value of the deliveryRepeatInterval is nil
// the current calendar will be used to calculate the repeat interval.
// alarm.deliveryRepeatInterval?.calendar = NSCalendar.currentCalendar()
// to repeat every day, set .deliveryRepeatInterval.day to 1.
alarm.deliveryRepeatInterval?.day = 1
// to repeat every hour, set .deliveryRepeatInterval.hour to 1.
alarm.deliveryRepeatInterval?.hour = 1
alarm.deliveryDate = NSDate().dateByAddingTimeInterval(60)
NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification(alarm)

Swift: Repeat action after a random period of time

Previously, with Objective-C I could use performSelector: in order to repeat an action after a random period of time which could vary between 1-3 seconds. But since I'm not able to use performSelector: in Swift, I've tried using "NSTimer.scheduledTimerWithTimeInterval". And it works in order to repeat the action. But there is a problem. On set the time variable to call a function that will generate a random number. But it seems that NSTimer uses the same number every time it repeats the action.
What that means is that the action is not performed randomly, but instead, after a set period of time that is generated randomly at the beginning of the game and it is used during all the game.
The question is: Is there any way to set the NSTimer to create a random number every time it executes the action? Or should I use a different method? Thanks!
#LearnCocos2D is right... use SKActions or the update method in your scene. Here is a basic example of using update to repeat an action after a random period of time.
class YourScene:SKScene {
// Time of last update(currentTime:) call
var lastUpdateTime = NSTimeInterval(0)
// Seconds elapsed since last action
var timeSinceLastAction = NSTimeInterval(0)
// Seconds before performing next action. Choose a default value
var timeUntilNextAction = NSTimeInterval(4)
override func update(currentTime: NSTimeInterval) {
let delta = currentTime - lastUpdateTime
lastUpdateTime = currentTime
timeSinceLastAction += delta
if timeSinceLastAction >= timeUntilNextAction {
// perform your action
// reset
timeSinceLastAction = NSTimeInterval(0)
// Randomize seconds until next action
timeUntilNextAction = CDouble(arc4random_uniform(6))
}
}
}
use let wait = SKAction.waitForDuration(sec, withRange: dur) in your code. SKAction.waitForDuration with withRange parameter will compute random time interval with average time = sec and possible range = dur
Generate a random time yourself and use dispatch_after to do the action.
For more information on dispatch_after, see here. Basically you can use this instead of performSelector

Resources