How to create a countdown timer for a Readme.md - github

I got this project that I'm collaborating on with other collaborators, the project is divided into stages, and each stage has it's time frame. I wanna create a countdown timer that should always show on the README.md file on github so that whenever a collaborator visits the github repo, he/she see the time remaining for that very stage to be finished.
Something like this:
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (--timer < 0) {
timer = duration;
}
}, 1000);
}
window.onload = function () {
var fiveMinutes = 60 * 5,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
};
<body>
<div>Stage one ends in <span id="time">05:00</span> minutes!</div>
</body>
But I will not want it to trigger the next stage automatically after the first stage is done, I will love to be the one to trigger the countdown timer again for the next stage.
NOTE: I am asking on how to implement this on a README.md file for github

Related

Dart | Convert seconds to DateTime without calculate

Sometimes we need day, hour, minute, second to countdown, but what we know just second.
For example:
1s -> 0day 0hour 0minute 1s
10s -> 0day 0hour 0minute 10s
100s -> 0day 0hour 1minute 40s
Here is my solution:
void _test() {
var diffseconds = 100;
var seconds = diffseconds % 60;
var minute = diffseconds ~/ 60 % 60;
var hour = diffseconds ~/ 60 ~/ 60 % 24;
var day = diffseconds ~/ 60 ~/ 60 ~/ 24;
print('day=$day');
print('hour=$hour');
print('minute=$minute');
print('second=$seconds');
}
If I can change second to DateTime, I can get day easily with date.day and so on and I don't need to calculate anymore.
So I wonder is there any api or simple way to achieve it without any calculate.
I wonder better solution.
I don't think this functionality is built into Dart but you can somewhat easy add the following extension to Duration which are more or less what you are already are doing:
extension RestTimeOnDuration on Duration {
int get inDaysRest => inDays;
int get inHoursRest => inHours - (inDays * 24);
int get inMinutesRest => inMinutes - (inHours * 60);
int get inSecondsRest => inSeconds - (inMinutes * 60);
int get inMillisecondsRest => inMilliseconds - (inSeconds * 1000);
int get inMicrosecondsRest => inMicroseconds - (inMilliseconds * 1000);
}
void main() {
const duration = Duration(seconds: 123);
print('Days: ${duration.inDaysRest}'); // 0
print('Hours: ${duration.inHoursRest}'); // 0
print('Minutes: ${duration.inMinutesRest}'); // 2
print('Seconds: ${duration.inSecondsRest}'); // 3
print('Milliseconds: ${duration.inMillisecondsRest}'); // 0
print('Microseconds: ${duration.inMicrosecondsRest}'); // 0
}
Just use Duration(seconds: seconds), it handles values more than 60.
Duration(seconds: 123) // 2 minutes and 3 seconds

How to convert the time to minutes of Timer

I have this time that starts when a product is initialized and I want to format it to 00:00 instead of just 0.
Timer _timer;
_startTimer(prod) {
prod.tempo = 0;
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {
prod.tempo++;
});
});
}`
[you can se the time in red I want to convert][1]
[1]: https://i.stack.imgur.com/vCv7p.jpg
If you have a total number of seconds, you can pretty print it with:
String toTimeField(int n) => n.toString().padLeft(2, '0');
var seconds = totalSeconds % 60;
var minutes = totalSeconds ~/ 60;
var prettyDuration = '${toTimeField(minutes)}:${toTimeField(seconds)}`;
That said, if you want to measure a duration, you're usually better off keeping track of the starting time and then computing the difference with the current time. That prevents accumulating error if there are any timing discrepancies from when your callback fires. You can use DateTime.now() to get the current time, store it, and then when your callback fires, call DateTime.now() again and subtract the original value. Or use the Stopwatch class, which does that for you. Using Stopwatch and Duration, you'd do:
_startTimer(prod) {
prod.stopwatch = Stopwatch();
...
}
...
final elapsed = prod.stopwatch.elapsed;
var seconds = elapsed.inSeconds % 60;
var minutes = elapsed.inMinutes;
Finally, I also recommend avoiding using : when printing durations since it could easily be misinterpreted. Does 12:34 represent a time? Does it represent 12 hours and 34 minutes or 12 minutes and 34 seconds? Printing durations as 12m34s is much clearer.
You can format the String as follows:
var seconds = prod.tempo % 60;
var minutes = (prod.tempo - seconds) / 60;
//if you have less than 10 seconds/minutes, prepend a '0':
String secondsAsString = seconds < 10 ? '0$seconds' : seconds;
String minutesAsString = minutes < 10 ? '0$minutes' : minutes;
String displayTime = 'Tempo: ' + secondsAsString + ':' + minutesAsString;

