Java将毫秒添加到毫秒时间戳,省略周末和假日

时间:2015-08-15 08:06:27

标签: java javafx timestamp

我是初学者,我希望将毫秒添加到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 个答案:

答案 0 :(得分:1)

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;
}

答案 1 :(得分:0)

tl; dr

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

java.time

现代方法使用现代的 java.time 类,而不使用可怕的旧式旧类,例如CalendarDate

MonthDay

  

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

使用MonthDay类代替这些值,而不是字符串。使用对象可使您的代码更具自记录性,可确保有效值并提供type-safety

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

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

LocalDate

LocalDate类表示没有日期和时区的仅日期值。

时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,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。切勿使用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。

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.

或者更好的是,使用预定义的Month枚举对象,每年的每个月使用一个。提示:在整个代码库中使用这些Month对象,而不是仅使用整数,可以使您的代码更具自文档性,确保有效值并提供type-safety

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

数学

您可以通过在plus…上调用minus…LocalDate方法来增加或减少天数。

LocalDate later = ld.plusDays( 11 ) ;

您可以通过定义EnumSet枚举对象中的DayOfWeek来跳过周末(星期六/星期日)。

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

对照该日期检查下一个约会。

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

更简单的方法是将ThreeTen-Extra库添加到您的项目中。这样就提供了一个TemporalAdjuster实现,它跳过了星期六/星期日:nextWorkingDay()

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.time

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

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

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

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

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore