Java problem in the last month of the month

I am trying to create a date range to span a full month, i.e.

[StartDate; EndDate]

Thus, I have a key date and try to create a new date from it. I have a problem with "endDate" because I want it closer to the end of the day (i.e. 23:59:59).

The code I use is as follows:

public static Date previousMonthLastDate(Date referenceDate) { Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); calendar.setTime(referenceDate); calendar.add(Calendar.MONTH, -1); // move to the previous month int lastDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); calendar.set(Calendar.DAY_OF_MONTH, lastDay); // set the time to be the end of the day calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); return calendar.getTime(); } 

This code works as expected on an Android emulator. However, running it on a real phone gives the wrong date. So, I guess this is some kind of timezone issue.

On the phone, instead of talking on 31 / August / 2010, he gives September 01/2010. This seam value is set after the line of code that sets HOUR_OF_DAY to 23.

Any ideas?

Thanks.

+7
java android date calendar
source share
6 answers

I can’t answer why this happens, but did you try to set it on the first day of the next month and subtract one second / millisecond?

 calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.MILLISECOND, -1); 
+6
source share

I work something like this:

With this code, I set the day in the interval:

 Date day = new Date() 

With this code, I get the interval:

 Calendar startDate = Calendar.getInstance(); Calendar endDate = Calendar.getInstance(); // Set time startDate.setTime(day); endDate.setTime(day); startDate.set(Calendar.DAY_OF_MONTH, 1); startDate.set(Calendar.HOUR_OF_DAY, 0); startDate.set(Calendar.MINUTE, 0); startDate.set(Calendar.SECOND, 0); startDate.set(Calendar.MILLISECOND, 0); endDate.set(Calendar.DAY_OF_MONTH, endDate.getActualMaximum(Calendar.DAY_OF_MONTH)); endDate.set(Calendar.HOUR_OF_DAY, 23); endDate.set(Calendar.MINUTE, 59); endDate.set(Calendar.SECOND, 59); 
+6
source share

If you want the time zone to depend on the settings of the phone, you should not force the time zone when creating your calendar. Just use:

 Calendar calendar = Calendar.getInstance(); 
+3
source share

The calendar API provides you this functionality out of the box, here is a trick to do this:

 // Get the instance of the Calendar. Calendar calendar = Calendar.getInstance(); // Set the date of the First day of Month calendar.set(Calendar.DAY_OF_MONTH, 1); // Roll it to previous day of Year to get the Last day of Month calendar.roll(Calendar.DAY_OF_YEAR, -1); 

Edit: You also need to set the hours, minutes, seconds and milliseconds.

+2
source share
 calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); 
0
source share

TL; DR

 ZoneId z = ZoneId.of( "America/Montreal" ); LocalDate today = LocalDate.now( z ); ZonedDateTime start = today.with( TemporalAdjusters.firstDayOfMonth() ) .atStartOfDay( z ) ; ZonedDateTime stop = today.with( TemporalAdjusters.firstDayOfNextMonth() ) .atStartOfDay( z ) ; 
  • A time zone is required to determine the date.
  • It’s better to specify explicitly than rely implicitly on the current time zone of JVMs.

Avoid obsolete classes

You are using the nasty old time classes, now obsolete, superseded by the java.time classes.

Using java.time

This job is much simpler with java.time classes.

LocalDate

The LocalDate class represents a date value only without time and without a time zone.

Timezone

The time zone is critical for determining the date. At any given moment, the date changes around the world by zone. For example, a few minutes after midnight in Paris, France is a new day, still "yesterday" in Montreal Quebec .

Specify the time zone name in continent/region format, such as America/Montreal , Africa/Casablanca or Pacific/Auckland . Never use an abbreviation of 3-4 characters, for example EST or IST , as they are not real time zones, and are not standardized or even unique (!).

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

