How to perform a task at a precise time in time?

Asked

Viewed 1,202 times

24

A style question Code Golf

I made a console program to show the time, only it’s different times than the ones we know - and involves a very simple account.

It checks the system time, and upon discovering that a minute has passed, it prints the calculated current time on the screen.

Examples of his departure:

35.5787037037037
35.69444444444444
36.388888888888886

However, I would like it to work a little better:

I wish he had the precision of a second, or a . beat

For this, I should be able to create a task connected to the system clock, so that he would warn me precisely at the moment I determined.

I know it’s possible to make one loop infinite, and check the system time thousands of times - but I don’t really like the idea. The ideal would be to have a Listener to inform me that the time has come to perform my task.

Is that possible? How to do it? (Is there any magic, voodoo that allows it?)

  • I would like simple examples in different languages
  • Console program
  • No need to implement . beat’s account
  • The idea is to free the program to do other things and have the task started at a precise time in time
  • A single language per response!


The account, for those who are curious, is this:
(UTC+1segundos + (UTC+1minutos * 60) + (UTC+1horas * 3600)) / 86.4

  • Do you want, for example, a certain function to run only at a certain time you set without there being a loop checking the time? I got it right?

  • @Andersoncarloswoss if not possible, the best way to do it with the loop (which can be accurate). if any function can abstract the loop, better - if it can do without the loop even better.

  • 2

    It’s possible, in Python, at least. I just found the first part of the question confusing, where you talk about account, calculated time and time different from the one we know.

  • @Andersoncarloswoss yes, so I said it’s not necessary at the end - my initial goal was to make a clock, if that’s not clear, but I think the interesting exercise is to check the system time the number of times needed to do it accurately.

  • @Andersoncarloswoss includes the beat account at the end of the question to kill curiosity.

  • I remember the .beat. It was a play of marketing by a Swiss watchmaker, Swatch, in the ancient times of 1998...

  • @Wtrmute went to meet last week! I saw that they wanted to put a satellite in space just to serve the time - insane!

Show 2 more comments

5 answers

20

Python

In Python there is the package sched which can be used to schedule tasks at certain points of time. See the example:

import sched, time, threading, sys

trigger = time.mktime((2017, 6, 14, 21, 15, 36, 0, 0, 0))

def task(trigger):
    sys.stdout.write("Tarefa executada com um erro de " + str(time.time() - trigger) + ' segundos\n')

s = sched.scheduler(time.time, time.sleep)

s.enterabs(trigger, 1, task, argument=(trigger,))

t = threading.Thread(target=s.run)
t.start()

while t.is_alive(): pass # Simula o programa executando normalmente

For the above example, the function task will be executed exactly in 2017-06-14 at 21:15:36, displaying on the screen the message (for example):

Tarefa executada com um erro de 0.0057599544525146484 segundos

See working on Repl.it

Reference of functions used:

sched.scheduler sched.scheduler.enterabs sched.scheduler.run time.mktime time.time time.sleep threading.Thread threading.Thread.start threading.Thread.is_alive

9

In Java:

import java.time.ZonedDateTime;
import java.time.ZoneOffset;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Swatch {
    public static void main(String[] args) {
        // Recebe a entrada em .beats e converte para milisegundos desde a meia-noite.
        int milisegundosAgendamento = Integer.parseInt(args[0]) * 86400;

        // Hora atual no fuso horário UTC+1.
        ZonedDateTime utc1 = ZonedDateTime.now(ZoneOffset.ofHours(1));

        // Calcula a quantidade de milisegundos desde a meia-noite que se passaram neste momento.
        int milisegundosAgora = utc1.getHour() * 3600000 + utc1.getMinute() * 60000 + utc1.getSecond() * 1000 + utc1.getNano() / 1000000;

        // Calcula quantos milisegundos faltam para chegar a hora certa. O if serve para o caso de a hora certa ser amanhã, e não hoje.
        int milisegundosQueFaltam = milisegundosAgendamento - milisegundosAgora;
        if (milisegundosQueFaltam < 0) milisegundosQueFaltam += 86400000;

        // Cria um objeto responsável por executar tarefas em momentos pré-agendados.
        ScheduledThreadPoolExecutor agendador = new ScheduledThreadPoolExecutor(1);

        // Agenda a tarefa de mostrar a hora e fechar o agendamento:
        agendador.schedule(() -> {
            System.out.println("Chegou a hora");
            agendador.shutdown();
        }, milisegundosQueFaltam, TimeUnit.MILLISECONDS);
    }
}

