【问题标题】:Create one file per week每周创建一个文件
【发布时间】:2019-04-30 04:12:03
【问题描述】:

我有一个每天都要手动运行的 java 程序。 现在我想每周创建一个 excel 文件来写入一周的所有任务

我知道如何每天像这样创建一个文件:

if(!IoUtils.fileExist("indicators-" + IoUtils.getCurrentDate() + ".xls")){
    IoUtils.createIndicFile("indicators-" + IoUtils.getCurrentDate() + ".xls");
}
else IoUtils.INDIC_FILEPATH = "indicators-" + IoUtils.getCurrentDate() + ".xls";

这是以特定格式为我提供当前日期的函数:

// IoUtils class
public static String getCurrentDate(){
    LocalDateTime ldt = LocalDateTime.now();
    return DateTimeFormatter.ofPattern("dd-MM-yyyy", Locale.ENGLISH).format(ldt);
}

那么我怎样才能将其更改为每周只创建一个文件?

我还想在文件名中包含月份和周数,如下所示:

// first monday of january 2018
name = "indicators-week1-01-2018"

// second monday of january 2018
name = "indicators-week2-01-2018"

谢谢

【问题讨论】:

  • 这样写...在写文件之前检查系统日是否是星期一
  • 你的问题是什么?检查当前日期是否为星期一?还是安排创作?
  • @Stultuske 请检查更新
  • @vincrichaud 我已经更新了问题
  • @AmadouBeye 英语不好没有问题;-)。问题是您显示了创建文件的代码。您显示获取日期的代码。但是,让它每天都发生的代码在哪里?

标签: java


【解决方案1】:

Java 提供 java.util.concurrent.ScheduledThreadPoolExecutor,可以额外安排命令在给定延迟后运行或定期执行。

Scheduler.scheduleWithFixedDelay(task, StartDelay, repeatInterval, TimeUnit.MINUTES);

【讨论】:

  • 请注意,如果这将在多个实例上运行,则会为每个实例分别生成一个报告。
  • @SofoGial 在由预定执行器服务运行的Runnable 中,程序员的工作是检查正确的日期并检查该周的文件是否已写入。所以执行者重复是一个特性,而不是一个问题。
  • @BasilBourque 绝对!我刚刚指出了这一点,因为我看到人们在过去 5 年中经常忘记这一点:)
【解决方案2】:

执行者

老式方法使用Timer 类。

New-school 方式使用Executors framework 处理后台线程上调度任务的细节。

设置一个执行程序以每隔几个小时运行一次Runnable。该任务检查当前时刻。如果当前日期的星期几是星期一,并且您的文件尚未写入,请写入。如果没有,则让 Runnable 过期。 scheduled executor service 将在几个小时后再次运行,并一次又一次地重复。

第一步是获取当前日期。

时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将 desired/expected time zone 明确指定为参数。

continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 2-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z );

从中获取当前星期几。

DayOfWeek dow = today.getDayOfWeek() ;

如果今天是星期一,则查看文件是否已写入。如果没有,就写吧。

if( dow.equals( DayOfWeek.MONDAY ) ) {
    if( file not written ) { write file }
}

将所有内容放在一个命名方法中。

private void writeFileOnMonday ( ) {
    ZoneId z = ZoneId.of( "America/Montreal" );
    LocalDate today = LocalDate.now( z );
    DayOfWeek dow = today.getDayOfWeek();
    if ( dow.equals( DayOfWeek.MONDAY ) ) {
        if ( file not written ){ write file }
    }
}

利用scheduled executor service 中的工作负载。指定运行之间要等待的小时数。如果我们指定每 3 小时运行一次任务,那么根据逻辑,我们的每周文件将在每个星期一的午夜和凌晨 3 点之间的某个时间写入。

计划执行器服务的一大问题:如果在任何运行中,您的任务抛出了ThrowableExceptionError)并到达执行器,重复的任务执行就会静默停止。因此,请始终将您的任务包装在 try-catch 中。见this Question

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();  // Convenience method to produce an executor service.

ScheduledFuture scheduledFuture =          // A handle to check the status of your task. May or may not be useful to you.
        scheduledExecutorService
                .scheduleWithFixedDelay( new Runnable() {  // Implement the `Runnable` interface as your task. 
                                             @Override
                                             public void run ( ) {
                                                 try {
                                                     writeFileOnMonday();
                                                 } catch (Exception e ) {
                                                     … handle unexected exception
                                                 }
                                             }
                                         } ,
                        0 ,                 // Initial delay
                        3 ,                 // Delay between runs.
                        TimeUnit.HOURS );   // Unit of time meant for the pair of delay numbers above.

搜索 Stack Overflow 以获取更多信息,因为所有这些内容已经被多次介绍过。


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案3】:

    创建一个石英 cron 作业调度程序0 0 12 ? * MON。 这将安排每周一中午 12 点的作业。

    【讨论】:

      【解决方案4】:

      由于您使用的是LocalDateTime,您可以使用getDayOfWeek 方法进行检查。

      例如

      if(LocalDateTime.now().getDayOfWeek() == DayOfWeek.MONDAY){
        // File Creation Logic ...
      }    
      

      【讨论】:

      • 虽然此代码有效,但ZonedDateTime 类比LocalDateTime 更合适。
      • 同意。只是处理问题的开始。干杯。
      【解决方案5】:

      使用日历 API,calendar.get(Calendar.DAY_OF_WEEK) 将返回星期一的 int 2。

      import java.util.Calendar;
      
      if(calendar.get(Calendar.DAY_OF_WEEK) == 2)
        if(!IoUtils.fileExist("indicators-" + IoUtils.getCurrentDate() + ".xls")){
            IoUtils.createIndicFile("indicators-" + IoUtils.getCurrentDate() + ".xls");
        }
        else IoUtils.INDIC_FILEPATH = "indicators-" + IoUtils.getCurrentDate() + ".xls";
      

      【讨论】:

      【解决方案6】:
      Calendar cal = Calendar.getInstance();
      cal.setFirstDayOfWeek(Calendar.MONDAY);
      int week = cal.get(Calendar.WEEK_OF_YEAR);
      
      String expectedFileName = "indicators-week"+week+"-whateveryouwant-"+cal.get(Calendar.YEAR);
      

      然后您可以检查文件是否存在,写入同一个文件,如果文件不存在,您将创建一个具有预期文件名的新文件并写入该新文件。但根据要求,年假应该妥善处理

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-18
      • 1970-01-01
      • 2020-06-18
      • 2019-12-04
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多