Always specify the time zone explicitly. If this parameter is omitted, the current default JVMs timezone is implicitly applied. This default value can be changed at any time by any code in any application in the JVM. Therefore, if this is important, ask the user to specify the desired / expected time zone. If this is not important, you can ask to explicitly state explicitly your intentions in your code, rather than ambiguity, relying on an implicit default value.

 ZoneId z = ZoneId.systemDefault(); // Get JVM's current default time zone. LocalDate today = LocalDate.now( z ); 

TemporalAdjuster

The TemporalAdjuster interface provides classes that can adjust date and time values. The TemporalAdjusters class provides several convenient implementations.

 LocalDate firstOfThisMonth = today.with( TemporalAdjusters.firstDayOfMonth() ); 

ZonedDateTime

To include this date only on a date with the time of day, use the ZoneId time zone to get the ZonedDateTime object.

Do not assume that the first moment of the day is 00:00:00. Due to anomalies such as daylight saving time (DST), the first moment may be something like 01:00:00. Let java.time figure this out by calling atStartOfDay .

 ZonedDateTime zdtStartOfMonth = firstOfThisMonth.atStartOfDay( z ); 

Half open

You are mistaken in trying to determine the last moment of the month. This last moment has an infinitely divisible fractional second. Trying to solve a certain level of detail is not recommended, since different systems use different degrees of detail. Older Java time classes use milliseconds, some databases, such as Postgres, use microseconds, java.time classes use nanoseconds, and other systems use other options.

A more reasonable approach, usually used to work with a time date for defining time intervals, is Half-Open, where the beginning is included, while the ending is exceptional. This means that the month begins at the first moment of the day of the first month and passes until the first, but not including the first moment of the next month.

 LocalDate firstOfNextMonth = today.with( TemporalAdjusters.firstOfNextMonth() ); 

Tune in to your time zone to get a specific moment.

 ZonedDateTime zdtStartOfNextMonth = firstOfNextMonth.atStartOfDay( z ); 

The logic of comparing the moment with this period of time: "Is this moment (a) equal to or after the beginning and (b) less than the end?". Note the absence of "or equal to" in part "b". This means that we get to the end, but do not include the ending.

Also, a shorter way of saying part β€œa” is β€œnot earlier than the start.” Therefore, we can ask easier: "This moment is not until the beginning And until the end?".

 ZonedDateTime moment = ZonedDateTime.now( z ); Boolean spanContainsMoment = ( ! moment.isBefore( zdtStartOfMonth ) ) && ( moment.isBefore( zdtStartOfNextMonth ) ) ; 

By the way, the standard ISO 8601 format for formatting a textual representation of a time span uses a slash to join the beginning and end.

 String output = zdtStartOfMonth.toString() + "/" + zdtStartOfNextMonth.toString() ; 

Interval

You can imagine this time span using the Interval class in ThreeTen-Extra . This class tracks the start and end in UTC as Instant objects. You can extract Instant from the ZonedDateTime object.

 Interval interval = Interval.of( zdtStartOfMonth.toInstant() , zdtStartOfNextMonth.toInstant() ); 

YearMonth

By the way, you can find the YearMonth class useful in your work.


About java.time

The java.time framework is built into Java 8 and later. These classes supersede the nasty old legacy datetime classes such as java.util.Date , Calendar and SimpleDateFormat .

The Joda-Time project, now in maintenance mode , is advised to switch to the java.time classes.

To learn more, see the Oracle Tutorial . And search for qaru for many examples and explanations. JSR 310 specification .

Where to get java.time classes?

  • Java SE 8 and SE 9 and later
    • Built in.
    • Part of the standard Java API with integrated implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and SE 7
    • Most of the functionality of java.time is ported back to Java 6 and 7 in ThreeTen-Backport .
  • Android
    • The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) specifically for Android.
    • See How to use ThreeTenABP ....

The ThreeTen-Extra project extends java.time with additional classes. This project is a proof of possible future additions to java.time. Here you can find useful classes such as Interval , YearWeek , YearQuarter and more .

0
source share

All Articles