I know this is an oft asked type of question, and I've been looking around the web for solutions, but to no avail. The problem is that we're fetching a date value from the database and want to display it in a PDF in local time. The raw formatted value is "2022/05/24 15:18:10" and using Costa Rica as an example client time zone (we're in LA), we'd want this "2022/05/24 16:18:10". However, we're getting this: "2022/05/24 17:18:10".
One of the odd things I'm seeing when I run the code below is that it seems that our server time zone is PST, according to Java, but is actually PDT.
creationDate from db=Tue May 24 15:18:10 PDT 2022
Desired creationDate output=2022/05/24 16:18:10
cal.getTimeZone.getDisplayName()=Pacific Standard Time
formatted creationDate=2022/05/24 17:18:10
So one question is: why are we seeing PST instead of PDT and the second question is how do I fix this?
Example code:
public static void main(
String[] args)
{
final String DATE_TIME_PATTERN = "yyyy/MM/dd HH:mm:ss";
final String LA_TIMEZONE_ID = "America/Los_Angeles";
DateFormat df = new SimpleDateFormat(DATE_TIME_PATTERN);
TimeZone serverTimeZone = TimeZone.getTimeZone(LA_TIMEZONE_ID);
Calendar cal = Calendar.getInstance(/* serverTimeZone */); // works same with or without param
TimeZone clientTimeZone = TimeZone.getTimeZone("CST"); // Costa Rica = Central Standard Time
Date creationDate;
df.setTimeZone(clientTimeZone);
// Values as fetched from database.
cal.set(Calendar.DAY_OF_MONTH, 24);
cal.set(Calendar.MONTH, Calendar.MAY);
cal.set(Calendar.YEAR, 2022);
cal.set(Calendar.HOUR_OF_DAY, 15);
cal.set(Calendar.MINUTE, 18);
cal.set(Calendar.SECOND, 10);
creationDate = cal.getTime();
System.out.println("creationDate from db=" + creationDate.toString());
System.out.println("Desired creationDate output=2022/05/24 16:18:10");
System.out.println("cal.getTimeZone.getDisplayName()=" + cal.getTimeZone().getDisplayName());
System.out.println("formatted creationDate=" + df.format(creationDate));
}
So, after a bit of hacking and googling, it would appear (at least to me), that "Central Standard Time" isn't what you want to use (nor should you use it generally).
From time-and-date/Central Standard Time (CST)
Caution: This is NOT the current local time in most locations in that time zone
North America: Only some locations are currently on CST because most places in this time zone are currently on summer time / daylight saving time and are observing CDT.
And then add in time-and-date/Time Zone in Costa Rica
Costa Rica observes Central Standard Time all year. There are no Daylight Saving Time clock changes.
That's not confusing at all 🙄. So, as I "understand" it, CST is normally -6 hours and CDT is -5 hours, but Costa Rica is always -6 hours.
So, based on the observations of your code, CST seems to be having the day light savings value applied to it, regardless of what you do.
So, what to do about it? Well, the simple answer is, don't use it, in fact, stop using the java.util.Date and related APIs altogether and instead, make use of the replacement java.time APIS and the America/Costa_Rica time zone directly, for example...
final String DATE_TIME_PATTERN = "yyyy/MM/dd HH:mm:ss";
final String LA_TIMEZONE_ID = "America/Los_Angeles";
final String dateStringValue = "2022/05/24 15:18:10";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.parse(dateStringValue, formatter);
ZoneId zoneId = ZoneId.of(LA_TIMEZONE_ID);
ZonedDateTime zdt = ldt.atZone(zoneId);
System.out.println(" Local = " + ldt);
System.out.println(" zdt = " + zdt);
System.out.println("Costa_Rica = " + zdt.withZoneSameInstant(ZoneId.of("America/Costa_Rica")));
System.out.println("US/Central = " + zdt.withZoneSameInstant(ZoneId.of("US/Central")));
which prints...
Local = 2022-05-24T15:18:10
zdt = 2022-05-24T15:18:10-07:00[America/Los_Angeles]
Costa_Rica = 2022-05-24T16:18:10-06:00[America/Costa_Rica]
US/Central = 2022-05-24T17:18:10-05:00[US/Central]
This is probably also a good (and over due) reason to dump the old java.util.Date and related classes and update to the java.time APIs, see the date/time trail for more details
Handling Daylight Savings Time in Java might also be worth a read
Related
I have been trying to convert local time (EST) to UTC and vice versa. So, I present a time picker, user selects the time, I convert the same to UTC and send to server. Here's the code:
val cal = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, mHour) //mHour = 15
cal.set(Calendar.MINUTE, mMinute) //mMinute = 00
cal.set(Calendar.SECOND, 0)
val formatter = SimpleDateFormat("HH:mm:ss")
formatter.timeZone = TimeZone.getTimeZone("UTC")
val cutOffTime = formatter.format(cal.time) //this gives 19:00:00 which is correct
Above output for cutOffTime is correct as 15:00 EST is 19:00 UTC after considering day light savings.
Now, I fetch this same cutOffTime from server, convert it to local (EST) and display. Here's the code:
val cutOffTime = jsonObject.get("cutOffTime").getAsString()) //value is 19:00:00
var cutoffTime: Time? = null
val format = SimpleDateFormat("hh:mm:ss")
format.timeZone = TimeZone.getTimeZone("UTC")
cutoffTime = Time(format.parse(cutOffTime).time)
//cutoffTime has value 14:00 which is strange, it should be 15:00
So, cutoffTime in above code has value 14:00 which is strange, it should be 15:00.
Please note that this code was working before day light savings on March 8, 2020. Any idea what am I doing wrong?
Please don't use the old and badly designed java api for date and times. Use the new java.time api. It's much more robust and is nicer to use.
Here is an example on how to do your code with java.time:
int mHour = 15;
int mMinute = 0;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
ZonedDateTime toFormat = LocalDateTime
.now() // Current date and time.
.withHour(mHour).withMinute(mMinute).withSecond(0) // Change hour, minute and second like in your example.
.truncatedTo(ChronoUnit.SECONDS) // Throw away milliseconds and nanoseconds.
.atZone(ZoneOffset.UTC); // Say that the time is located at UTC+0.
String formatted = formatter
.withZone(ZoneId.of("America/New_York")) // Create a new formatter that formats toFormat to the local time America/New_York.
.format(toFormat);
System.out.println(formatted); // Gives 11:00:00 on my machine now. America/New_York is either UTC-5 or UTC-4.
ZonedDateTime parsed = LocalTime
.parse(formatted, formatter) // Parse the String. The result is an instance of LocalTime.
.atDate(LocalDate.now(ZoneId.of("America/New_York"))) // Add the date values which are those of the current local date at America/New_York.
.atZone(ZoneId.of("America/New_York")); // Create a ZonedDateTime of the LocalDateTime to explicitly define the zone.
Instant pointInTimeA = parsed.toInstant();
Instant pointInTimeB = toFormat.toInstant();
System.out.println(pointInTimeA.equals(pointInTimeB)); // Gives true because both describe the same point in time as they should.
The great benefit is that the api will handle everything regarding summertime and wintertime for you. Have read here for information about the EST and why you shouldn't use it.
The problem you face is probably due to the fact that you used HH in one formatter but hh in the other one. Those are not the same. Have read here about Patterns for Formatting and Parsing.
I ended up with below solution. I knew the format of the string from server, so I split it. I didn't want to use the new time API since it is available from API level 26 onwards.
val cutOffString = jsonObject.get("cutOffTime").getAsString() //UTC date 19:00:00 from server
val cal = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, cutOffString.split(":")[0].toInt())
cal.set(Calendar.MINUTE, cutOffString.split(":")[1].toInt())
cal.set(Calendar.SECOND, 0)
cal.timeZone = TimeZone.getTimeZone("UTC")
val cutoffTime: Time = Time(cal.time.time) //15:00:00
I have time stamp in format 2017-18-08 11:45:30.345.
I want to convert it to epoch time, so I am doing below:
String timeDateStr = "2017-18-08 11:45:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
ZonedDateTime zdt = ZonedDateTime.parse(timeDateStr, dtf);
System.out.println(zdt.toInstant().toEpochMilli());
I am getting below error:
java.time.format.DateTimeParseException: Text '2017-18-08 11:45:30.345' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor
I also tried different formats but still getting errors.
Note: originally the question had the input 2017-18-08 12:60:30.345 (with 60 in the minutes field), then it was edited (the time changed from 12:60 to 11:45), but I decided to keep this answer discussing about the original input (12:60), as it also works for the edited version (11:45).
ZonedDateTime needs a timezone or offset, but the input String doesn't have it (it has only date and time).
There are also another details in the input:
the minute value is 60, which is not accepted: the valid values are from 0 to 59 (actually there's a way to accept this, see "Lenient parsing" below)
the hh is the clock-hour-of-am-pm field, so it also needs the AM/PM designator to be fully resolved. As you don't have it, you should use the HH pattern instead
So the pattern must be yyyy-dd-MM HH:mm:ss.SSS, the input can't have 60 as the minutes value (unless you use lenient parsing, which I'll explain below) and you can't direclty parse it to a ZonedDateTime because it doesn't have a timezone/offset designator.
One alternative is to parse it to a LocalDateTime and then define in which timezone/offset this date is. In the example below, I'm assuming it's in UTC:
// change 60 minutes to 59 (otherwise it doesn't work)
String timeDateStr = "2017-18-08 12:59:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
// parse to LocalDateTime
LocalDateTime dt = LocalDateTime.parse(timeDateStr, dtf);
// assume the LocalDateTime is in UTC
Instant instant = dt.toInstant(ZoneOffset.UTC);
System.out.println(instant.toEpochMilli());
This will output:
1503061170345
Which is the equivalent of 2017-18-08 12:59:30.345 in UTC.
If you want the date in another timezone, you can use the ZoneId class:
// get the LocalDateTime in some timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Europe/London"));
System.out.println(z.toInstant().toEpochMilli());
The output is:
1503057570345
Note that the result is different, because the same local date/time represents a different Instant in each timezone (in each part of the world, the local date/time 2017-18-08 12:59:30.345 happened in a different instant).
Also note that API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
You can also use the system's default timezone with ZoneId.systemDefault(), but this can be changed without notice, even at runtime, so it's better to explicity use a specific one.
There's also the option to convert the LocalDateTime to an offset (like -05:00 or +03:00):
// get the LocalDateTime in +03:00 offset
System.out.println(dt.toInstant(ZoneOffset.ofHours(3)).toEpochMilli());
The output will be equivalent to the local date/time in the offset +03:00 (3 hours ahead of UTC):
1503050370345
Lenient parsing
As #MenoHochschild reminded me in the comments, you can use lenient parsing to accept 60 in the minutes field (using the java.time.format.ResolverStyle class):
String timeDateStr = "2017-18-08 12:60:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS")
// use lenient parsing
.withResolverStyle(ResolverStyle.LENIENT);
// parse to LocalDateTime
LocalDateTime dt = LocalDateTime.parse(timeDateStr, dtf);
In this case, 60 minutes are adjusted to the next hour, and the LocalDateTime will be:
2017-08-18T13:00:30.345
Daylight Saving Time
If you decide to use UTC or a fixed offset (using ZoneOffset class), you can ignore this section.
But if you decide to use a timezone (with ZoneId class), you must also take care of DST (Daylight Saving Time) issues. I'm gonna use the timezone I live in as example (America/Sao_Paulo).
In São Paulo, DST starts at October 15th 2017: at midnight, clocks shift 1 hour forward from midnight to 1 AM. So all local times between 00:00 and 00:59 don't exist in this timezone. If I create a local date in this interval, it's adjusted to the next valid moment:
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// October 15th 2017 at midnight, DST starts in Sao Paulo
LocalDateTime d = LocalDateTime.of(2017, 10, 15, 0, 0, 0, 0);
ZonedDateTime z = d.atZone(zone);
System.out.println(z);// adjusted to 2017-10-15T01:00-02:00[America/Sao_Paulo]
When DST ends: in February 18th 2018 at midnight, clocks shift back 1 hour, from midnight to 23 PM of 17th. So all local times from 23:00 to 23:59 exist twice (in DST and in non-DST), and you must decide which one you want:
// February 18th 2018 at midnight, DST ends in Sao Paulo
// local times from 23:00 to 23:59 at 17th exist twice
LocalDateTime d = LocalDateTime.of(2018, 2, 17, 23, 0, 0, 0);
// by default, it gets the offset before DST ends
ZonedDateTime beforeDST = d.atZone(zone);
System.out.println(beforeDST); // before DST end: 2018-02-17T23:00-02:00[America/Sao_Paulo]
// get the offset after DST ends
ZonedDateTime afterDST = beforeDST.withLaterOffsetAtOverlap();
System.out.println(afterDST); // after DST end: 2018-02-17T23:00-03:00[America/Sao_Paulo]
Note that the dates before and after DST ends have different offsets (-02:00 and -03:00). This affects the value of epochMilli.
You must check when DST starts and ends in the timezone you choose and check the adjustments accordingly.
Corrected your code regarding yyyy-dd-MM. Also minute value could be 1-59 not 60. You provided 60. This is another simple way to solve the issue. Simply use DateFormat class.
String timeDateStr = "2017-18-08 12:59:30.345";
DateFormat df = new SimpleDateFormat("yyyy-dd-MM hh:mm:ss.SSS", Locale.ENGLISH);
try {
Date d = df.parse(timeDateStr);
System.out.println(d.toInstant().toEpochMilli());
} catch (ParseException e) {
e.printStackTrace();
}
Just i had made little bit change in nagendra547's answer
Please reffer to below code:-
String timeDateStr = "2017-18-08 12:59:30.345";
DateFormat df = new SimpleDateFormat("yyyy-dd-mm hh:mm:ss.SSS", Locale.ENGLISH);
try {
Date d = df.parse(timeDateStr);
System.out.println(d.toInstant().toEpochMilli());
} catch (ParseException e) {
e.printStackTrace();
}
Your code will fail for below 3 reasons.
Your date string (2017-18-08 12:60:30.345), doesn't match with the Formatter you used. It should be yyyy-MM-dd HH:mm:ss.SSS instead of yyyy-dd-MM hh:mm:ss.SSS
the range of minutes is (0-59), 60 doesn't come in this range.
Even if you have corrected code based above point it won't run for ZonedDateTime. So you would need to create a LocalDateTime before and then pass a ZoneId to it.
The code should look like below:
String timeDateStr = "2017-18-08 12:59:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
LocalDateTime date = LocalDateTime.parse(timeDateStr, dtf);
ZonedDateTime zdt = date.atZone(ZoneId.of("Europe/London"));
System.out.println(zdt.toInstant().toEpochMilli());
I've timestamp based on IST ( Indian Standard Time / GMT + 5:30 Hrs), My application shows last activity time based on device timestamp.
that is current time - activity timestamp. Its fine when the device timezone is IST.
For example,
Activity timestamp - 11/Feb/2016 09:00:00 AM
Current timestamp (IST) - 11/Feb/2016 10:00:00 AM
My Calculation = Current timestamp - Activity timestamp
So Application shows 1 hr ago
But the device timezone changed to some other like PHT for the same time (Philippine Time / GMT + 8 Hr)
Activity timestamp - 11/Feb/2016 09:00:00 AM
Current timestamp(PHT) - 11/Feb/2016 12:30:00 AM (plus 2:30Hrs compare with IST)
My Calculation = Current timestamp - Activity timestamp
So Application shows 3 hrs 30 mis ago
My problem is, How to get the IST time always using java? whatever the timezone, I need IST time.
I tried below code, When i change the value to IST but the timezone automatically changed to device timezone.
Please refer below URL for source code http://goo.gl/dnvQF5
SimpleDateFormat sd = new SimpleDateFormat(
"yyyy.MM.dd G 'at' HH:mm:ss z");
Date date = new Date();
// TODO: Avoid using the abbreviations when fetching time zones.
// Use the full Olson zone ID instead.
sd.setTimeZone(TimeZone.getTimeZone("GMT"));
String gmtDate = sd.format(date);
System.out.println("GMT --> " + gmtDate);
String istDate = gmtDate.replace("GMT", "IST");
System.out.println("After Replace -> " + istDate);
sd.setTimeZone(TimeZone.getTimeZone("IST"));
try {
Date istConvertedDate = sd.parse(gmtDate);
System.out.println("After Convert --> " + istConvertedDate);
} catch (ParseException ex) {
ex.printStackTrace();
}
I got output like
GMT --> 2016.02.11 AD at 05:20:07 GMT
After Replace -> 2016.02.11 AD at 05:20:07 IST
After Convert --> Thu Feb 11 00:20:07 EST 2016
Please help me to resolve this.
The class java.util.Date is only a thin wrapper around elapsed milliseconds since UNIX epoch (1970-01-01T00:00:00Z). Objects of this type don't carry any format or timezone information. Therefore every such object has completely lost the timezone information after parsing a text with timezone identifier or name using SimpleDateFormat.
What you observe and are confused about is the fact that the method toString() of this class uses a specific representation based on the system timezone.
Another thing: If you apply a string manipulation replacing "GMT" by "IST" (an ambivalent timezone name - Israel? India? Ireland?) then you effectively change the moment/instant while keeping the local time representation. Do you really want this?
If you want to preserve the timezone information which was originally parsed then you could use ZonedDateTime in the library Threeten-ABP or DateTime in the library Joda-Time-Android or ZonalDateTime in my library Time4A.
Try
public static void main(String[] args) {
SimpleDateFormat sd = new SimpleDateFormat(
"yyyy.MM.dd G 'at' HH:mm:ss z");
Date date = new Date();
// TODO: Avoid using the abbreviations when fetching time zones.
// Use the full Olson zone ID instead.
sd.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(sd.format(date));
String gmtDate = sd.format(date);
System.out.println(gmtDate);
//Here you create a new date object
Date istDate= new Date();
sd.setTimeZone(TimeZone.getTimeZone("IST"));
String istDate=sd.format(istDate);
System.out.println(istDate)
}
This way the first printed time will be GMT and second will be ISD.
You can use java.util.Calendar
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("IST"));
this calendar contains current time in IST timeZone.
You can set timeStamp:
calendar.setTimeInMillis(timeStamp);
And get java.util.Date or time stamp
Date date = calendar.getTime();
Long timeStamp = calendar.getTimeInMillis();
Replace
sd.setTimeZone(TimeZone.getTimeZone("IST"));
to
TimeZone.setDefault(TimeZone.getTimeZone("IST"));
For the below code I get different outputs
TimeZone t = TimeZone.getTimeZone("GMT-8"); // Also tried UTC-8 and GMT-8:00
//TimeZone t = TimeZone.getTimeZone("America/Los_Angeles");
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
Date d = null;
Calendar c = Calendar.getInstance(t);
c.set(Calendar.MONTH, Calendar.AUGUST);
c.set(Calendar.DAY_OF_MONTH, 22);
c.set(Calendar.YEAR, 2013);
d = c.getTime();
String s = sdf.format(d);
System.out.println(s + " " + t.inDaylightTime(d));
Output is:
08/22/2013 false
Now America/Los_Angeles is GMT-8 / UTC-8 or PST. But when I change parameter from GMT-8 to America/Los_Angeles,
Output is:
08/22/2013 true
Can't use PST like abbreviations since its deprecated. Also CST can mean both Central Standard time and China Standard Time.
The input I have is like -8, -9 -14 etc. to which I wish to prepend GMT/UTC to know if I can get the DST activation on a given date.
Please guide me in this regard.
The results are correct, when you specify GMT with an offset there is no way to know which country/city is this, so it is not possible to determine if Day Light Time is active or no.
So inDaylightTime() will be false for all time zones specified with GMT and an offset.
CST in Java is Central Standard Time, you can check yourself by this line of code:
System.out.println(TimeZone.getTimeZone("CST").getDisplayName());
China Standard Time zone ID in Java is CTT
Edit
Consider using Joda time and date API for more up-to-date Timezone information
The results are correct, as explained by #iTech. Just to add, you can lookup the timezone ids available as
import java.util.TimeZone;
public class TimeZones {
public static void main(String[] args) {
String[] timezones = TimeZone.getAvailableIDs();
System.out.println(timezones.length);
for (String t : timezones) {
System.out.println(t);
}
}
}
This prints a long list of 600 timezones available.
You can then get the display name for the abbreviated ones as
System.out.println(TimeZone.getTimeZone("IST").getDisplayName());
I have a Java app that needs to be cognizant of the time zone. When I take a Unix epoch time and try to convert it into a timestamp to use for an Oracle SQL call, it is getting the correct timezone, but the timezone "useDaylightTime" value is not correct, i.e., it is currently returning "true", when we are NOT in DST (I am in Florida in TZ "America/New_York").
This is running on Red Hat Linux Enterprise 6, and as far as I can tell, it is correctly set up for the timezone, e.g. 'date' returns:
Wed Nov 28 12:30:12 EST 2012
I can also see, using the 'zdump' utility, that the current value for 'isdst' is 0.
My Java version is 1.6.0_31.
I have Googled this and seen the numerous issues this has caused, but many of them simply say to set the TZ manually, but my issue is not the TZ, but the fact that the default TZ has the "isDaylight" set to 'true'. I believe this is causing my query to return data that is one hour off (I can see that it is).
Here is a simple code piece I have run to try and reproduce this in the simplest way possible:
public class TZdefault {
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis()/1000;
Calendar start = Calendar.getInstance();
start.setTimeInMillis(startTime);
start.setTimeZone(TimeZone.getDefault());
System.out.println("Start UTC: " + start + "ms: " + start.getTimeInMillis());
System.out.println("use daylight: " + start.getTimeZone().useDaylightTime());
} // end main
} // end class
One final thing. If in my code I set the TZ to "EST", it of course does return a TZ with 'isDaylight' set to False. But that is not a good solution.
I wanted to add some more detail that I had been hoping to hide.
I have records in an Oracle 11g database that use TIMESTAMP with TIMEZONE fields. I am simply doing JDBC queries where two of the parameters are using BETWEEN a start timestamp and end timestamp.
When I query this table, I am using a prepared statement that is using a Calendar entry, the sole purpose of which was to try and manipulate the timezone. The bottom line is that I am doing a pstmt.setTimestamp() call using the 'getTimeInMillis' method for the start and end time after the "default" timezone was applied. The log output shows that in fact it is putting in the correct milliseconds, but the returned SQL results are clearly off by one hour exactly!
I am still trying to verify that there is not an issue on the data insertion side as well.
But I have a lot of debug information, and it looks like I am asking for the correct time in my JDBC query.
the timezone useDaylightTime value is not correct, i.e., it is currently returning "true", when we are NOT in DST
I think you're confusing useDaylightTime with inDaylightTime. The former tells you whether there is a transition between daylight time and standard time in the future, not which side of that transition you're on. For example, it returns false for Chinese time zones because China does not adjust for daylight savings time, but it returns true for most US time zones because most US states (except Arizona) do observe daylight savings time.
inDaylightTime
public abstract boolean inDaylightTime(Date date)
Queries if the given date is in Daylight Saving Time in this time zone.
vs
useDaylightTime
public abstract boolean useDaylightTime()
Queries if this TimeZone uses Daylight Saving Time.
If an underlying TimeZone implementation subclass supports historical and future Daylight Saving Time schedule changes, this method refers to the last known Daylight Saving Time rule that can be a future prediction and may not be the same as the current rule. Consider calling observesDaylightTime() if the current rule should also be taken into account.
If you want to disable daylight saving calculation, then you must set your timezone to EST. Else otherwise time will be calculated based on default time zone set for AMERICA/NEW_YORK
TimeZone zoneEST = TimeZone.getTimeZone("EST");
System.out.println(zoneEST.getDSTSavings()); //0 hour
System.out.println(zoneEST.getRawOffset()); //5 hour
TimeZone.setDefault(zoneEST);
System.out.println("");
TimeZone zoneNY = TimeZone.getTimeZone("America/New_York");
System.out.println(zoneNY.getDSTSavings()); // 1 hour
System.out.println(zoneNY.getRawOffset()); // 5 hour
I have found a way to ensure the daylight saving is ignored
TimeZone tz = TimeZone.getTimeZone("GMT");
TimeZone.setDefault(tz);
GregorianCalendar calendar;
calendar = new GregorianCalendar();
Set the timezone before you create your GregorianCalendar object
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class TimeZoneTest {
public static void main(String[] argv) throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
String dateInString = "22-01-2015 10:15:55 AM";
Date date = formatter.parse(dateInString);
TimeZone tz = TimeZone.getDefault();
// From TimeZone Asia/Singapore
System.out.println("TimeZone : " + tz.getID() + " - " + tz.getDisplayName());
System.out.println("TimeZone : " + tz);
System.out.println("Date : " + formatter.format(date));
// To TimeZone America/New_York
SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
TimeZone tzInAmerica = TimeZone.getTimeZone("America/New_York");
sdfAmerica.setTimeZone(tzInAmerica);
String sDateInAmerica = sdfAmerica.format(date); // Convert to String first
Date dateInAmerica = formatter.parse(sDateInAmerica);
System.out.println("\nTimeZone : " + tzInAmerica.getID() +
" - " + tzInAmerica.getDisplayName());
System.out.println("TimeZone : " + tzInAmerica);
System.out.println("Date (String) : " + sDateInAmerica);
System.out.println("Date (Object) : " + formatter.format(dateInAmerica));
}
}