【问题标题】:How can I manage working hours in Java?如何在 Java 中管理工作时间?
【发布时间】:2012-08-13 12:08:45
【问题描述】:

我想问一下是否有人知道任何 API 或类似的东西可以让我管理一天中的具体部分(例如工作时间)

我的问题是我必须在下一个上下文中管理时间:

假设我在一家公司工作,工作时间是“8am-2pm”和“3pm-6pm”,夏令时从“8am 到 2pm”。我想知道具体日期的具体时刻是劳动时刻还是不是。

例如,如果我有提到的日历,并且我询问 API “2012 年 8 月 13 日晚上 9 点”是否是工作时间,它必须检查它并返回正确答案(在这种情况下为错误),如果我问如果“2012 年 8 月 13 日上午 9 点”是工作时间,则必须返回“true”

其他重要的事情相关。我必须使用提到的日历计算两个日期之间的间隔。例如,如果我将开始时间设置为“今天下午 5 点”,结束时间设置为“明天上午 10 点”,则它必须返回 3 小时(或以秒或毫秒为单位的等效时间),因为它是在开始日期和此日历中的结束日期。

它还必须适用于假期(尤其是每个国家/地区)。我找到了一个 API 调用“JollyTime”,虽然它适用于假期,但它不支持工作时间......

有什么想法吗?

【问题讨论】:

  • 我会查看 Joda Time (joda-time.sourceforge.net),尤其是它的周期和持续时间功能。至于诸如夏令时和假期之类的事情,您可能必须提供自己的 API forint 才能有意义且准确
  • @MadProgrammer 仅供参考,“its”表示“属于它”时没有撇号
  • 我想对于特殊要求您将不得不自己执行...
  • 好的,谢谢大家...如果我别无选择,我将自己创建实现!
  • @boheman @ 3am,在 iPad 上,人们往往不会注意到这些事情;P

标签: java date


【解决方案1】:

更新: Joda-Time 库现在处于维护模式,其主要作者 Stephen Colebourne 继续领导定义 java.time 类的 JSR 310内置于 Java 8 及更高版本中。


一个对日期时间具有复杂支持的良好数据库可能会有所帮助。一个这样的数据库是Postgres,具有良好的日期时间data typescommands ("functions")

Joda-Time 框架也可能有所帮助。 Interval 类及其父类定义了一对开始和停止日期时间之间的时间跨度。它们提供了比较方法,例如:包含、重叠、isBefore、is After。

这里有一些示例代码可以帮助您开始使用 Joda-Time 2.3 和 Java 7。

// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );

List<Interval> workIntervalsFor13Aug2012 = new ArrayList<Interval>( 2 );
DateTime start, stop;
Interval interval;

start = new DateTime( 2012, 8, 13, 8, 0, 0, timeZone );
stop = new DateTime( 2012, 8, 13, 14, 0, 0, timeZone );
interval = new org.joda.time.Interval( start, stop );
workIntervalsFor13Aug2012.add( interval );

start = new DateTime( 2012, 8, 13, 15, 0, 0, timeZone );
stop = new DateTime( 2012, 8, 13, 18, 0, 0, timeZone );
interval = new org.joda.time.Interval( start, stop );
workIntervalsFor13Aug2012.add( interval );

// Check a date-time against those work intervals.
DateTime test09 = new DateTime( 2012, 8, 13, 9, 0, 0, timeZone );
DateTime test21 = new DateTime( 2012, 8, 13, 21, 0, 0, timeZone );

// You should write a "dateTimeIsInWorkingInterval" method that performs this loop.
Boolean hit = false;
for ( Interval nthInterval : workIntervalsFor13Aug2012 ) {
    if( nthInterval.contains( test09 )) {
        hit = true;
        break;
    }
}
if( hit ) {
    System.out.println( "This date-time: " + test09 + " occurs during a work interval.");
} else {
    System.out.println( "This date-time: " + test09 + " occurs outside a work interval.");
}

hit = false;
for ( Interval nthInterval : workIntervalsFor13Aug2012 ) {
    if( nthInterval.contains( test21 )) {
        hit = true;
        break;
    }
}
if( hit ) {
    System.out.println( "This date-time: " + test21 + " occurs during a work interval.");
} else {
    System.out.println( "This date-time: " + test21 + " occurs outside a work interval.");
}

运行时……

This date-time: 2012-08-13T09:00:00.000+02:00 occurs during a work interval.
This date-time: 2012-08-13T21:00:00.000+02:00 occurs outside a work interval.

