Problem in converting IST to GMT.
DateFormat df = new SimpleDateFormat("HH:mm:ss z");
String input = "05:30:00 IST";
Date d = df.parse(input);
Calendar c = Calendar.getInstance();
c.setTime(d);
System.out.println(c.getTime());
getting Thu Jan 01 03:30:00 GMT 1970 as output instead of Thu Jan 01 00:00:00 GMT 1970
You should be wary of using three-letter abbreviations of timezones because they are ambiguous. In this case, IST could refer to:
Indian Standard Time (UTC+0530)
Israel Standard Time (UTC+02)
Irish Standard Time (UTC+01)
Wikipedia lists some common timezone abbreviations; examples of other ambiguous common abbreviations are:
AM(S)T
AST
BST
CDT
CST
ECT
FKST
GST
MST
It is better to use either a UTC offset (e.g. +0530 for Indian Standard Time) or a uniquely-defined timezone identifier (e.g. Asia/Calcutta)
There are a number of things wrong with what you seem to be trying to do here.
You are trying to use a java.util.Date object to contain just a time-of-day (hours, minutes, seconds). A java.util.Date object is not suitable for that purpose. A java.util.Date object is really a timestamp - it represents an "absolute" moment in time, counted as a number of milliseconds since 01-01-1970, 00:00:00 GMT.
A java.util.Date object does not contain timezone information. You cannot convert a Date object from one timezone to another timezone, because the Date object simply does not contain information about a timezone.
Converting a time-of-day from one timezone to another cannot be done if you only know the hours, minutes and seconds. The result also depends on the date (year, month, day) - the results can be influenced by daylight savings transitions. So it's not possible to convert a time-of-day from one timezone to another if you don't know the date.
If you use the Java 8 java.time API, then it's easy; use ZonedDateTime, which does contain information about the timezone.
// Assuming that with "IST" you mean India Standard Time
ZonedDateTime input = ZonedDateTime.of(2015, 3, 23, 5, 30, 0, 0, ZoneId.of("Asia/Calcutta"));
System.out.println(input);
ZonedDateTime output = input.withZoneSameInstant(ZoneId.of("GMT"));
System.out.println(output);
If you want to use the old java.util.Date and java.util.Calendar API, then you set the timezone on the DateFormat object that you use to display the date - not on the Date object itself:
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
cal.set(2015, Calendar.MARCH, 23, 5, 30, 0);
Date input = cal.getTime();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
System.out.println(df.format(input));
df.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(df.format(input));
Related
I am confused with Timezone conversions in Java. I have a few cases which I will list out below.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// sdf.setTimeZone(TimeZone.getTimeZone("Asia/kolkata"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1); //. O/P - Sun Jan 31 00:00:00 IST 2021
Now lets uncomment the Timezone part and see the time difference
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/kolkata"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1); // O/P - Sun Jan 31 05:30:00 IST 2021
Now lets set the TimeZone to IST and see the time difference
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("IST"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1); // O/P - Sun Jan 31 00:00:00 IST 2021
Now lets set the TimeZone to UTC and see the time difference
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1); // O/P - Sun Jan 31 05:30:00 IST 2021
Can anybody please explain me why this shift in time is happening (+- 5:30) when I change the Timezone?
For IST and Asia/Kolkata, time should have remain same because they are same Timezone, but why the shift?
Why When using the UTC Timezone, time gets increased by 5:30 hours? What I understand is IST is 5:30 hrs ahead of UTC, so cnverting to UTC should have decreased the time by 5:30 hrs
Why even after converting to UTC, my time displays IST 2021?
I still have confusion here.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1.getTime()); // 1612051200000
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
sdf1.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date2 = sdf1.parse("2021-01-31");
System.out.println(date2.getTime()); // 1612031400000
Why instant of time in UTC is greater than instant of time in Asia/Kolkata ?
Here are some things for you to note:
When a Date is printed, it will be formatted in your computer's local timezone (that's what Date.toString does). Presumably, your computer is in the Asia/Kolkata timezone, so the output is always displayed as a date & time in that timezone.
A Date represents a point in time (i.e. an instant). It is not a tuple of year, month, day, hour, minute, seconds and timezone
Since there are no time in your input string, the time 00:00:00 is used for the time when parsing.
Just a date and a time is not enough to produce a point in time. You also need a timezone to specify a point in time. Since there is no timezone in your input string, the local timezone of your computer is used, or if you have set it, sdf.getTimeZone().
Although a timezone is used in parsing the date, the timezone is not part of the Date object.
Can anybody please explain me why this shift in time is happening (+- 5:30) when I change the Timezone?
When you use the "IST" timezone (first and third code snippet), sdf gets the following pieces of information:
Date: 2021-01-31
Time: 00:00:00
TimeZone: Asia/Kolkata
With these pieces of information, it can produce a point in time, represented by a number of milliseconds since the Java Epoch - 1970-01-01 00:00:00 UTC. This is the Date object. Then you print the Date object, which gets formatted to your local timezone. Your local timezone just so happens to be the same as the one that sdf is provided with, so you see Sun Jan 31 00:00:00 IST 2021.
When you use UTC (second and fourth code snippets), these information are provided to sdf:
Date: 2021-01-31
Time: 00:00:00
TimeZone: UTC
That represents a different point in time than 2021-01-31T00:00:00 in Kolkata. How different? 2021-01-31T00:00:00 in UTC is exactly 5 and a half hours later than 2021-01-31T00:00:00 in Kolkata. Recall that to convert a UTC time to Kolkata, you add 5 and a half hours.
For IST and Asia/Kolkata, time should have remain same because they are same Timezone, but why the shift?
Because you have misspelled Asia/Kolkata. The first "K" in "Kolkata" should be capitalised. Unknown zone IDs are treated as UTC by the TimeZone class. This is why you should move to the new java.time classes. ZoneId throws an exception if you supply it with an unknown zone ID.
Why When using the UTC Timezone, time gets increased by 5:30 hours? What I understand is IST is 5:30 hrs ahead of UTC, so converting to UTC should have decreased the time by 5:30 hrs
You are thinking about formatting dates, not parsing, because remember that the timezone is not part of Date, but part of SimpleDateFormat. Your code does not format Date, only parses them. Without formatting, Dates are always printed in your local timezone.
To see your desired behaviour using SimpleDateFormat, you'd first parse the date string once, and then format it using SimpleDateFormats with different timezones.
Really though, you should change to java.time. Using that API, your zone changing code could be written like so:
ZonedDateTime zdt = LocalDate.parse("2021-01-31")
.atStartOfDay()
.atZone(ZoneId.of("Asia/Kolkata"));
System.out.println(zdt);
ZonedDateTime utcDateTime = zdt.withZoneSameInstant(ZoneId.of("UTC"));
System.out.println(utcDateTime);
// output:
// 2021-01-31T00:00+05:30[Asia/Kolkata]
// 2021-01-30T18:30Z[UTC]
java time
I recommend you use java.time, the modern Java date and time API, for your date work
LocalDate date = LocalDate.parse("2021-01-31");
System.out.println(date);
Output is:
2021-01-31
A LocalDate is a date without time of day and without time zone or UTC offset, so using it frees you completely from all time zone trouble. Furthermore we don’t need any explicit formatter. Your string is in ISO 8601 format, and LocalDate parses the most common ISO 8601 variant as its default. As you can see, it also prints the same ISO 8601 format back when we print it, implicitly calling its toString method.
What went wrong in your code?
The SimpleDateFormat, TimeZone and Date classes that you are using are poorly designed and long outdated. No wonder that their behaviour confuses you.
I am assuming that Asia/Kolkata (or Asia/Colombo or Asia/Calcutta) is the default time zone of your JVM. In your first example the SimpleDateFormat is using your default time zone and is parsing the string into the first moment of the day in that time zone.
In your second example, as Elavya has spotted so well, you have got a lower case k in Asia/kolkata which causes TimeZone not to recognize the intended time zone. And this is where TimeZone excels in bad design: it just tacitly gives you GMT instead. Next the Date class is poorly designed too and still prints the time in the default time zone of the JVM, giving the illusion that the Date object contains a time zone. This has confused very many. The start of the day in GMT is the same point in time as 05:30:00 IST, so this is what you get.
In your third and fourth example, even though the three letter time zone abbreviations are deprecated, IST (contrary to what Eklavya said) is interpreted as Asia/Kolkata and UTC as Etc/UTC. Even though as Eklavya also said, IST is ambiguous.
So in short:
The change happens because the start of the day is a different point in time in different time zones.
Because of your typo in Asia/kolkata. Time zone IDs are case sensitive.
You are not converting to UTC. You are parsing in UTC thereby converting from UTC, and Date.toString() further converts to Asia/Kolkata (IST) as the output also says.
Because the Date object hasn’t got a time zone and because Date.toString() grabs the default time zone of your JVM and uses it for rendering the string to be returned.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
All about java.util.Date
Java doc for getTimeZone
ID - the ID for a TimeZone, either an abbreviation such as "PST", a
full name such as "America/Los_Angeles", or a custom ID such as
"GMT-8:00". Note that the support of abbreviations is for JDK 1.1.x
compatibility only and full names should be used.
TimeZone abbreviation is not supported. So you can't use IST
And in TimeZone Doc for Three-letter time zone IDs
For compatibility with JDK 1.1.x, some other three-letter time zone
IDs (such as "PST", "CTT", "AST") are also supported. However, their
use is deprecated because the same abbreviation is often used for
multiple time zones (for example, "CST" could be U.S. "Central
Standard Time" and "China Standard Time"), and the Java platform can
then only recognize one of them.
Problem is IST abbreviation is used for multiple time zones like Irish Standard Time, Isreal Standrad Time, Indian Standard Time. And you mistyped Asia/Kolkata as Asia/kolkata.
So, the GMT zone will return if the given ID cannot be understood from TimeZone.getTimeZone()
As an addition to the accepted answer, for the last part of your question;
Why instant of time in UTC is greater than instant of time in Asia/Kolkata in below code?
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1.getTime()); // 1612051200000
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
sdf1.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date2 = sdf1.parse("2021-01-31");
System.out.println(date2.getTime()); // 1612031400000
First, you have a point T in time regardless of timezone. In our example T=2021-01-31 00:00:00.
When we set timezone as UTC and print the time using java.util.Date.getTime() method, it will print milliseconds since the Unix epoch, which occurred at midnight January 1st 1970, UTC. So it will print 1612051200000. As you see the epoch and our date has the same timezone which is UTC. So the time is printed directly, no adjustment necessary for timezone.
Now, when we set timezone as Asia/Kolkata, during SimpleDateFormat.parse, timezone information will be added to date. That means +5:30h(19800000ms) will be added to time T. Therefore our time T is increased by 19800000ms. However T must be pointing to the same point in time. How do we fix that? It is fixed on SimpleDateFormat.parse method by subtracting 19800000ms from the time 1612051200000ms so that getTime() method will now show 1612031400000ms so that our actual time T will still show the same point in time(which is 1612051200000ms) because in this date object we have an extra 19800000ms which comes from timezone.
I need to parse a date string with timezone to Date object. The input date string pattern is:
"MM/dd/yyyy hh:mm a z" (eg: 04/30/2018 06:00 PM IST).
I have used below given code. But it returns incorrect date as output.
new SimpleDateFormat("MM/dd/yyyy hh:mm a z").parse("04/30/2018 06:00 PM IST")
Current Output: "Mon Apr 30 09:00:00 PDT 2018".
Expected Output: "Mon Apr 30 05:30:00 PDT 2018.
That's because timezone's abbreviations such as IST are ambiguous. IST is used in India, Israel and Ireland, and SimpleDateFormat assumes some of them as default, in obscure and undocumented ways (AFAIK). Actually, according to javadoc: "support of abbreviations is for JDK 1.1.x compatibility only and full names should be used".
One way to make it work is to arbitrarily choose a timezone and set it in the formatter:
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm a z");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date = sdf.parse("04/30/2018 06:00 PM IST");
Always use names in the format Continent/Region, such as Asia/Kolkata. Those names are IANA's timezones names, and they are not ambiguous, so this make things work.
java.time API
If you're using Java 8 or higher, switch to the java.time API, which is much better. For Java 7 or lower, there's the Threeten Backport with the same classes and functionality.
In this API, you must set a list of all preferred timezones to be used in case of ambiguous names like IST:
// prefered zones
Set<ZoneId> preferredZones = new HashSet<>();
preferredZones.add(ZoneId.of("Asia/Kolkata"));
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date and time
.appendPattern("MM/dd/yyyy hh:mm a ")
// zone (use set of prefered zones)
.appendZoneText(TextStyle.SHORT, preferredZones)
// use English, because different locales can affect timezones names
.toFormatter(Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse("04/30/2018 06:00 PM IST", fmt);
If you still need to use java.util.Date, it's easy to convert:
// Java 8
Date d = Date.from(zdt.toInstant());
// Java 7 (Threenten Backport)
Date d = DateTimeUtils.toDate(zdt.toInstant());
The resultant Date object will not hold any timezone information. See the similar query in this stackoverflow thread
You might be getting the correct date but in your JVM's current timezone.
In case if you are using Java 8, then there's a provision of Date object with timezone. Look at ZonedDateTime, but for this you need a different kind of formatter while parsing (DateTimeFormatter)
Given that my default TimeZone is Europe/Paris:
System.out.println("Current Timezone: " + TimeZone.getDefault());
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
String dateStrIn = "2016-08-01T00:00:00Z";
Date date = dateFormat.parse(dateStrIn);
String dateStrOut = dateFormat.format(date);
System.out.println("Input date String: "+dateStrIn);
System.out.println("Date.toString() "+date);
System.out.println("Output date String: "+dateStrOut);
The output is:
Current Timezone: sun.util.calendar.ZoneInfo[id="Europe/Paris",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=184,lastRule=java.util.SimpleTimeZone[id=Europe/Paris,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
Input date String: 2016-08-01T00:00:00Z
Date.toString() Mon Aug 01 02:00:00 CEST 2016
Output date String: 2016-08-01T02:00:00+02
Now, I repeat the execution but setting a different default TimeZone (UTC):
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
System.out.println("Current Timezone: " + TimeZone.getDefault());
...
And this is the output:
Current Timezone: sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
Input date String: 2016-08-01T00:00:00Z
Date.toString() Mon Aug 01 00:00:00 UTC 2016
Output date String: 2016-08-01T02:00:00+02
Date.toString() has correctly taken into account the TimeZone change. However, the String gotten from dateFormat.format(date); is still showing +02 instead of Z or +00, why?
Using standard Java API, is there any way to force the formatting according to a selected TimeZone?
UPDATE:
Jesper's solution works in almost all cases, but I have come across this one (using Canary Island's summer time zone WEST) in which it doesn't:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss z");
dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Paris"));
System.out.println("Current Timezone: " + TimeZone.getDefault());
String dateStrIn = "2016-08-01T08:00:00 WEST";
Date date = dateFormat.parse(dateStrIn);
String dateStrOut = dateFormat.format(date);
System.out.println("Input date String: "+dateStrIn);
System.out.println("Date.toString() "+date);
System.out.println("Output date String: "+dateStrOut);
Output:
Current Timezone: sun.util.calendar.ZoneInfo[id="Europe/Paris",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=184,lastRule=java.util.SimpleTimeZone[id=Europe/Paris,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
Input date String: 2016-08-01T08:00:00 WEST
Date.toString() Mon Aug 01 09:00:00 CEST 2016
Output date String: 2016-08-01T08:00:00 WEST
You can see that Output date String is still expressed in WEST.
If, for instance, I change the initial dateStrIn to: String dateStrIn = "2016-08-01T08:00:00 GMT";, then the Output date String is expressed in CEST as espected:
Output date String: 2016-08-01T10:00:00 CEST
Could it be a bug?
UPDATE 2:
Another example
Default TimeZone for both Date and SimpleDateFormat: "Europe/Paris"
Input String: "2016-08-01T08:00:00 WET"
Output:
Date.toString() Mon Aug 01 10:00:00 CEST 2016
Output date String: 2016-08-01T09:00:00 WEST
Notice that dateFormat.format(date); has produced a WEST date string. From WET -> WEST when it should be WET -> CEST.
Instead of setting the default time zone, set the time zone on your SimpleDateFormat object:
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
This will make the SimpleDateFormat object format your Date object in the UTC time zone.
If you're using Java 8, consider using the new date and time API in the package java.time instead of the old java.util.Date and java.text.SimpleDateFormat.
You torture yourself by using the troublesome old legacy date-time classes now outmoded by the java.time framework.
tl;dr
ZonedDateTime.ofInstant( Instant.parse( "2016-08-01T00:00:00Z" ) , ZoneId.of( "Europe/Paris" ) )
java.time
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat. The Joda-Time team also advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
Instant
The Z on the end of your input string 2016-08-01T00:00:00Z is short for Zulu and means UTC. Represented in java.time by the Instant class with a resolution up to nanoseconds.
Instant instant = Instant.parse ( "2016-08-01T00:00:00Z" );
ZonedDateTime
Specify a time zone via ZoneId to get a ZonedDateTime.
In the summer, Paris time is two hours ahead of UTC. So the same moment as seen on a clock on the wall in Paris is 2 AM rather than midnight, on same date of August 1st.
ZoneId zoneId_Paris = ZoneId.of ( "Europe/Paris" );
ZonedDateTime zdt_Paris = ZonedDateTime.ofInstant ( instant , zoneId_Paris );
You can adjust into another time zone such as Atlantic/Canary. For this date in the summer, the time is one hour ahead of UTC. Result is 1 AM rather than midnight.
ZoneId zoneId_Canary = ZoneId.of ( "Atlantic/Canary" );
ZonedDateTime zdt_Canary = zdt_Paris.withZoneSameInstant ( zoneId_Canary );
Dump to console.
System.out.println ( "instant: " + instant + " | zdt_Paris: " + zdt_Paris + " | zdt_Canary: " + zdt_Canary );
instant: 2016-08-01T00:00:00Z | zdt_Paris: 2016-08-01T02:00+02:00[Europe/Paris] | zdt_Canary: 2016-08-01T01:00+01:00[Atlantic/Canary]
All three of these objects (UTC, Paris, Canary) represent the very same simultaneous moment in history, the same single point on the timeline. Each is viewed through the lens of a different wall-clock time.
Real Time Zones
Avoid 3-4 letter zone abbreviations such as WET and WEST. These are not real time zones, not standardized, and not even unique(!).
Europe/Paris and Atlantic/Canary are proper time zone names, in the format of continent/region.
The answer to this mystery was on the Javadoc:
DateFormat.parse(String source, ParsePosition pos)
This parsing operation uses the calendar to produce a Date. As a
result, the calendar's date-time fields and the TimeZone value may
have been overwritten, depending on subclass implementations. Any
TimeZone value that has previously been set by a call to setTimeZone
may need to be restored for further operations.
Setting the TimeZone after parsing works it out:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss z");
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Paris"));
System.out.println("Current Timezone: " + TimeZone.getDefault());
String dateStrIn = "2016-08-01T08:00:00 WET";
Date date = dateFormat.parse(dateStrIn);
dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
String dateStrOut = dateFormat.format(date);
System.out.println("Input date String: "+dateStrIn);
System.out.println("Date.toString() "+date);
System.out.println("Output date String: "+dateStrOut);
Right output:
Current Timezone: sun.util.calendar.ZoneInfo[id="Europe/Paris",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=184,lastRule=java.util.SimpleTimeZone[id=Europe/Paris,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
Input date String: 2016-08-01T08:00:00 WET
Date.toString() Mon Aug 01 10:00:00 CEST 2016
Output date String: 2016-08-01T10:00:00 CEST
No, its not a bug.
You have to first understand how Date class works. It is nothing but a wrapper over the number of milliseconds since the epoch, expressed in long. Hence, whichever timezone it may be, the underlying value of the date object remains the same. You can never really change the timezone of a Date class. You can only represent a String format of a date instance using a SimpleDateFormat class. This representation might have different time zones, based on which you are using while creating the SimpleDateFormatobject.
Again, you need to check the toString method of the Date class. It always prints the date with the default time zone.
Edit
You should look at the SimpleDateFormat.parse() definition as well. The JDK says that,
The TimeZone value may be overwritten, depending on the given pattern and the time zone value in text. Any TimeZone value that has previously been set by a call to setTimeZone may need to be restored for further operations.
Why cannot I clear the time from a timestamp this way:
one day == 24 * 3600 * 1000 == 86400000 milliseconds.
long ms = new Date().getTime(); //Mon Sep 03 10:06:59 CEST 2012
Date date = new Date(ms - (ms % 86400000));
how come this is Mon Sep 03 02:00:00 CEST 2012 instead of Mon Sep 03 00:00:00 CEST 2012?
Why cannot I clear time from timestamm this way
You're correctly clearing the time part in UTC. The millisecond values in Date are always relative to January 1st 1970 midnight in UTC. However, you're not displaying it in UTC, because of the way Date.toString() works (it always uses the system local time zone). Note that a Date itself has no concept of a time zone. It's just a number of milliseconds since January 1st 1970 midnight UTC.
The concept of "clearing a time from a timestamp" doesn't really make sense without specifying which time zone you're talking about, as the same timestamp will have different times of day (and even dates) in different time zones.
To be honest, I would suggest using Joda Time for any significant date/time work. Then you can create a LocalDate which is obviously meant to represent "just a date" - and the translation from a Date (or Instant) to a LocalDate will make it easy for you to specify whichever time zone you want to use.
I actually want to compare it to another date not taking into account time of day
To compare dates I suggest using JodaTime which supports this functionality with LocalDate
LocalDate date1 = new LocalDate(); // just the date without a time or time zone
LocalDate date2 = ....
if (date1.compareTo(date2) <=> 0)
Note: this will construct timezone-less LocalDates which is appropriate for the default timezone. As long as you are only talking about the timezone where the default timezone for the machine has been set, this is fine. e.g. say you have a timezone of CEST then this is fine for most of Europe.
Using the built in time functions you can do something like
public static int compareDatesInTimeZone(Date d1, Date d2, TimeZone tz) {
long t1 = d1.getTime();
t1 += tz.getOffset(t1);
long t2 = d2.getTime();
t2 += tz.getOffset(t2);
return Double.compare(t1 / 86400000, t2 / 86400000);
}
Try this...
Calendar c = Calendar.getInstance();
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
String strDate = df.format(c.getTime()));
Now this way you can have the another date, and then compare it....as they are now in String format.
I have a requirement of sending the calendar object with time zone, like Tue Mar 03 13:43:00. I know that Calendar object always return with Tue Mar 03 13:43:00 CST 2009, so how can I create it without the time zone?
You can use the DateFormat class (more specifically the SimpleDateFormat concrete subclass) to format the date however you want. Here is an example:
Calendar cal = Calendar.getInstance();
DateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss");
String dateString = format.format(cal.getTime()));
Prints:
Fri Mar 06 15:50:26
It's not possible to have a Calendar object without a TimeZone. Really, that doesn't make any sense - Calendar seeks to represent "a specific instant in time" - how can you represent an instance in time without knowing what TimeZone the time you are representing is in?
So, there's a few things to consider:
You say you need to pass this Calendar to some other component - does that API care what TimeZone the Calendars are in? Will that API ignore the TimeZone setting, use it to calculate a time difference against it's own local timezone, etc.?
Are you aware that you can easily change the TimeZone of a Calendar instance?
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getDefault()); // returns default TimeZone for your system
cal.setTimeZone(TimeZone.getTimeZone("EST")); // Eastern Standard Time
cal.setTimeZone(TimeZone.getTimeZone("Asia/Kolkota"); // UTC+5:30
Javadocs on Calendar, TimeZone.
You can use a simple Date object using;
Date d = new Date();
Date d2 = calendar.getTime();
Or the even simpler, time in milli-seconds.
long time = System.currentTimeMillis();
To avoid confusion over time zones, I suggest storing and setting all date/times as a standard time zone, such as GMT+0 and then converting the time for display etc as required.
Upon rereading your question and your comments on my other answer, it sounds like the problem is that you want the result to be a Calendar object, not a String. So it isn't a question of formatting the String representation of the Calendar.
In this case, what you are asking is technically impossible: all implementations of the Calendar class exist to represent an internal time, which is stored as the number of milliseconds since the Unix epoch (Jan 1 1970 00:00 GMT). The time "5:00 am" in Boston is different from "5:00 am" in Seattle--they have different internal timestamps.
Your best bet would be to use the same time zone everywhere, and probably GMT makes the most sense for that purpose:
cal.setTimeZone(TimeZone.getTimeZone("GMT+0000"));