How to get the first date and last date of current quarter in java.util.Date

前端 未结 8 850

I need to get the first date of the current quarter as a java.util.Date object and the last date of the current quarter as a java.util.Date

相关标签:
8条回答
  • 2020-12-10 14:52

    As others mentioned, you are using outmoded classes. Sun/Oracle decided to supplant the old date-time classes with the java.time framework, a vast improvement.

    Avoid the old date-time classes. They really are poorly designed, confusing, and troublesome.

    java.time

    The java.time framework is built into Java 8. For Java 6 & 7, use the back-port, ThreeTen-Backport. For Android, the adaptation of that back-port, ThreeTenABP.

    The java.time framework is inspired by the highly successful Joda-Time library, defined by JSR 310, and extended by the ThreeTen-Extra project. See Oracle Tutorial.

    LocalDate

    For a date-only value, without time-of-day and without time zone, use LocalDate built-in as part of java.time. To get the current date requires a time zone as the date varies around the world (a new day dawns earlier in the east).

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

    Quarter & YearQuarter

    The ThreeTen-Extra project mentioned above serves as the proving ground for possible future features to be added to java.time. To use this library, add its jar file to your project (or use Maven etc.). If you really don’t want to add a library, see an alternate solution Answer by dheeran.

    This library currently includes the Quarter and YearQuarter classes that you might find particularly useful. Safer to pass around objects of these types in your code rather than use strings and numbers to represent your quarters.

    YearQuarter currentQuarter = YearQuarter.now ( zoneId );
    

    The YearQuarter has many useful methods, including asking for its dates.

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

    Dump to console.

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

    today: 2016-04-08 currentQuarter: 2016-Q2 start: 2016-04-01 stop: 2016-06-30

    If you really do not want to add the ThreeTen-Extra library as I recommended, see the Answer by Pavel for another solution using only the built-in java.time classes. But if you are doing much work with quarters, I am sure you’ll find ThreeTen-Extra to be well worth the trouble of adding a library to your project.

    Conversion

    If you must use java.util.Date to work with old code not yet updated to java.time, you can convert back and forth. Find new methods added to the old classes for conversion.

    Unfortunately, the old classes lack any clean way to represent a date-only value. So there is no perfectly clean way to go to/from a LocalDate.

    java.sql.Date

    The java.sql.Date class pretends to be a date-only but actually contains a time-of-day adjusted to 00:00:00.0. This class awkwardly inherits from java.util.Date but the doc clearly warns against using that fact; you are supposed to treat the two as separate unrelated classes.

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

    java.util.Date

    A java.util.Date represents both a date and time-of-day, effectively in UTC. We can first adjust our LocalDate into the first moment of a day to get a date with time-of-day, a ZonedDateTime. From there we can ask for an Instant which is a moment on the timeline in UTC. The old .Date class has a static from( Instant ) conversion method.

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

    About java.time

    The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

    The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

    To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

    You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

    Where to obtain the java.time classes?

    • Java SE 8, Java SE 9, Java SE 10, and later
      • Built-in.
      • Part of the standard Java API with a bundled implementation.
      • Java 9 adds some minor features and fixes.
    • Java SE 6 and Java SE 7
      • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
    • Android
      • Later versions of Android bundle implementations of the java.time classes.
      • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

    The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

    0 讨论(0)
  • 2020-12-10 14:55

    Pure Java-8+ solution:

    LocalDate localDate = LocalDate.now();
    LocalDate firstDayOfQuarter = localDate.with(localDate.getMonth().firstMonthOfQuarter())
        .with(TemporalAdjusters.firstDayOfMonth());
    
    LocalDate lastDayOfQuarter = firstDayOfQuarter.plusMonths(2)
        .with(TemporalAdjusters.lastDayOfMonth());
    
    0 讨论(0)
  • 2020-12-10 14:57

    You can use 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();
    

    When DateTime date = new DateTime(2016, 8, 12, 1, 1, 1);

    I get:

    Fri Jul 01 00:00:00 CEST 2016
    Fri Sep 30 00:00:00 CEST 2016
    
    0 讨论(0)
  • 2020-12-10 14:57

    Using the answer from Volodymyr Masliy using java.util.Date, there is some bug that came up in my tests If you enter "31/05/2000" it returns July 1st of that year, which is obviously not what we're looking for.

    I used java.time.LocalDate as suggested by Basil Bourque and dheeran and the test case works ok.

    My method is as follows:

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

    My UnitTests using ZohhakRunner are as follows:

    @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);
    }
    
    0 讨论(0)
  • 2020-12-10 14:58

    you can use java 8 LocaDate to get current quarter first and last day

    The code below gives you.

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

    Here in second method the 92 has partially lenient

    The day-of-quarter has values from 1 to 90 in Q1 of a standard year, from 1 to 91in Q1 of a leap year, from 1 to 91 in Q2 and from 1 to 92 in Q3 and Q4

    see ISOFields documentation for details here

    0 讨论(0)
  • 2020-12-10 15:11

    Keep it simple

    I think the following is most elegant because it doesn't have any magical numbers (like 92), TemporalAdjusters or non-obvious calculations, and can easily be adapted to get the start and end of any quarter (not just current quarter).

    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
    

    If you don't have a date, but just a year and quarter (e.g. Q2 2020), this becomes:

    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();
    
    0 讨论(0)
提交回复
热议问题