【讨论】:

    【解决方案2】:

    看看 JODA 时间库。我知道它有间隔,可能正是您所需要的。

    【讨论】:

    • joda 时间的间隔不是他需要的。他只在工作时间寻找间隔。 IE。工作日还剩 1 小时到下一个工作日还剩 1 小时将是 2 小时的间隔,而不是 16 小时(或按时间顺序排列的任何时间)。但我确实同意 Joda-Time 是进行任何日期/时间计算的最佳库。 Java 内置的日期/时间处理非常糟糕。
    • @Matt 我不同意。 Interval 及其父 ReadableInterval 似乎只是门票。间隔表示一对停止和开始时刻之间的跨度。区间提供比较方法:包含、重叠、isBefore、is After。您认为什么是不匹配?
    【解决方案3】:

    我已经实施了一个简单的解决方案来计算两个日期之间的工作时间。从这个角度出发可能会帮助你完成你的任务。

    这是以分钟或毫秒计算工作时间的类。

    public class WorkingTime {
    
    private static final long ONE_SECOND_AS_MILISECONDS = TimeUnit.SECONDS.convert(1, TimeUnit.SECONDS);
    
    private Integer startHour;
    private Integer endHour;
    private Integer startMinute;
    private Integer endMinute;
    
    public WorkingTime(int startHour, int endHour) {
        this(startHour, 0, endHour, 0);
    }
    
    public WorkingTime(Integer startHour, Integer startMinute, 
            Integer endHour, Integer endMinute) {
        super();
        this.startHour = startHour;
        this.endHour = endHour;
        this.startMinute = startMinute;
        this.endMinute = endMinute;
    }
    
    ... getters and setters
    
    public long calculateWorkingAsMilis(Date date1, Date date2) {
        return ONE_SECOND_AS_MILISECONDS * calculateWorkingSeconds(date1, date2);
    }
    
    public long calculateWorkingSeconds(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        setWorkingCalendar(cal1);
    
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        setWorkingCalendar(cal2);
    
        long day1 = TimeUnit.MILLISECONDS.toDays(cal1.getTimeInMillis());
        long day2 = TimeUnit.MILLISECONDS.toDays(cal2.getTimeInMillis());
        long daydiff = day2 - day1;
        long weekendDiff = (daydiff / 7); // get number of weekends
        if (isLeakWeekend(cal1, cal2))
            weekendDiff++;
    
        long dailyWorkingTimeAsMinutes = getDailyWorkingTimeAsMinutes();
        long secondsToBeDecrementedAsNonWorkingHours = TimeUnit.SECONDS.convert((24 * 60 - dailyWorkingTimeAsMinutes), TimeUnit.MINUTES); // seconds that are not in interval of working hours
        long secondsToBeDecrementedAsWorkingHoursForWeekends = TimeUnit.SECONDS.convert(dailyWorkingTimeAsMinutes * 2, TimeUnit.MINUTES); // weekend is not working days, they need to be decremented
    
        long dayDiffAsSeconds = daydiff * secondsToBeDecrementedAsNonWorkingHours;
        dayDiffAsSeconds += (weekendDiff * secondsToBeDecrementedAsWorkingHoursForWeekends); 
    
        long workDiffSeconds = TimeUnit.SECONDS.convert(
                cal2.getTimeInMillis() - cal1.getTimeInMillis(),
                TimeUnit.MILLISECONDS) - dayDiffAsSeconds; 
        return workDiffSeconds;
    }
    
    private boolean isLeakWeekend(Calendar cal1, Calendar cal2) {
        if (cal1.get(Calendar.DAY_OF_WEEK) > cal2.get(Calendar.DAY_OF_WEEK))
            return true;
        return false;
    }
    
    private long getDailyWorkingTimeAsMinutes() {
        return (getEndHour() * 60 + getEndMinute()) - (getStartHour() * 60 + getStartMinute());
    }
    
    private Calendar setWorkingCalendar(Calendar cal) {
        if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
            cal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR) + 1);
            resetWorkingHourAndSeconds(cal);
        } else if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
            cal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR) + 2);
            resetWorkingHourAndSeconds(cal);
        } else if (cal.get(Calendar.HOUR_OF_DAY) > endHour || (cal.get(Calendar.HOUR_OF_DAY) == endHour && cal.get(Calendar.MINUTE) > endMinute)) {
            cal.set(Calendar.HOUR_OF_DAY, endHour);
            cal.set(Calendar.MINUTE, endMinute);
        } else if (cal.get(Calendar.HOUR_OF_DAY) < startHour || (cal.get(Calendar.HOUR_OF_DAY) == startHour && cal.get(Calendar.MINUTE) < startMinute)) {
            cal.set(Calendar.HOUR_OF_DAY, startHour);
            cal.set(Calendar.MINUTE, startMinute);
        }
        return cal;
    }
    private Calendar resetWorkingHourAndSeconds(Calendar cal) {
        cal.set(Calendar.HOUR_OF_DAY, startHour);
        cal.set(Calendar.MINUTE, startMinute);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal;
    }
    

    }

    这是用法

    // create an instance (working hours from 08:30 to 17:30)
    WorkingTime workingTime = new WorkingTime(8, 30, 17, 30);
    long durationAsMilis = workingTime.calculateWorkingAsMilis(date1, date2);
    

    希望有帮助

    Tuncay Senturk

    【讨论】:

    • 嗨! getDailyWorkingTimeAsMinutes() 方法是什么?
    • 谢谢!最好的问候。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 2019-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多