找到X年的倍数的第一天

时间:2014-08-21 01:21:39

标签: java date graph calendar

我在创建方法时遇到了以下问题:unix时间戳和表示获取第一个日期的时间段的int传入,该方法返回一个unix时间戳表示那个时候的第一天。我现在使用的方法使用Calendar类,如下所示:

public static long firstTime(long in, int period){
    if(period == DAY_OF_FIVE_YEARS){
        period = Calendar.DAY_OF_YEAR;
        in -= in%Vars.FIVE_YEARS;
    }
    cal.setTimeInMillis(in*1000L);
    cal.set(period,cal.getActualMinimum(period));
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    return cal.getTimeInMillis()/1000L;
}

然而,有时我需要获得五年的第一天。例如,我将在1987年的一个日期通过,我希望这个方法能够在1985年的第一天返回。第一个if语句就是我的尝试,但它不起作用,而且我是想知道是否有更简单的方法。请注意,DAY_OF_FIVE_YEARS是一个表示它的int,而Vars.FIVE_YEARS是一个long,即五年内的秒数。

2 个答案:

答案 0 :(得分:1)

感谢ajb,这里有一个方法可以找到几年的第一个倍数:

    public static final int DAY_OF_FIVE_YEARS = 843521;  //just any unused number
    public static long firstTime(long in, int period){
        cal.setTimeInMillis(in*1000L);
        if(period == DAY_OF_FIVE_YEARS){
            int year = cal.get(Calendar.YEAR);
            cal.roll(Calendar.YEAR, -(year%5));
            period = Calendar.DAY_OF_YEAR;
        }
        cal.set(period,cal.getActualMinimum(period));
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        return cal.getTimeInMillis()/1000L;
    }

答案 1 :(得分:1)

tl; dr

LocalDate                          // Represent a date-only value, without time-of-day and without time zone.
.of( 2018 , Month.JANUARY , 23 )   // Get a particular date.
.withDayOfYear( 1 )                // Get first of the year.
.minusYears( 1 )                   // Go back a year

问题所在

您正在滥用日期时间类,显然是试图在“带日期的日期和时区的日期”类中表示仅日期的值。

  

Vars.FIVE_YEARS是一个长整数,表示五年内的秒数

您将五年表示为秒数的概念在两个方面存在缺陷:(a)天并不总是24小时长,并且(b)年并不总是365天长。

另一个问题:您应该在日期时间对象中工作,而不是传递仅以毫秒为单位的整数。这些数字使调试和记录变得困难,因为人类无法理解其含义。因此,错误和错误可能会引起注意。如上所述,这些数字可能无法正确表示预期值。

您正在使用的是可怕的旧日期时间类,而这些类早已被 java.time 类取代。

Instant

将自纪元以来的毫秒数解析为Instant

Instant instant = Instant.ofEpochMilli( myMillis ) ;

时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,Paris France午夜之后的几分钟是新的一天,而Montréal Québec仍然是“昨天”。

ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

LocalDate

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

从上面的ZonedDateTime中提取日期。

LocalDate ld = zdt.toLocalDate() ;

如果您想要一年的第一天,请提出要求。

LocalDate firstOfThisYear = ld.withDayOfYear( 1 ) ;  // Get first of the year.

根据需要回溯许多年。

LocalDate firstOfLastYear = ld.minusYears( 1 ) ;

如果要使用十年的前半年或下半年(0-4和5-9年),请选择年份并进行数学计算。

int year = ld.getYear() ;  // Ex: 2018

关于 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