有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaFXJava向毫秒时间戳添加毫秒忽略周末和假日

我是一名初学者,我想将毫秒添加到java时间戳中(以毫秒为单位),并获取结果时间(以毫秒为单位),以便进一步操作。我试图通过每毫秒增加一次时间戳并检查它是否到达假日或周末来实现这一点,然后我跳过了这一天。那样做不太明智。需要永远。有人已经发明了轮子吗

这是我糟糕且非常糟糕的代码(不要使用此代码,需要很长时间)

public static class businessdays {

        public static long addWorkingTime(long timestamp, long milliseconds){

            for (int i=0;i<milliseconds;i ++){
                long test_timestamp = timestamp + 1;
                while (isHoliday(test_timestamp)){
                    System.out.println("isHoliady");
                    timestamp += 24 * 60 * 60 * 1000; //jump weekend or holiday
                    test_timestamp += (12 * 60 * 60 * 1000);
                }               
                timestamp += i;
            }

            return timestamp;           
        }

        private static boolean isHoliday(long timestamp){
            List<String> holidays = new ArrayList<String>(Arrays.asList("01/01,05/01,06/01,10/20,12/12,12/25,12/26".split(",")));
            SimpleDateFormat dw = new SimpleDateFormat("u"); //date of the week - 1 - 7
            SimpleDateFormat dd = new SimpleDateFormat("dd"); //1 - 30/31
            SimpleDateFormat dm = new SimpleDateFormat("MM"); //1 - 12
            Date test_timeDate = new Date(timestamp);
            String date = dm.format(test_timeDate)+"/"+dd.format(test_timeDate); //MM/dd
            String doweek = dw.format(test_timeDate);
            if (holidays.contains(date) || doweek.contains("6") || doweek.contains("7")){
                return true;
            }
            return false;
        }
    }

