I work with decimal times in Lua and make arithmetical operations on them.
For example 124500+5=124505 (12:45:05)
What formula can avoid 60 digits problem?
124459+5=124504 (not 124464)
How can I resolve it?
You are mixing formation with calculation. The best way is to transform your time "string" in a real number:
12:45:05 -> 12 * 60 * 60 + 45 * 60 + 05 = 45905
The function could look like this:
function time_to_number(t)
return (math.floor(t / 10000) * 60 * 60) + ((math.floor(t / 100) % 100) * 60) + (t % 100)
-- you can also use % 10000 if the hours are limited to two digits
end
Now you can calculate on the seconds.
To format the value back you can use this function
function time_split(t)
local hour = math.floor(t / 3600)
local min = math.floor((t % 3600) / 60)
local sec = (t % 3600) % 60
return hour, min, sec
end
I have used many brackets for readability, which are not all required.
Related
Modified Question.
My fitness app will calculate the number of calories burned based on a calculated value for each second. I have a timer that will allow the app to pick back up should it. I can't get the running sum to continue calculating when the app goes into the background. I tried to place the running sum inside of a DispatchQueue but not getting the sum as expected. Any guidance is greatly appreciated.
Here's the code I have placed inside the function that updates the timer.
//MARK: - Update Timer Label
func updateTimerLabel() {
interval = -Int(timerStartDate.timeIntervalSinceNow)
time = interval
let hours = interval / 3600
let minutes = interval / 60 % 60
let seconds = interval % 60
print("Current interval = \(interval)")
timerLabel.text = String(format:"%02i:%02i:%02i", hours, minutes, seconds)
DispatchQueue.global(qos: .background).async {
if self.activityArray[self.currentArrayRow].2 <= 4.5 {
self.cps = self.activityArray[self.currentArrayRow].2 * Double(self.user.userWeightInKilo) / 3600
self.runningCPS = self.runningCPS + self.cps
print("MET \(self.activityArray[self.currentArrayRow].2) <= 4.5 * KG (\(Double(self.user.userWeightInKilo))) * HR (\(Double(self.user.userHeartRate))) / MaxHR (\(Double(self.user.maxHeartRate)) * interval \(Double(self.interval)) / 3600. Gives a cps 0f \(self.cps) and a runningCPS of \(self.runningCPS) ")
} else {
self.cps = self.activityArray[self.currentArrayRow].2 * Double(self.user.userWeightInKilo) * Double(self.user.userHeartRate) / Double(self.user.maxHeartRate) / 3600
self.runningCPS = self.runningCPS + self.cps
print("MET \(self.activityArray[self.currentArrayRow].2) > 4.5 * KG (\(Double(self.user.userWeightInKilo))) * HR (\(Double(self.user.userHeartRate))) / MaxHR (\(Double(self.user.maxHeartRate)) * interval \(Double(self.interval)) / 3600. Gives a cps 0f \(self.cps) and a runningCPS of \(self.runningCPS) ")
}
}
activeLabel.text = String(format: "%0.1f", runningCPS) + " Calories Burned"
}
I need a simple function to convert seconds into a time string that humans can read to represent the countdown. I can get the results what I need through very intuitive mathematical calculations, but not elegant enough.
Then I noticed that there is a function named os.date, but I can't get the result I want, what is wrong with my calling, here is my code:
#!usr/bin/env lua
local function getDate1(sec)
local days = math.floor(sec / 86400)
local hours = math.floor((sec % 86400) / 3600)
local minutes = math.floor((sec % 3600) / 60)
local seconds = math.floor(sec % 60)
return days, hours, minutes, seconds
end
local function getDate2(sec)
local date = os.date("*t", sec)
return date["day"], date["hour"], date["min"], date["sec"]
end
local function printDate(d, h, m, s)
print(string.format("%02d %02d:%02d:%02d", d, h, m, s))
end
function main()
printDate(getDate1(999999))
printDate(getDate2(999999))
end
main()
11 13:46:39
12 21:46:39
local function getDate2(sec)
local date = os.date("!*t", sec)
return date["day"]-1, date["hour"], date["min"], date["sec"]
end
I get the following error when using code for an extension, I'm not sure if they're asking to just use a different operator or modify the values in the expression based on an internet search.
Error: % is unavailable: Use truncatingRemainder instead
Extension code:
extension CMTime {
var durationText:String {
let totalSeconds = CMTimeGetSeconds(self)
let hours:Int = Int(totalSeconds / 3600)
let minutes:Int = Int(totalSeconds % 3600 / 60)
let seconds:Int = Int(totalSeconds % 60)
if hours > 0 {
return String(format: "%i:%02i:%02i", hours, minutes, seconds)
} else {
return String(format: "%02i:%02i", minutes, seconds)
}
}
}
The error(s) occur when setting the minutes and seconds variables.
CMTimeGetSeconds() returns a floating point number (Float64 aka
Double). In Swift 2 you could compute the
remainder of a floating point division as
let rem = 2.5 % 1.1
print(rem) // 0.3
In Swift 3 this is done with
let rem = 2.5.truncatingRemainder(dividingBy: 1.1)
print(rem) // 0.3
Applied to your code:
let totalSeconds = CMTimeGetSeconds(self)
let hours = Int(totalSeconds / 3600)
let minutes = Int((totalSeconds.truncatingRemainder(dividingBy: 3600)) / 60)
let seconds = Int(totalSeconds.truncatingRemainder(dividingBy: 60))
However, in this particular case it is easier to convert the duration
to an integer in the first place:
let totalSeconds = Int(CMTimeGetSeconds(self)) // Truncate to integer
// Or:
let totalSeconds = lrint(CMTimeGetSeconds(self)) // Round to nearest integer
Then the next lines simplify to
let hours = totalSeconds / 3600
let minutes = (totalSeconds % 3600) / 60
let seconds = totalSeconds % 60
The % modulus operator is defined only for integer types. For floating-point types, you need to be more specific about the kind of IEEE 754 division/remainder behavior you want, so you have to call a method: either remainder or truncatingRemainder. (If you're doing floating-point math you actually need to care about this, and lots of other stuff, or you can get unexpected / bad results.)
If you actually intend to do integer modulus, you need to convert the return value of CMTimeGetSeconds to an integer before using %. (Note that if you do, you'll lop off the fractional seconds... depending on where you're using CMTime that may be important. Do you want minutes:seconds:frames, for example?)
Depending on how you want to present CMTime values in your UI, it might be better to extract the seconds value and pass it to NSDateFormatter or NSDateComponentsFormatter so you get appropriate locale support.
Bring back the simple modulo syntax in swift 3:
This syntax was actually suggested on Apples official swift mailing list here but for some reason they opted for a less elegant syntax.
infix operator %%/*<--infix operator is required for custom infix char combos*/
/**
* Brings back simple modulo syntax (was removed in swift 3)
* Calculates the remainder of expression1 divided by expression2
* The sign of the modulo result matches the sign of the dividend (the first number). For example, -4 % 3 and -4 % -3 both evaluate to -1
* EXAMPLE:
* print(12 %% 5) // 2
* print(4.3 %% 2.1) // 0.0999999999999996
* print(4 %% 4) // 0
* NOTE: The first print returns 2, rather than 12/5 or 2.4, because the modulo (%) operator returns only the remainder. The second trace returns 0.0999999999999996 instead of the expected 0.1 because of the limitations of floating-point accuracy in binary computing.
* NOTE: Int's can still use single %
* NOTE: there is also .remainder which supports returning negatives as oppose to truncatingRemainder (aka the old %) which returns only positive.
*/
public func %% (left:CGFloat, right:CGFloat) -> CGFloat {
return left.truncatingRemainder(dividingBy: right)
}
This simple swift 3 migration tip is part of a more comprehensive swift 3 migration guide with many insights (35k loc / 8-days of migration) http://eon.codes/blog/2017/01/12/swift-3-migration/
There's no need to create a separate modulo operator for floating point numbers, unless you think it makes the code safer. You can overload the % operator to accept floating point numbers like so:
func %<N: BinaryFloatingPoint>(lhs: N, rhs: N) -> N {
lhs.truncatingRemainder(dividingBy: rhs)
}
Usage
let a: Float80 = 10
let b: Float80 = 3
print(a % b)
You can now use % with any two floating point numbers of the same tye.
I found that the following works in Swift 3:
let minutes = Int(floor(totalSeconds / 60))
let seconds = Int(totalSeconds) % 60
where totalSeconds is a TimeInterval (Double).
I have the following function:
function timestamp(duration)
local hours = duration / 3600
local minutes = duration % 3600 / 60
local seconds = duration % 60
return string.format("%02d:%02d:%02.03f", hours, minutes, seconds)
end
when the duration is 4.404 sec it returns 00:00:4.404
what is am looking for is 00:00:04.404
It should be:
string.format("%02d:%02d:%06.3f", hours, minutes, seconds)
Field width contains all characters of the number, including point and fraction.
The task is to Write a method that will take in a number of minutes, and returns a string that formats the number into hours:minutes.
here's what I have so far:
def time_conversion(minutes)
minutes = (minutes / 60) % 60
hours = minutes / (60 * 60)
format(" %02d:%02d ", hours, minutes)
return format
end
it's not working out for me
Try this
def time_conversion(time)
minutes = time % 60
hours = time / 60
minutes = (minutes < 10)? "0" + minutes.to_s : minutes.to_s
return hours.to_s + ":" + minutes
end
Using division in Ruby returns a whole number, lowered to the previous number. Using modulus returns the remainder after division.
Ruby's Numeric#divmod is exactly what you want here. It returns both the quotient and remainder of a division operation, so e.g. 66.divmod(60) returns [ 1, 6 ]. Combined with sprintf (or String#%, it makes for an extremely simple solution:
def time_conversion(minutes)
"%02d:%02d" % minutes.divmod(60)
end
puts time_conversion(192)
# => 03:12
Well try
h = minutes/60
M = minutes%60