【问题标题】:How Would I Execute an Event at a Specific Time如何在特定时间执行事件
【发布时间】:2021-09-18 14:21:00
【问题描述】:

目前我正在尝试创建一个计时器,在每周的特定时间(星期四下午 1:00)通知我。我现在面临的问题是如何在不执行任何操作的情况下触发计时器启动。每次机器人启动时,我都需要计时器自行启动。任何帮助表示赞赏。

这是我的代码:

public class Reminder extends ListenerAdapter {
    @Override
    public void onGuildMessageReceived(GuildMessageReceivedEvent e) {
        if (e.getGuild().getId().equalsIgnoreCase("77804326694381163")) {
            TextChannel defaultChannel = e.getGuild().getDefaultChannel();
            if (defaultChannel != null) {
                Calendar time = Calendar.getInstance();
                ZoneId zoneId = ZoneId.of("America/Los_Angeles");
                time.setTimeZone(TimeZone.getTimeZone(zoneId));
                Date timeGet = time.getTime();

                DateFormat df = new SimpleDateFormat("EE HH:mm:ss");
                String string = df.format(timeGet);

                if (string.equalsIgnoreCase("Thu 13:00:00")) {
                    Timer timer = new Timer();
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            defaultChannel.getChannel().sendTyping().queue();
                            defaultChannel.getChannel().sendMessage("Works").queue();
                        }
                    }, time.getTime(), TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS));
                }

            } else if (defaultChannel == null) {
                e.getChannel().sendTyping().queue();
                e.getChannel().sendMessage("Failed to get default channel.").queue();
            }
        }
    }
}

【问题讨论】:

  • 您需要考虑如何存储不同运行之间的时间。也许您可以将 DateTime 字符串存储在数据库中,甚至将其写入文件,然后当机器人重新启动时,您只需从数据库或文件中加载数据,然后您的应用程序需要做的就是每 10 秒循环一次并检查时间是否已到达列表中。
  • 嗯,不错的主意。但也许有更简单的方法吗?我认为这会更容易一些:p。
  • 我不知道你说的更简单是什么意思?您需要在机器人重新启动之间的某处存储信息,否则,每次机器人开始检查以前的命令时,您都必须重新扫描整个频道内容。虽然这是可能的,但它既不高效也不有效,并且当频道收到太多消息时会中断,并且不和谐会对您的机器人施加速率限制以尝试扫描数百万条旧消息。保存到文件相对容易,有很多可用的教程,但您需要考虑创建一个循环,或使用结束/触发器启动计时器。

标签: java discord-jda


【解决方案1】:

我建议你使用ScheduledExecutorService

ScheduledExecutorService scheduledActivity = Executors.newScheduledThreadPool(1);
scheduledActivity.scheduleAtFixedRate(() -> {
      //whatever you want to do at 11 PM on Thursday
},
initialDelay, //you have to calculate an initial delay
TimeUnit.DAYS.toSeconds(7), //makes it run every 7 days
TimeUnit.SECONDS);

initalDelay 始终是当前时间与您希望服务运行的时间之间的差值(在您的情况下为星期四晚上 11 点)。

关于如何实现这一点有几种解决方案,但我个人更喜欢以下方法:

//you might want to change the timezone to your liking
LocalDateTime now = LocalDateTime.now(ZoneId.of("Europe/Berlin"));        
LocalDateTime then = LocalDateTime.now(ZoneId.of("Europe/Berlin"));

//then equals the next or current Thursday on 13:00 (or 1 PM)
then = then.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY)).withHour(13).withMinute(0).withSecond(0);
    
Duration duration = Duration.between(now, then);
long initialDelay = duration.getSeconds();

//initialDelay can become negative if the current day is Thursday but it's already too late
if (initialDelay < 0) {
    //add one week to shift the delay to the next correct time
    initialDelay = Duration.between(now, localDate.with(TemporalAdjusters.next(DayOfWeek.THURSDAY)).withHour(13).withMinute(0).).getSeconds();
}

(这绝对可以优化!)

【讨论】:

    猜你喜欢
    • 2012-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 2023-02-05
    相关资源
    最近更新 更多