使用GregorianCalendar循环任务一年

时间:2017-07-30 22:07:44

标签: java time gregorian-calendar

我必须编写一个程序,显示Timeplan关于何时发送电子邮件。

用户正在输入开始日期,我必须显示一年的时间计划。 如何循环任务? 在此示例中,邮件应每8天发送一次。

    if(recipient==0) {
        System.out.println("send mail on this day:" +calendar.getTime());   
        calendar.add((GregorianCalendar.DAY_OF_YEAR),8);
        return true;    
    }

我想将System.out.printlncalendar.add任务循环到一年之后。

编辑:我还有另一个案例,它应该每16天发送一次电子邮件,但是当星期六或星期日,它应该在下一个星期一发送邮件。

我是这样做的,但现在我得到的日期超出了我的需要。

if(empfaenger==1)
    {
         for (Date d=startDate; d.before(endDate); d.setTime(d.getTime() + (1000 * 60 * 60 * 24 * 8)))
         {
             if(calendar.get(calendar.DAY_OF_WEEK)==1)
            {
            calendar.add((GregorianCalendar.DAY_OF_YEAR),1);
            System.out.println("mail will be sent on this day:"+calendar.getTime());
            calendar.add((GregorianCalendar.DAY_OF_YEAR), 16);
            }
        else if(calendar.get(calendar.DAY_OF_WEEK)==7)
            {
            calendar.add((GregorianCalendar.DAY_OF_YEAR), 2);
            System.out.println("mail will be sent on this day:"+calendar.getTime());
            calendar.add((GregorianCalendar.DAY_OF_YEAR),16);
            } 
        else
        {
            System.out.println("mail will be sent on this day:"+calendar.getTime());
            calendar.add((GregorianCalendar.DAY_OF_YEAR),16);
        }
        //System.out.println(calendar.getTime;)
         }
    }

2 个答案:

答案 0 :(得分:1)

以下是使用java 8中的 java.time api的示例,它更易于理解和使用日历或日期类:

static void sendEveryEightDays(){
    LocalDateTime timeToSendEmail= LocalDateTime.now();
    LocalDateTime afterAYear = timeToSendEmail.plusYears(1);

    while(timeToSendEmail.isBefore(afterAYear)){
        System.out.println("SendTheEmail "+timeToSendEmail.toString());
        timeToSendEmail=timeToSendEmail.plusDays(8);
    }
}

如果您想考虑用户的时区,可以使用 ZonedDateTime 关闭 LocalDateTime

static void sendEveryEightDays(ZoneId userTimeZone){
    ZonedDateTime timeToSendEmail= ZonedDateTime.now(userTimeZone);
    ZonedDateTime afterAYear = timeToSendEmail.plusYears(1);

    while(timeToSendEmail.isBefore(afterAYear)){
        System.out.println("SendTheEmail "+timeToSendEmail.toString());
        timeToSendEmail=timeToSendEmail.plusDays(8);
    }
}

答案 1 :(得分:0)

我想知道老师为什么还在教授旧API(DateCalendarSimpleDateFormat),因为他们有lots of problemsdesign issues,他们& #39;被新API取代。 (Java 8于2014年发布,顺便说一下。)

无论如何,如果你有一个GregorianCalendar,你可以将它转换为新的java.time类,然后用它们完成。

首先,您可以使用日历创建Instant

Instant instant = Instant.ofEpochMilli(calendar.getTimeInMillis());

唯一的问题是,如果您创建Calendar并设置日,月和年,它将具有当前时间(小时/分钟/秒),因此上面的Instant将以UTC格式表示当前时间。如果可以,您可以将此瞬间转换为您的时区:

ZoneId zone = ZoneId.of("America/Sao_Paulo");
ZonedDateTime start = instant.atZone(zone);

我使用America/Sao_Paulo,但您可以更改为对您的系统有意义的时区。 API使用IANA timezones names(始终采用Region/City格式,如America/Sao_PauloEurope/Berlin)。 避免使用3个字母的缩写(例如CSTPST),因为它们是ambiguous and not standard

您可以致电ZoneId.getAvailableZoneIds()获取可用时区列表(并选择最适合您系统的时区)。如果需要,您也可以使用系统的默认设置(ZoneId.systemDefault()),但请注意,即使在运行时也可以在不事先通知的情况下进行更改,因此最好指定您的时区#&# 39;重新使用。如果要使用UTC中的日期,可以使用内置常量ZoneOffset.UTC

上面的代码会创建一个ZonedDateTime,其日历的日期和时间会调整到指定的时区。只是提醒一下,如果你这样做:

Calendar calendar = new GregorianCalendar();
calendar.set(2017, 7, 12);

日期相当于 8月12日 th 2017 (因为Calendar API中的月份从零开始,因此第7个月是8月),并且时间将是创建日历的当前时间。

如果您想指定小时,您可以选择一些小时来调整它:

// change the hour/minute/second to 10:20:45
start = start.with(LocalTime.of(10, 20, 45));

// change just the hour to 10
start = start.withHour(10);

// set to start of the day
start = start.toLocalDate().atStartOfDay(zone);

通过此,您可以相应地更改时间(以及日期)字段。查看javadocOracle's tutorial,查看所有可用选项。方法atStartOfDay更好,因为它会处理夏令时变化(取决于夏令时的变化,这一天可以从凌晨1点而不是午夜开始,这个方法会处理所有细节。)

如果您不想依赖Calendar,还可以直接创建日期:

// creating August 12th 2017, at 10:00
start = ZonedDateTime.of(2017, 8, 12, 10, 0, 0, 0, zone);

请注意,8月是第8个月(旧API的最佳和最明显的改进之一)。

现在你有了开始日期,你可以循环一整年,并根据你的规则检查日期。我是使用每16天发送一次电子邮件的示例,如果是周末则调整到下一个星期一:

ZonedDateTime d = start;
// ends in 1 year - this method already takes care of leap years
ZonedDateTime end = start.plusYears(1);
while (end.isAfter(d)) {
    d = d.plusDays(16);
    if (d.getDayOfWeek() == DayOfWeek.SUNDAY || d.getDayOfWeek() == DayOfWeek.SATURDAY) {
        // weekend, adjust to next monday
        d = d.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
    }
    // send email
}

如果您使用的是Java< = 7,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。

与Java 8的唯一区别是包名称(在Java 8中为java.time而在ThreeTen Backport(或Android的ThreeTenABP中)为org.threeten.bp),但类和方法< strong>名称是相同的。

正如@BasilBourque在评论中提醒我的那样,您还可以使用GregorianCalendar方法将ZonedDateTime转换为toZonedDateTime()(这将使用日历的时区 - 通常系统的默认设置,如果你没有设置它)。您也可以使用Instant方法将其转换为toInstant()。唯一的限制是这些方法仅在Java 8中可用(因此,如果您使用的是ThreeTen Backport,只需使用上面描述的方式)。