0

I have method to find month end date based on the timezone.

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
calendar.set(
    Calendar.DAY_OF_MONTH, 
    calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
);
System.out.println(calendar.getTime());`

It displays output: Thu Aug 30 18:04:54 PDT 2018.

It should, however, give me an output in CET.

What am I missing?

Karthik
  • 107
  • 1
  • 10
  • 1
    FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Aug 03 '18 at 18:58
  • Don’t rely on three and four letter time zone abbreviations like CET. Most are ambiguous, and many, like CET, are not true time zones. Instead give time zone as for example Europe/Paris. The European countries that use CET, use CEST in August, so your requirement seems rather — should I say, contradictory, impossible? Or just detached from the real world? – Ole V.V. Aug 04 '18 at 19:01
  • Why do you want output in CET? The last day of August is August 31 in all time zones. Asking also because `LocalDate` of java.time will give you that independently of time zone. Isn’t that even better? – Ole V.V. Aug 04 '18 at 21:13

3 Answers3

4

The Calendar.getTime() method returns a Date object, which you then printed in your code. The problem is that the Date class does not contain any notion of a timezone even though you had specified a timezone with the Calendar.getInstance() call. Yes, that is indeed confusing.

Thus, in order to print a Date object in a specific timezone, you have to use the SimpleDateFormat class, where you must call SimpleDateFormat.setTimeZone() to specify the timezone before you print.

Here's an example:

import java.util.Calendar;
import java.util.TimeZone;
import java.text.SimpleDateFormat;

public class TimeZoneTest {

    public static void main(String argv[]){
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        System.out.println("calendar.getTime(): " + calendar.getTime());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss z");
        sdf.setTimeZone(TimeZone.getTimeZone("CET"));
        System.out.println("sdf.format(): " + sdf.format(calendar.getTime()));
     }
}

Here is the output on my computer:

calendar.getTime(): Fri Aug 31 01:40:17 UTC 2018
sdf.format(): 2018-Aug-31 03:40:17 CEST
stackoverflowuser2010
  • 38,621
  • 48
  • 169
  • 217
  • Thank you explaining it clearly. I had confusion with setting timezone to calendar object not returning the proper time. – Karthik Aug 02 '18 at 01:58
1

This is because Date object doesn't have timezone as part of its state, and getTime() actually returns a date which corresponds to the JVM's timezone, instead you need SimpleDateFormat to format and print the date in your required timezone.

If you try adding the following line of code, you could see that the timezone in the calendar is actually CET.

System.out.println(calendar.getTimeZone().getDisplayName()); 
Ganesh S P
  • 11
  • 2
1

tl;dr

YearMonth                         // Represent a year-month without day-of-month.
.now(                             // Capture the current year-month as seen in the wall-clock time used by the people of a particular region (a time zone).
    ZoneId.of( "Africa/Tunis" )   // Specify your desired time zone. Never use 3-4 letter pseudo-zones such as `CET`. 
)                                 // Returns a `YearMonth` object.
.atEndOfMonth()                   // Determine the last day of this year-month. Returns a `LocalDate` object.
.atStartOfDay(                    // Let java.time determine the first moment of the day. Not necessarily 00:00:00, could be 01:00:00 or some other time-of-day because of anomalies such as Daylight Saving Time (DST). 
    ZoneId.of( "Africa/Tunis" )  
)                                 // Returns a `ZonedDateTime` object, representing a date, a time-of-day, and a time zone.

java.time

You are using the terrible old Calendar class that was supplanted years ago but the modern java.time classes.

LocalDate

If you need only a date, use LocalDate class. Then the time zone is irrelevant for your output.

But time zone is very relevant for determining the current date. For any given moment, the date varies around the globe by zone.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as CET or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "Europe/Paris" ) ;  // Or "Africa/Tunis" etc.
LocalDate today = LocalDate.now( z ) ;    // Capture the current date as seen by the wall-clock time used by the people of a certain region (a time zone).

YearMonth

Get the month for that date. Represent a year-month with, well, YearMonth.

YearMonth ym = YearMonth.from( today ) ;

Or skip the LocalDate.

YearMonth ym = YearMonth.now( z ) ;

Get the end of the month.

LocalDate endOfThisMonth = ym.atEndOfMonth() ;

ISO 8601

To generate a String representing that LocalDate object’s value, call toString. The default format is taken from the ISO 8601 standard. For a date-only value that will be YYYY-MM-DD such as 2018-01-23.

String output = endOfThisMonth.toString() ;

If you need another format, use DateTimeFormatter class. Search Stack Overflow for many examples and discussions.

Moment

If you need a moment, you can add a time-of-day and time zone to your LocalDate to get a ZonedDateTime. Or let ZonedDateTime determine the first moment of the day (which is not always 00:00:00!).

ZonedDateTime zdt = LocalDate.atStartOfDay( z ) ;

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?

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.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154