代码之家  ›  专栏  ›  技术社区  ›  Asanka sanjaya

如何在java.util.date中获取当前季度的第一个日期和最后一个日期

  •  12
  • Asanka sanjaya  · 技术社区  · 10 年前

    我需要得到 当前季度的第一个日期 作为java.util。Date对象和 当前季度的最后日期 作为java.util。Date对象。

    我使用以下方法来获取本月的第一个日期和本月的最后一个日期。

    private   Date getThisMonthFirstDate(){
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }
    
    private   Date getThisMonthLastDate(){
        Calendar calandar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.DAY_OF_MONTH,1);
        calendar.add(Calendar.MONTH, 1);
        calendar.add(Calendar.DATE, -1);
       return calendar.getTime();
    }
    

    有没有一种方法可以修改该函数来实现这一点,或者有人能指出更好的方法吗?

    假设Q1=一月至二月至三月,Q2=四月、五月、六月等。

    8 回复  |  直到 10 年前
        1
  •  42
  •   Pavel    8 年前

    纯Java-8+解决方案:

    LocalDate localDate = LocalDate.now();
    LocalDate firstDayOfQuarter = localDate.with(localDate.getMonth().firstMonthOfQuarter())
        .with(TemporalAdjusters.firstDayOfMonth());
    
    LocalDate lastDayOfQuarter = firstDayOfQuarter.plusMonths(2)
        .with(TemporalAdjusters.lastDayOfMonth());
    
        2
  •  17
  •   Volodymyr Masliy    5 年前

    以下是Java 7或更早版本的解决方案(否则,我建议检查其他答案):

    private static Date getFirstDayOfQuarter(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.MONTH, cal.get(Calendar.MONTH)/3 * 3);
        return cal.getTime();
    }
    
    private static Date getLastDayOfQuarter(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.MONTH, cal.get(Calendar.MONTH)/3 * 3 + 2);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }
    

    注1: 月份 java.util.Calendar 表示为从0(1月)到11(12月)的整数
    注2: 在Java中,整数的除法会得到下限值(另一个整数值)。因此2/3=0、4/3=1等等。 所以 cal.get(Calendar.MONTH)/3 * 3 计算季度从零开始的指数:0(Q1)、1(Q2)、2(Q3)、3(Q4)。
    例子: 日历中的二月是1。因此,1/3*3=0。
    如果提供了2月的日期,那么季度的开始是1月1日(因为我们得到了0),季度的结束是月份的最后一天0+2=2(3月)

        3
  •  7
  •   Basil Bourque    8 年前

    正如其他人提到的,你正在使用过时的类。Sun/Oracle决定用java取代旧的日期时间类。时间框架,a 巨大的 改善

    避免旧的日期时间类。它们确实设计得很差,令人困惑,而且很麻烦。

    java.时间

    这个 java.time 框架内置于Java8中;7、使用后端口, ThreeTen-Backport 对于Android,该后端端口的适配, ThreeTenABP .

    java。时间框架的灵感来自于非常成功的JodaTime库,由JSR310定义,并由ThreeTenExtra项目扩展。看见 Oracle Tutorial .

    LocalDate

    对于仅限日期的值,不带时间和时区,请使用 LocalDate 作为java.time的一部分内置。获取当前日期需要一个时区,因为世界各地的日期都不一样(东部的新一天更早)。

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

    Quarter & YearQuarter

    这个 ThreeTen-Extra 上面提到的项目是未来可能添加到java.time中的特性的试验场。要使用此库,请将其jar文件添加到项目中(或使用Maven等)。如果您确实不想添加库,请参阅其他解决方案 Answer by dheeran .

    此库当前包括 Quarter 和 YearQuarter 您可能会发现特别有用的类。在代码中传递这些类型的对象比使用字符串和数字来表示季度更安全。

    YearQuarter currentQuarter = YearQuarter.now ( zoneId );
    

    这个 年度季度 有很多有用的方法,包括询问日期。

    LocalDate start = currentQuarter.atDay ( 1 );
    LocalDate stop = currentQuarter.atEndOfQuarter ();
    

    转储到控制台。

    System.out.println ( "today: " + today + " currentQuarter: " + currentQuarter + " start: " + start + " stop: " + stop );
    

    今天:2016-04-08当前季度:2016-Q2开始:2016-03-01停止:2016-06-30

    如果您确实不想添加 额外三个十 根据我的建议,请参阅 Answer by Pavel 对于仅使用内置 java.时间 课程。但如果你在宿舍做很多工作,我相信你会发现 额外三个十 值得为项目添加库。

    转变

    如果必须使用java.util。使用尚未更新为java的旧代码的日期。时间,你可以来回转换。查找添加到旧类中进行转换的新方法。

    不幸的是,旧类缺少表示仅日期值的干净方法。因此,没有完全干净的方式去/从 本地日期 .

    java.sql.Date

    这个 java.sql.Date 类假装只是一个日期,但实际上包含一个调整为 00:00:00.0 。这个类笨拙地继承自 java.util.Date 但该文件明确警告不要使用这一事实;你应该把这两个类作为独立的无关类来对待。

    java.sql.Date sqlDate_quarterStart = java.sql.Date.valueOf( start );
    

    日期类型

    A. java.util.Date 表示一天中的日期和时间,以UTC表示。我们可以首先调整 本地日期 在一天中的第一个时刻 ZonedDateTime .从那里我们可以要求 Instant 这是UTC时间线上的一个时刻。旧的.Date类有一个静态 from( Instant ) 转换方法。

    ZonedDateTime zdt = start.atStartOfDay( zoneId ); // First moment of the day on a certain date.
    Instant instant = zdt.toInstant(); // Moment on the timeline in UTC.
    java.util.Date utilDate = java.util.Date.from( instant );
    

    关于 java.时间

    这个 java.time 该框架内置于Java8和更高版本中。这些类取代了麻烦的旧类 legacy 日期时间类,如 java.util.Date , Calendar ,& SimpleDateFormat .

    这个 Joda-Time 项目,现在在 maintenance mode ,建议迁移到 java.time 课程。

    要了解更多信息,请参阅 Oracle Tutorial 。并搜索Stack Overflow以获得许多示例和解释。规格为 JSR 310 .

    你可以交换 java.时间 对象直接与数据库关联。使用 JDBC driver 符合 JDBC 4.2 或更晚。不需要字符串,不需要 java.sql.* 课程。

    从何处获取java。时间课程?

    这个 ThreeTen-Extra 项目扩展了java。时间与额外的课程。这个项目是未来可能添加java.time的一个试验场。您可以在这里找到一些有用的类,例如 Interval , YearWeek , 年度季度 和 more .

        4
  •  3
  •   Mohan    8 年前

    LocalDate非常简单

    LocalDate inputDate = LocalDate.parse("2018-09-04");
    LocalDate firstDayOfQuarter = inputDate.withMonth(inputDate.get(IsoFields.QUARTER_OF_YEAR) * 3 - 2).with(TemporalAdjusters.firstDayOfMonth());
    LocalDate lastDayOfQuarter = inputDate.withMonth(inputDate.get(IsoFields.QUARTER_OF_YEAR) * 3).with(TemporalAdjusters.lastDayOfMonth());
    

    干杯

        5
  •  1
  •   Pavan    7 年前

    您可以使用java8LocaDate获取当前季度的第一天和最后一天

    下面的代码为您提供了。

    public static LocalDate getCurrentQuarterStartDay(LocalDate date) {
            return date.with(IsoFields.DAY_OF_QUARTER, 1L);
        }
    
    public static LocalDate getCurrentQuarterEndDate(LocalDate date) {
            return date.with(IsoFields.DAY_OF_QUARTER, 92L);
        }
    

    在第二种方法中,92具有部分宽松

    季度日的值在标准年的第一季度从1到90,闰年的第1季度从1至91,第2季度的从1到91,第3季度和第4季度的值从1到92

    有关详细信息,请参阅ISOFields文档 here

        6
  •  1
  •   herman    6 年前

    保持简单

    我认为以下是最优雅的,因为它没有任何神奇的数字(如92)、时间调整器或不明显的计算,并且可以很容易地适应任何季度的开始和结束(而不仅仅是当前季度)。

    import static java.time.temporal.IsoFields.QUARTER_OF_YEAR;
    
    LocalDate date = LocalDate.now(); // can be any other date
    
    int year = date.getYear();
    int quarter = date.get(QUARTER_OF_YEAR);
            
    LocalDate start = YearMonth.of(year, 1)                    // January of given year
                               .with(QUARTER_OF_YEAR, quarter) // becomes first month of given quarter
                               .atDay(1);                      // becomes first day of given quarter
    
    LocalDate end = YearMonth.of(year, 3)                      // March of given year
                             .with(QUARTER_OF_YEAR, quarter)   // becomes 3rd (last) month of given quarter
                             .atEndOfMonth();                  // becomes last day of given quarter
    

    如果您没有日期,但只有一年或一个季度(例如2020年第二季度),则会变成:

    LocalDate start = YearMonth.of(2020, 1).with(QUARTER_OF_YEAR, 2).atDay(1);
    LocalDate end = YearMonth.of(2020, 3).with(QUARTER_OF_YEAR, 2).atEndOfMonth();
    
        7
  •  0
  •   g-t    10 年前

    您可以使用joda:

    Date start = date.withMonthOfYear(((date.getMonthOfYear() / 3) + 1) * 3 - 2)
                .withDayOfMonth(1)
                .withTimeAtStartOfDay()
                .toDate();
    Date end = date.withMonthOfYear(((date.getMonthOfYear() / 3) + 1) * 3)
                .withDayOfMonth(Month.of(((date.getMonthOfYear() / 3) + 1) * 3).maxLength())
                .withTimeAtStartOfDay()
                .toDate();
    

    当DateTime日期=新的DateTime(2016,8,12,1,1,2)时;

    我得到:

    Fri Jul 01 00:00:00 CEST 2016
    Fri Sep 30 00:00:00 CEST 2016
    
        8
  •  0
  •   DaithiG    7 年前

    使用Volodymyr Masliy的答案 java.util.Date ,我的测试中出现了一些错误 如果输入“31/05/2000”,它将返回当年的7月1日,这显然不是我们想要的。

    我用过 java.time.LocalDate 正如Basil Bourque和dheeran所建议的,测试用例工作正常。

    我的方法如下:

    public static Date lastDayOfQuarter(Date date) {
        LocalDate inputDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate lastDayOfQuarter = inputDate.withMonth(inputDate.get(IsoFields.QUARTER_OF_YEAR) * 3).with(TemporalAdjusters.lastDayOfMonth());
        return Date.from(LastDayOfQuarter.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }
    

    我使用ZohhakRunner的UnitTests如下:

    @TestWith({
        "01/03/2000, 31/03/2000",
        "05/04/1982, 30/06/1982",
        "31/05/1982, 30/06/1982",
        "09/07/1990, 30/09/1990",
        "11/11/2019, 31/12/2019",
        "31/03/2016, 31/03/2016"})
    public void lastDayOfQuarter_useInputDate_returnExpectedEndOfQuarterDate(String inputDateAsString, String endOfQuarterAsString) throws ParseException{
        Date inputDate = new SimpleDateFormat("dd/MM/yyyy").parse(inputDateAsString);
        Date expectedDate = new SimpleDateFormat("dd/MM/yyyy").parse(endOfQuarterAsString);
    
        Date result = DateUtils.lastDayOfQuarter(inputDate);
        assertEquals(result, expectedDate);
    }