在同一天内正确验证时间间隔

时间:2016-12-03 12:22:17

标签: java date jodatime localdate

我有一个方法如下:

public void storeAppointment(int year,
    int monthOfYear,
    int dayOfMonth,
    int hourOfDayFrom,
    int minuteFrom,
    int hourOfDayUntil, int minuteUntil) {

    Calendar appointmentCalendar = Calendar.getInstance();
    appointmentCalendar.set(year, monthOfYear, dayOfMonth);
    TimeZone tz = appointmentCalendar.getTimeZone();
    DateTimeZone jodaTz = DateTimeZone.forID(tz.getID());
    DateTime appointmentDateTime = new DateTime(appointmentCalendar.getTimeInMillis(), jodaTz);
    LocalDate localDate = appointmentDateTime.toLocalDate();

    // At this point I have the appointment date.  

    // Should e.g. throw an exception for invalid time interval
    validate(hourOfDayFrom, minuteFrom, hourOfDayUntil, minuteUntil);

    // set proper times for calendar
    appointmentCalendar.set(Calendar.HOUR, hourOfDay);
    appointmentCalendar.set(Calendar.MINUTE, minute);
    // store date and times  
    // Should I update the localDate instead of the appointmentCalendar?
}    

问题:

  1. 我应该如何验证小时/分钟?是否应包括实际日期或不相关?

  2. 我应该更新localDate而不是appointmentCalendar吗?

1 个答案:

答案 0 :(得分:2)

你在这里工作太辛苦了。

避免遗留日期时间类

避免使用麻烦的旧日期时间类,例如Date& Calendar。现在是遗留的,取而代之的是java.time类。

不要混合日期时间库

不要混用不同的日期时间库。如果使用Joda-Time,则无需java.util.Date,也不需要java.util.Calendar。如果使用java.time类,则不需要Joda-Time,也不需要java.util.Date / .Calendar

现在位于Joda-Timemaintenance mode项目建议迁移到java.time。

业务规则

  

是否应包括实际日期或不相关?

我们无法告诉您是否考虑日期。这取决于您的业务规则。

例如,如果您的公司总是从中午到13:00休息,那么在该小时标记有时间的任何商业记录都必须无效。如果你每天都在同一个午休时间,这里的日期无关紧要。

但是,如果您的方案类似于记录工作人员的工作时间,那么在同一天不会有两个时间段重叠。在这种情况下,您必须考虑日期。

ZonedDateTime

  

我应该更新localDate而不是appointmentCalendar吗?

a)如上所述,你不应该混合这些类。

b)在Joda-Time和java.time中,LocalDate类表示没有时间的仅日期值。和它的兄弟Local…类一样,它故意没有时区概念。所以根本不适合你的目的。

您需要使用ZonedDateTime来表示在预期时区内有意义的日期和时间。

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

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2016 , 1 , 23 );
LocalTime lt = LocalTime.of( 12 , 30 );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );

获取当前时刻:

Instant instant = Instant.now();  // UTC.
ZonedDateTime zdt = instant.atZone( z );

......或者,作为捷径......

ZonedDateTime zdt = ZonedDateTime.now( z );

此外,java.time类为immutable objects。所以你不要改变(“改变”)他们的价值观。而是根据原始值实例化一个新对象。

间隔

您可以在Interval项目中找到ThreeTen-Extras课程,以便在此处提供帮助。

Interval a = Interval.of( zdtStart.toInstant() , zdtStop.toInstant() );

您可以将时间间隔与containsoverlapsenclosesisBeforeisAfter等方法进行比较。

Boolean overlaps = a.overlaps( b );

传递对象

不是传递零碎数据的基元,而是传递对象。

因此,不要传递月份,日期和小时等整数等基元,而是传递InstantOffsetDateTimeZonedDateTime等java.time对象。如果您只有日期或只有时间,请通过LocalDateLocalTime

默认时区

要获取JVM的当前默认时区,请致电ZoneId.systemDefault

但是如果重要的话,你应该问用户他们想要的/预期的时区。该默认值可随时由该JVM中运行的任何应用程序的任何线程中的任何代码更改。