Using perform(afterDelay:) within a while loop gives me a logic error?

I am making a timer program which uses a slider to set a timer value and then updates a digital clock display to show the corresponding numerical time remaining as image files.
I am trying to run a 1 second delay function within a while loop, and update the image files each second, essentially trying to create a timer which updates the variables used to determine which images are used in real time.
I am having difficulty assigning counting down correctly: the variables used to set the image files h, min1 and min2 are set to 0 after a 1 second delay. It seems that the while loop calls the delay function once, iterates until the condition is met without delaying the timer and then displays the final values.
I've tried different methods of timing a 1 second delay including using the let timer = Timer. approach and DispatchQueue.main. approach but they don't seem to work.
#IBAction func slider(_ sender: UISlider)
{
self.x = Int(sender.value)
// Note I omitted the rest of this code as it concerned setting images while changing slider value, and used local variables.
}
var x: Int = 60
var h: Int = 1
var min1: Int = 1
var min2: Int = 7
#objc func animate2 ()
{
checkLbl.text = String(h) + ("1")
checkLbl2.text = String(min1) + ("1")
checkLbl3.text = String(min2) + ("1")
self.H2ImageView.image = UIImage(named: "\(h).png")!
self.M1ImageView.image = UIImage(named: "\(min1).png")!
self.M2ImageView.image = UIImage(named: "\(min2).png")!
}
func animate ()
{
var timeLeft = x
var seconds = 60
while timeLeft >= 0
{
(h, _) = x.quotientAndRemainder(dividingBy: 60)
(min1, min2) = x.quotientAndRemainder(dividingBy: 10)
if min1 >= 6
{
min1 = min1 - 6
if h == 2
{
min1 = 0
}
}
checkLbl.text = String(h)
checkLbl2.text = String(min1)
checkLbl3.text = String(min2)
// checkLbl used to track the variables
perform(#selector(animate2), with: nil, afterDelay: 1)
seconds = seconds - 1
if seconds == 0
{
timeLeft = timeLeft - 1
seconds = 60
}
}
}
#IBAction func watchPress(_ sender: UIButton)
{
animate()
}
To summarise: I expected the delay function to update h, min1 and min2 (and therefore update the checkLbl text) every second however these values go straight to 0.
Any help is appreciated, thanks!
You need to understand that performSelector, DispatchQueue.main.asyncAfter and Timer all run code asynchronously after a certain time. This means that line B won't run one second after line A in this example:
checkLbl3.text = String(min2) // A
perform(#selector(animate2), with: nil, afterDelay: 1)
seconds = seconds - 1 // B
Line B will run immediately after line A. And after one second, animate2 will be called.
Therefore, you should not use a while loop. Instead, you should use a Timer like this:
Timer(timeInterval: 1, repeats: true) { (timer) in
if timeLeft == 0 {
timer.invalidate()
}
seconds -= 1
if seconds == 0
{
timeLeft = timeLeft - 1
seconds = 60
}
// update the labels and image views
}
I also recommend you to only store the time left as a number of seconds. Remove your h, min1, min2 and seconds variables. Only calculate them from the time left when you update the UI.

Dates (Duration) in Google Sheets Script

I have a Google Sheet with three columns:
- Date and time (timestamp)
- Duration
- Description
I have an script that when I write something in 'Description', inserts in 'Date' the date and time at this moment, and the 'Duration':
function onEdit(e) {
if(e.source.getActiveSheet().getName() == "Sheet2" ) {
var col = e.source.getActiveCell().getColumn();
if(col == 3 ) {
// I'm in column three
var cellTimeStamp = e.range.offset(0,-2); // First column of the same row
var cellTimeDiff = e.range.offset(0,-1); // Second column of the same row
var cellTimePrev = e.range.offset(-1,-2); // First column of the previous row
var timeTimeStamp = new Date();
var iniTime = cellTimePrev.getValue().getTime();
var finTime = timeTimeStamp.getTime() ;
var timeDiff = String(finTime - iniTime) ;
cellTimeStamp.setValue(timeTimeStamp);
cellTimeDiff.setValue(timeDiff); // [***]
}
}
}
When this executes (as an event) in the column of 'Duration' there is NOT something in the format of 'HH:mm:ss'.
But if I remove the last line in this script and adds this formulae in the sheet:
=A3-A2 (in row 3)
=A4-A3 (in row 4)
...
then it works ok.
I'd like to know how to meet the same result but with a script.
Thanks in advance.
timeDiff is the result of finTime - iniTime which are both native date object values, which means we have milliseconds .
converting that in hh:mm:ss is simple math... : 60 seconds in a minute and 60 minutes in an hour...
A simple code could be like this :
function msToTime(s) {
var ms = s % 1000;
s = (s - ms) / 1000;
var secs = s % 60;
s = (s - secs) / 60;
var mins = s % 60;
var hrs = (s - mins) / 60;
return hrs + ':' + mins + ':' + secs; // milliSecs are not shown but you can use ms if needed
}
If you prefer formating your string more conventionally (2 digits for each value) don't forget you can use Utilities.formatString() to do so.
example below :
return Utilities.formatString("%02d",hrs) + ':' + Utilities.formatString("%02d",mins) + ':' + Utilities.formatString("%02d",secs);
EDIT
Following your comment :
Spreadsheets are smarter than you think, you can try the code below and you will see that the result is actually a time value.(check by double clicking on it)
function test() {
var sh = SpreadsheetApp.getActiveSheet();
var t1 = sh.getRange('a1').getValue().getTime();
var t2 = sh.getRange('b1').getValue().getTime();
sh.getRange('c1').setValue(msToTime(t1-t2)).setNumberFormat('hh:mm:ss');
}
function msToTime(s) {
var ms = s % 1000;
s = (s - ms) / 1000;
var secs = s % 60;
s = (s - secs) / 60;
var mins = s % 60;
var hrs = (s - mins) / 60;
return hrs + ':' + mins + ':' + secs; // milliSecs are not shown but you can use ms if needed
}
note that setNumberFormat('hh:mm:ss') is optional, it's only there to force the spreadsheet to display hour:min:sec format but automatic mode works as well.

AVAudioPlayer currentTime exceeds duration

I'm making my own audio player using AVAudioPlayer.
NOTE: "p" is my instance of the player
Here's how I'm reading the track progress in one of the labels:
currentTime.text = [NSString stringWithFormat:#"%d:%02d", (int)p.currentTime / 60, (int)p.currentTime % 60];
Here's how I set the total duration of the track in one of the labels:
int seconds = (int)p.duration % 60;
int minutes = (int)p.duration / 60;
duration.text = [NSString stringWithFormat:#"%d:%02d", minutes, seconds];
When I run the app on the device, the track's current time ALWAYS exceeds the duration (by about 5-10 seconds).
Is this a bug in AVAudioPlayer, or am I not doing it correctly?
NOTE: This behavior also occurs on the device (not just on the simulator)
After finding the seconds by using % 60, you should remove those seconds when converting the remaining for the minutes. For e.g., with the total duration of 119 seconds after finding 59 seconds you should remove that from 119 and then do minute conversion for 60 seconds (119-59). That might solve your problem.
Minutes should be float: 152 seconds / 60.0f = 2.5333 not 2.
That being said, if you want to show the remaining minutes without the seconds you already obtain: int minutes = (p.duration-seconds) / 60
Also, for a better method to format time the way you want to, have a look at the second answer in this question (not the accepted solution).
Here is the function:
func setTimeString(duration: Double)->String {
var audioDurationSeconds = duration
var expression = ""
var minutesString = "00"
var minutesFloat = 0.0
if (audioDurationSeconds)/60 >= 1 {
minutesFloat = (audioDurationSeconds) / 60
audioDurationSeconds = TimeInterval(Int(audioDurationSeconds)%60)
if minutesFloat < 10.0 {
minutesString = String.init(format: "0%.f", floor(minutesFloat))
} else {
minutesString = String.init(format: "%.f", floor(minutesFloat))
}
}
if audioDurationSeconds < 10.0 {
expression = String.init(format: "%#:0%i", minutesString, Int(audioDurationSeconds))
} else {
expression = String.init(format: "%#:%i", minutesString, (Int(audioDurationSeconds)))
}
return expression
}
extension UILabel{
func getTimeString(from duration:Double) -> String{
let hours = Int(duration / 3600)
let minutes = Int(duration / 60) % 60
let seconds = Int(duration.truncatingRemainder(dividingBy: 60))
if hours > 0 {
return String(format: "%i:%02i:%02i", arguments: [hours,minutes,seconds])
}else {
return String(format: "%02i:%02i", arguments: [minutes,seconds])
}
}