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?
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
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());
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?
- 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.