The code above shows the message Chegou a hora when the time is right. There is no error check on the input, it assumes that it will receive per command line an integer between 0 and 999. After the right time comes the program ends.

Meanwhile, considering the original rules of code-golf which aim to minimize the size of the source code, I come to this other version down here with 404 373 366 bytes. In it, the message that the time has come is just the program returning the status 5 to the operating system when the time comes. Its accuracy is one-tenth of a second instead of one-millisecond as the code above. Again, there is no verification as to whether the entry is valid:

import java.time.*;import java.util.concurrent.*;class S{public static void main(String[]x){ZonedDateTime z=ZonedDateTime.now(ZoneOffset.ofHours(1));int g=Integer.parseInt(x[0])*864-z.getHour()*36000-z.getMinute()*600-z.getSecond()*10-z.getNano()/100000000;new ScheduledThreadPoolExecutor(1).schedule(()->System.exit(5),(g<0?g+864000:g)*100,TimeUnit.MILLISECONDS);}}
  • milisegundosAgora does not exist in the top code (era b?) - Other than that, I liked it! (mainly from the bottom code that caused the eclipse syntax checker to break) + 1

  • @Tidy blogger. This is the result that I started minifying the original code, I saw that I was making a mistake, I pressed Ctrl+Z several times (but I missed one), I copied the code here and then I continued with the minification.

4

In C#

the same can be done using a timer.

The trickiest part is handling the case of when the timer should start. Since there is no simple API to do this Voce has to resort to other mechanisms like Thread.Sleep.

System.Timers.Timer StartTimer(TimeSpan interval, Action onTick, DateTime? startAt = null){
    startAt = startAt ?? DateTime.UtcNow;
    var timer =  new  System.Timers.Timer();
    timer.Interval = interval.TotalMilliseconds;
    timer.Elapsed += (ctx, arg) => onTick();
    timer.AutoReset = true;

    //evita o bloqueamento da thread chamadora.
    ThreadPool.QueueUserWorkItem(ctx =>{  
        //espera até que o momento atual seja aproximadamente `startAt`
        Thread.Sleep(Math.Max(0, (DateTime.UtcNow - startAt).TotalMilliseconds));
        //chama o callback e comeca o timer que vai chamar o callback em intervalos
        onTick();
        timer.Start();
    });
    return timer;
}

StartTimer(TimeSpan.FromMinutes(1), () => Console.WriteLine("Tick"));
  • In your two answers you enter only one value in minutes or seconds to perform the task, but not an exact point on the timeline, correct? If yes, I believe that the way it is they do not completely respond to what was requested, being liable, thus, an adaptation of your, because the task must be executed exactly at that moment independent of when I execute the code.

  • @Andersoncarloswoss Nao. This code just calls the callback on startAt and then x in x interval. Voce javascript has to calculate the delay by Voce itself.

  • It is precisely this calculation that is the adaptation that I talked about. In this answer, won’t the task be executed 1 minute after I run the programs? How would you determine the exact time you want?

  • @Andersoncarloswoss Nao. This only happens in the Javascript code. In this c# if you pass a 2020 Startat it only starts in 2020. No Javascript Voce has to calulcar the Difference between 2020 and the current date in milliseconds.

1

Javascript

Can be done using setTimeout and some recursion.

function setIntervalDelayed(delay, interval, cb){
    setTimeout(function(){
        cb();
        setIntervalDelayed(interval, interval, cb);
    }, delay);
}

setIntervalDelayed(1000, 5000, function(){console.log('Tick');});

1

In C:

#include <stdio.h>
#include <time.h>
#include <unistd.h>


void callback_func( time_t t )
{
    printf("CallBack: %ld\n", t );
}


void timer( int intervalo, void (*func)(time_t) )
{
    time_t atual;
    time_t ultima;

    while(1)
    {
        atual = time(NULL);

        if( atual >= ultima + intervalo )
        {
            func( atual );
            ultima = atual;
        }

        usleep( (intervalo / 10) * 1000000L );
    }

}

int main( int argc, char * argv[] )
{
    timer( 1, callback_func );
    return 0;
}

Exit:

CallBack: 1498509557
CallBack: 1498509558
CallBack: 1498509559
CallBack: 1498509560
CallBack: 1498509561
CallBack: 1498509562
CallBack: 1498509563
CallBack: 1498509564
CallBack: 1498509565
CallBack: 1498509566
CallBack: 1498509567
CallBack: 1498509568
CallBack: 1498509569
CallBack: 1498509570

Browser other questions tagged

You are not signed in. Login or sign up in order to post.