problems with Java daylight savings time - java

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

Related

Java and converting displayed value into local time zone and daylight savings

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

Oracle's to_date function returns a non existing date

When java.util.Date is parsing "01/01/1901" to a Date objet, Java API is converting the date to “01/01/1901 0:08:39” instead of “01/01/1901 0:00:00” and this is happening only for Malaysia time zone.
This is happening because in 1901 Malaysia decided to synchronize his time zone with Penang, Malacca and Singapore and for that reason they added 8 minutes and 39 seconds. Java knows this and for that reason is automatically adding minutes and seconds to the date object (Because in Malaysia the hour 00:00:00 doesn’t exist for date 01/01/1991).
Malaysia TZ change:
https://www.timeanddate.com/time/change/malaysia/kuala-lumpur?year=1901
Java Source:
public class SimpleDateFormatExample {
public static void main(String[] args) {
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
// Locale for formatter
Locale malaysianLocale = new Locale("ms", "MY");
// Default date and time format for Malaysia
DateFormat defaultMalaysianFormatter = DateFormat.getDateTimeInstance(
DateFormat.DEFAULT, DateFormat.DEFAULT, malaysianLocale);
// This step is crucial
TimeZone malaysianTimeZone= TimeZone.getTimeZone("Asia/Kuala_Lumpur");
defaultMalaysianFormatter.setTimeZone(malaysianTimeZone);
try {
format.setTimeZone(malaysianTimeZone);
Date a = format.parse("01/01/1901");
String t = defaultMalaysianFormatter.format(a);
System.out.println(t);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Example java output:
01 Januari 1901 12:08:39 AM
In Oracle Database TO_date function is not working in the same fashion, we believe that Oracle database doesn’t consider the time zone and for that reason it is not retrieving the correct values when send via SQL query.
Oracle Sql Source:
ALTER SESSION SET TIME_ZONE='Asia/Kuala_Lumpur';
select to_date('19010101 00:00:00','YYYYMMDD HH24:MI:SS') from dual;
Example Oracle output:
01-JAN-01 00:00:00
This issues are specific for Malaysia Time zone and for 1901 01/01
Why Java and Oracle database are behaving in different fashion?
Too long for a comment:
A DATE data type does not have a location or time zone. If you want that then you need to use a TIMESTAMP WITH TIME ZONE data type:
ALTER SESSION SET TIME_ZONE='Asia/Kuala_Lumpur';
SELECT FROM_TZ(
CAST(
DATE '1901-01-01' + INTERVAL '08:39' MINUTE TO SECOND
AS TIMESTAMP
),
'Asia/Kuala_Lumpur'
)
FROM DUAL;
Outputs:
1901-01-01 00.09.04.000000000 ASIA/KUALA_LUMPUR
Specifying any value between 1900-01-01 00:00:00 and 1900-01-01 00:08:38 will give ORA-01878: specified field not found in datetime or interval as Oracle knows it is an invalid date/time/time zone combination.
Why the output is 00:09:04 and not 00:08:39 is another question...
You can also use an ANSI timestamp literal:
SELECT TIMESTAMP '1901-01-01 00:08:39 Asia/Kuala_Lumpur' FROM DUAL;

Oracle Timestamp to BST time conversion

I know that there are tons of different tutorials on time conversion, but this one got me very confused. My task is to read UTC DATE from Oracle DB and convert it into BST time (in a more human readable format).
Facts:
Field in the DB is of DATE type.
When i perform SELECT query it returns 2011-07-12 15:26:07 result.
I'm located in Poland, hence in July the TimeZone here is UTC+2
What's happening:
On the Java side I'm using "classical" JDBC connection to the DB.
When I perform Timestamp timestampDate = resultSet.getTimestamp(COLUMN_NAME) I get the result ... but ...
System.out.println(timestampDate) prints to the console 2011-07-12 15:26:07.0 (which is similar to what I see in the DB tool.
System.out.println(timestampDate.getTime()); prints to the console 1310477167000 (which is wondering, because according to the ms to date converter i found online, it's basically 2011-07-12 13:26:07.0 (2h earlier - which somehow might be related to Polish timezone on that date)
When I perform conversion according to this code:
ukDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ukDateFormatter.setTimeZone(TimeZone.getTimeZone("BST"));
return ukDateFormatter.format(timestampDate.getTime());
I get 2011-07-12 19:26:07 which I can't really explain.
I was also trying this
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(timestampDate);
calendar.setTimeZone(TimeZone.getTimeZone("BST"));
return ukDateFormatter.format(calendar.getTime());
with the same result.
Question
How to properly read DATE from Oracle DB in "timezone agnostic" format and convert it into BST?
Here's a way of doing it in the database side:
with dates as (select to_date('01/07/2016 10:39:29', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select to_date('01/02/2016 09:18:41', 'dd/mm/yyyy hh24:mi:ss') dt from dual)
select dt,
cast(dt AS TIMESTAMP) utc_dt_ts,
from_tz(cast(dt AS TIMESTAMP), 'UTC') AT time zone 'Europe/London' dt_as_ts_bst,
cast(from_tz(cast(dt AS TIMESTAMP), 'UTC') AT time zone 'Europe/London' AS DATE) dt_at_bst
from dates;
DT UTC_DT_TS DT_AS_TS_BST DT_AT_BST
------------------- ------------------------------------------------- ------------------------------------------------- -------------------
01/07/2016 10:39:29 01-JUL-16 10.39.29.000000 01-JUL-16 11.39.29.000000 EUROPE/LONDON 01/07/2016 11:39:29
01/02/2016 09:18:41 01-FEB-16 09.18.41.000000 01-FEB-16 09.18.41.000000 EUROPE/LONDON 01/02/2016 09:18:41
The fourth column (dt_at_bst) is the one that shows how to take the date and turn it into another date at BST. It does this by first casting the date as a timestamp and then telling Oracle to treat it as a timestamp at UTC and to output the timestamp for the 'Europe/London' region. Specifying the region like this (rather than passing a specific +01:00 timezone) means that the resultant timestamp will be daylight savings aware. Specifying the region as a three letter shortcut is not advised since that may represent more than one region - e.g. BST could be British Summer Time or Bering Standard Time; both very different things!
I have assumed that by BST you mean British Summer Time, so I have specified the region for the timestamp to be moved to as Europe/London. You would need to adjust this as applicable, if you need a different timezone.
I have included a winter and a summer date in my sample data to show you the effects of casting it into BST - the summer time is expecting to be changed, and the winter time is not.
Actually it is not about Oracle, but more about Java.
First of all:
When you use
System.out.println(timestampDate)
in output you see already adjusted time to your computer time zone.
It is always adjusted when you use Date (i.e.
Calendar.getTime() or Timestamp.getTime())
Code to play with:
SimpleDateFormat dtFmt = new SimpleDateFormat("HH:mm:ss");
NumberFormat nFmt = NumberFormat.getIntegerInstance();
nFmt.setMinimumIntegerDigits(2);
long currentTimeMs = System.currentTimeMillis();
GregorianCalendar utcCalendar = new GregorianCalendar(
TimeZone.getTimeZone("UTC"));
GregorianCalendar bstCalendar = new GregorianCalendar(
TimeZone.getTimeZone("Europe/London"));
GregorianCalendar localCalendar = new GregorianCalendar();
utcCalendar.setTimeInMillis(currentTimeMs);
bstCalendar.setTimeInMillis(currentTimeMs);
localCalendar.setTimeInMillis(currentTimeMs);
System.out.println("---- milliseconds ----");
System.out.println("Current ms : " + currentTimeMs);
System.out.println("Local Calendar ms: " + localCalendar.getTimeInMillis());
System.out.println("UTC Calendar ms: " + utcCalendar.getTimeInMillis());
System.out.println("BST Calendar ms: " + bstCalendar.getTimeInMillis());
System.out.println("---- SimpleFormat Time ----");
System.out.println("Current Time: "
+ dtFmt.format(new Date(currentTimeMs)));
System.out.println("Local Time: " + dtFmt.format(localCalendar.getTime()));
System.out.println("UTC Time : " + dtFmt.format(utcCalendar.getTime()));
System.out.println("BST Time : " + dtFmt.format(bstCalendar.getTime()));
System.out.println("---- Calendar Zone Time ----");
System.out.println("Local Zone Time: "
+ nFmt.format(localCalendar.get(Calendar.HOUR_OF_DAY)) + ":"
+ nFmt.format(localCalendar.get(Calendar.MINUTE)) + ":"
+ nFmt.format(localCalendar.get(Calendar.SECOND)));
System.out.println("UTC Zone Time : "
+ nFmt.format(utcCalendar.get(Calendar.HOUR_OF_DAY)) + ":"
+ nFmt.format(utcCalendar.get(Calendar.MINUTE)) + ":"
+ nFmt.format(utcCalendar.get(Calendar.SECOND)));
System.out.println("BST Zone Time : "
+ nFmt.format(bstCalendar.get(Calendar.HOUR_OF_DAY)) + ":"
+ nFmt.format(bstCalendar.get(Calendar.MINUTE)) + ":"
+ nFmt.format(bstCalendar.get(Calendar.SECOND)));
}
As you will see each Calendar returns Time fields (HOUR_OF_DAY, MINUTE, SECOND) according to its TimeZone, not what you print or format from Calendar.getTime())
What I did, and it seems to be working for me:
ukDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ukDateFormatter.setTimeZone(TimeZone.getTimeZone("Europe/London"));
and performing:
Timestamp timestampDate = rs.getTimestamp(...);
DateTime dateTime = new
DateTime(timestampDate).withZoneRetainFields(DateTimeZone.UTC);
System.out.println(ukDateFormatter.format(dateTime.getMillis()));
prints:
2011-07-12 16:26:07 from the input 2011-07-12 15:26:07
Why happened here?
What was so problematic here, is that rs.getTimestamp(...) was returning the date from the database "as it is" (since DATE column type doesn't preserve the timezone) implicitly but was adding some information about my local timezone - which I didn't wanted.
Easiest solution was to use joda and create new object, retaining values, but changing timezone to UTC. From that point conversion with SimpleDateFormat is quite straightforward.

TimeZone with Calendar confusing results

I have been working with timezone conversions lately and am quite astonished by the result i get.Basically, i want to convert a date from one timezone into another. below is the code, conversions working fine, but what i have observed while debugging is, the date is not converted unless i call Calendar#get(Calendar.FIELD).
private static void convertTimeZone(String date, String time, TimeZone fromTimezone, TimeZone toTimeZone){
Calendar cal = Calendar.getInstance(fromTimezone);
String[] dateSplit = null;
String[] timeSplit = null;
if(time !=null){
timeSplit = time.split(":");
}
if(date!=null){
dateSplit = date.split("/");
}
if(dateSplit !=null){
cal.set(Calendar.DATE, Integer.parseInt(dateSplit[0]));
cal.set(Calendar.MONTH, Integer.parseInt(dateSplit[1])-1);
cal.set(Calendar.YEAR, Integer.parseInt(dateSplit[2]));
}
if(timeSplit !=null){
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(timeSplit[0]));
cal.set(Calendar.MINUTE, Integer.parseInt(timeSplit[1]));
}
// System.out.println("Time in " + fromTimezone.getDisplayName() + " : " + cal.get(Calendar.DATE) +"/"+ (cal.get(Calendar.MONTH)+1)+"/"+ cal.get(Calendar.YEAR) +" " + ((cal.get(Calendar.HOUR_OF_DAY)<10) ? ("0"+cal.get(Calendar.HOUR_OF_DAY) ): (cal.get(Calendar.HOUR_OF_DAY)))
// +":" + (cal.get(Calendar.MINUTE)<10 ? "0"+cal.get(Calendar.MINUTE) : cal.get(Calendar.MINUTE)) );
cal.setTimeZone(toTimeZone);
System.out.println("Time in " + toTimeZone.getDisplayName() + " : " + cal.get(Calendar.DATE) +"/"+ (cal.get(Calendar.MONTH)+1)+"/"+ cal.get(Calendar.YEAR) +" " + ((cal.get(Calendar.HOUR_OF_DAY)<10) ? ("0"+cal.get(Calendar.HOUR_OF_DAY) ): (cal.get(Calendar.HOUR_OF_DAY)))
+":" + (cal.get(Calendar.MINUTE)<10 ? "0"+cal.get(Calendar.MINUTE) : cal.get(Calendar.MINUTE)) );
}
public static void main(String[] args) throws ParseException {
convertTimeZone("23/04/2013", "23:00", TimeZone.getTimeZone("EST5EDT"), TimeZone.getTimeZone("GB"));
}
Expected Output: Time in Greenwich Mean Time : 24/4/2013 04:00
Output i got when i comment sysout 1: Time in Greenwich Mean Time : 23/4/2013 23:00
If i un-comment sysout1 i get the expected valid output.
Any help is appreciated
The internal representation of the given date is not evaluated until really needed, that is until you try to access it by those getters. However the best way of parsing dates is through SimpleDateFormat.
EDIT (added for summarize the comments below and to better clarify my answer).
Calendar works this way for better efficiency: instead of recalculate everithing each time you call a setter, it waits until you call a getter.
Calendar should be used mainly for date calculations (see add() and roll()), but you are using it for parsing and formatting: these tasks are better accomplished with SimpleDateFormat, that's why I say that your usage of Calendar is not elegant.
See this example:
private static void convertTimeZone(String date, String time,
TimeZone fromTimezone, TimeZone toTimeZone) throws ParseException {
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm");
df.setTimeZone(fromTimezone);
Date d = df.parse(date + " " + time);
df.setTimeZone(toTimeZone);
System.out.println("Time in " + toTimeZone.getDisplayName() + " : " +
df.format(d));
}
I have reimplemented your method using SimpleDateFormat only. My method is smaller, there is no splitting logic (it's hidden in parse()), and also the output is handled in a simpler way. Furthermore the date format is expressed in a compact and standard way that can be easily internationalized using a ResourceBundle.
Also note that the timezone conversion is just a formatting task: the internal representation of the parsed date does not change.
The answer is partly explained in a commented section in setTimeZone():
Consider the sequence of calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
Is cal set to 1 o'clock EST or 1 o'clock PST? Answer: PST. More
generally, a call to setTimeZone() affects calls to set() BEFORE AND
AFTER it up to the next call to complete().
In other words, the sequence
Set Calendar time
Change TimeZone
is interpreted to mean "Use this time in this new time zone", while the sequence
Set Calendar time
Get the time (or some part of it)
Change Time Zone
will be interpreted as "Use this time in the old time zone, then change it".
So, in your case, to get the behavior you are hoping for, you will need to call get(), or any other method that internally calls complete() inside the Calendar, before you change the time zone.
Are you restricted to using TimeZone and Calendar? If not I suggest using the excellent Library JodaTime which makes handling time zones much easier.
Your example would then look like this:
public static void convertTimeZoneJoda(String date, String time, DateTimeZone fromTimezone, DateTimeZone toTimeZone) {
DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyyHH:mm").withZone(fromTimezone);
DateTime dt = dtf.parseDateTime(date+time).withZone(toTimeZone);
System.out.println("Time in " + toTimeZone.getID() + " : " + dt.toString());
}
public static void main(String[] args) {
convertTimeZoneJoda("23/04/2013", "23:00", DateTimeZone.forID("EST5EDT"), DateTimeZone.forID("GMT"));
}
JodaTime also allows for convenient conversation between TimeZone and DateTimeZone.
To add to #Pino's answer, the reason why get() doesn't return an updated time is because setTimeZone() simply doesn't update the fields, just sets areAllFieldsSet to false, which is useless since get() doesn't check for it. If you ask me, this is very poorly coded from SUN's part. Here is the competent code from Calendar:
setTimeZone():
public void setTimeZone(TimeZone value){
zone = value;
sharedZone = false;
areAllFieldsSet = areFieldsSet = false;
}
get():
protected final int internalGet(int field){
return fields[field];
}
This code works for me to convert to UTC:
create a Calendar Object with UTC time zone
Calendar utcTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
set the point in time in the UTC Calendar object from the "any time zone" Calendar object
utcTime.setTimeInMillis(myCalendarObjectInSomeOtherTimeZone.getTimeInMillis());
utcTime will now contain the same point in time as myCalendarObjectInSomeOtherTimeZone converted to UTC.

Java getTimeZone() behaving differently for different kind of inputs

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

Categories