共 (2) 个答案

  1. # 1 楼答案

    tl;博士

    • 不要用毫秒来追踪工作日和假期
    • 使用LocalDate类,以及DayOfWeekMonthMonthDay

    爪哇。时间

    现代方法使用现代的java。时间类,而不是像Calendar&Date

    MonthDay

    new ArrayList(Arrays.asList("01/01,05/01,06/01,10/20,12/12,12/25,12/26".split(",")))

    对于这些值,使用^{}类而不是字符串。使用对象可以使代码更加自我记录,确保有效值,并提供type-safety

    List< MonthDay > monthDayHolidays = List.of( 
        MonthDay.of( Month.JANUARY , 1 ) ,
        MonthDay.of( Month.DECEMBER , 25 ) ,
        MonthDay.of( Month.DECEMBER , 26 ) 
    ) ;
    

    这种定义假日的方法是不完整的。有些假期是按日期设定的,但很多是相对的,比如某个月的第三个星期一

    LocalDate

    ^{}类表示一个只包含日期的值,不包含一天中的时间和时区

    时区对确定日期至关重要。在任何一个特定的时刻,世界各地的日期因地区而异。例如,午夜过后几分钟在Paris France是新的一天,而在Montréal Québec仍然是“昨天”

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

    continent/region的格式指定一个proper time zone name,例如^{}^{}Pacific/Auckland。千万不要使用3-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的(!)

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

    如果您想使用JVM的当前默认时区,可以请求它并将其作为参数传递。如果省略,JVM的当前默认值将隐式应用。最好是显式的,因为JVM中任何应用程序的任何线程中的任何代码都可以在运行时期间随时更改默认值

    ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.
    

    或者指定一个日期。你可以用数字来设定月份,1-12月的数字是1-12

    LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ;  // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
    

    或者,更好的方法是使用预先定义的^{}enum对象,一年中每个月一个。提示:在整个代码库中使用这些Month对象,而不仅仅是一个整数,以使代码更加自我记录,确保有效值,并提供type-safety

    LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
    

    数学

    您可以通过调用plus…&minus…方法在LocalDate

    LocalDate later = ld.plusDays( 11 ) ;
    

    通过定义^{}枚举对象的^{},可以跳过周末(周六/周日)

    Set< DayOfWeek > weekend = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY ) ;
    

    把你的下一次约会和那一套核对一下

    if( weekend.contains( localDate.getWeekOfDay() ) ) {
        nextWorkingDay.plusDays( 1 ) ;
    }
    

    更简单的方法是将ThreeTen-Extra库添加到项目中。这提供了一个跳过Sat/Sun的^{}实现:^{}

    LocalDate nextWorkingDay = 
        localDate.with( 
            org.threeten.extra.Temporals.nextWorkingDay() 
        ) 
    ;
    

    过滤器

    你必须将每个日期与你的假期列表进行比较

    我们可以向LocalDate索取它的MonthDay

    MonthDay md = MonthDay.from( localDate ) ;
    

    看看MonthDay是否出现在我们的列表中

    if( monthDayHolidays.contains( md ) ) 
    { … skip … }
    

    毫秒

    如果必须从UTC中1970年的第一个时刻开始计算毫秒数,请将其解析为Instant对象

    Instant instant = Instant.ofEpochMilli( … ) ;
    

    约会需要一个时区。在任何一个特定的时刻,世界各地的日期因地区而异。巴黎午夜过后的几分钟,法国是一个新的一天,而魁北克山仍然是“昨天”

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

    将此ZoneId应用于Instant以获取ZonedDateTime对象。与Instant相同的时刻,时间轴上的相同点,但通过特定地区的人们使用的挂钟来看

    ZonedDateTime zdt = instant.atZone( z ) ;
    

    只提取日期部分,不包括一天中的时间和时区

    LocalDate ld = zdt.toLocalDate() ;
    

    关于java。时间

    {a18}框架内置于Java8及更高版本中。这些类取代了^{}^{}、&^{}

    目前位于maintenance modeJoda-Time项目建议迁移到java.time

    要了解更多信息,请参阅Oracle Tutorial。并搜索堆栈溢出以获得许多示例和解释s、 规范是JSR 310

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

    在哪里可以获得java。时间课

    ThreeTen-Extra项目扩展了java。有额外课程的时间。这个项目是java未来可能增加的一个试验场。时间你可以在这里找到一些有用的类,比如^{}^{}^{}more

  2. # 2 楼答案

    Calendar类将允许您在几天内进行操作,这可能更可取。对于日期处理来说,毫秒往往是一个幼稚的选择,因为不是所有的日子都有相同的毫秒数。每隔闰秒插入一次,夏时制周期每结束一天比通常的24小时少或多一整小时

    final static int DAY_MILLIS = 24 * 60 * 60 * 1000;
    static String hols[] = new String[] { "01/01", "05/01", "06/01", "10/20", "12/12", "12/25", "12/26" };
    
    public static long addWorkingTime(long timestamp, long milliseconds)
    {
        // Get a calendar from a timestamp.
        Calendar cal = new GregorianCalendar();
        cal.setTimeInMillis(timestamp);
        while (isHoliday(cal)) cal.add(Calendar.DATE, 1);
    
        // Count off the days in milliseconds.
        int days = (int)(milliseconds / DAY_MILLIS);
        for (int i = 0; i < days; i++) {
            cal.add(Calendar.DATE, 1);
            while (isHoliday(cal)) cal.add(Calendar.DATE, 1);
        }
    
        // Apply the leftover from milliseconds if there is any.
        milliseconds = milliseconds - days * DAY_MILLIS;
        cal.add(Calendar.MILLISECOND, milliseconds);
        while (isHoliday(cal)) cal.add(Calendar.DATE, 1);
    
        // Return a timestamp from a calendar.
        return cal.getTimeInMillis();
    }
    
    static boolean isHoliday(Calendar cal)
    {
        int dow = cal.get(Calendar.DAY_OF_WEEK);
        if (dow == Calendar.SATURDAY || dow == Calendar.SUNDAY) return true;
        String mmdd = new SimpleDateFormat("MM/dd").format(cal.getTime());
        return Arrays.binarySearch(hols, mmdd) >= 0;
    }