I use getTime() method of Date class in java.
when I perform it in my local it return an value different with when I perform it in other pc whereas date value is same.
start.getTime()
The Date object is effectively just a container for milliseconds-since-the-Epoch values (milliseconds since Jan 1st 1970 at midnight UTC), which is the value you get from getTime. You've said "...whereas date value is same..." which suggests you're looking at other aspects of the Date object, like getHours and such, but note all those "Deprecated" notices on those methods. They're there for a reason.
If you use something that's designed to handle timezones well (the new java.time stuff; at a pinch the old java.util.Calendar, but "well" is stretching it), you could easily have a Date object in one timezone which those mechanisms say is (for instance) 2017-02-01 at 11:06, and another in another timezone which they also say is 2017-02-01 at 11:06, but get different values from getTime. That's because of the difference in timezones.
See javadoc for Date.getTime():
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object
Note that the String representation of the Date instance (the String returned by toString()) may differ depending on locale and time zone settings, but the getTime() method will always behave as described above.
Related
This question already has answers here:
Get GMT Time in Java
(12 answers)
How to Parse Date from GMT TimeZone to IST TimeZone and Vice Versa in android
(4 answers)
Getting the current time millis from device and converting it into a new date with different timezone [duplicate]
(2 answers)
How to set time zone of a java.util.Date?
(12 answers)
Closed 3 years ago.
Java 8 here, I have the following code:
public class PossibleBug {
public static void main(String[] args) {
new PossibleBug().run();
}
public void run() {
buildDate("20181205");
}
public Date buildDate(final String yyyyMmDd) throws ParseException {
TimeZone expectedTz = TimeZone.getTimeZone("America/New_York");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(expectedTz);
TimeZone actualTz = sdf.getTimeZone();
Date answer = sdf.parse(yyyyMmDd);
return answer;
}
}
So pretty basic stuff:
create a SimpleDateFormat and set its timezone to EST
Use the SDF to parse a date string
Result should be a date in EST as well
However at runtime, look at the debugger results:
How is this possible?!?! sdf.parse(yyyyMmDd) is returning a date formatted in GMT. Is there something I'm missing on my end or is this a bug in SimpleDateFormat?
I am able to invoke buildDate and run it from inside a different class and it seems to work fine:
Date stores no timezone. It's essentially just a wrapper around a long, storing millis after epoch.
When you print it (or when your debugger invokes the toString() method to get a string representation to display), your JVM's default timezone is used, irrespective of how it was created.
Date, despite the name, doesn't model a date: it's an instant in time.
Given that your input is "20181205", don't use Date: use classes from java.time like java.time.LocalDate.
If you take a look at the Java-Doc for SimpleDateFormat.parse(), you can see that the TimeZone might be overwritten:
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.
The documentation says: "This parsing operation uses the calendar to produce a Date. All of the calendar's date-time fields are cleared before parsing, and the calendar's default values of the date-time fields are used for any missing date-time information. For example, the year value of the parsed Date is 1970 with GregorianCalendar if no year value is given from the parsing operation. 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."
In short, SimpleDateFormat is a formatter/parser, not a utility for performing time zone conversions. If there's no TZ in the string you are parsing, you get the default value from Calendar.
Consider what would happen if you called setTimeZone, then parsed a string that actually contained a time zone itself? What would you expect to happen?
Also, note that Date doesn't contain a time zone. It's specifically defined as being the number of milliseconds since January 1, 1970, 00:00 UTC. Library functions apply a time zone when needed (like when converting to a String) and if you don't specify one, you'll get the default time zone. You see GMT because your default time zone is GMT or because your IDE always displays Date objects in GMT, and the person who said he got EST must have is default time zone set to EST.
In your case, you're parsing a string that does not contain a time zone at all. In fact, it doesn't even contain a time. Using Date to handle, uh, dates (I realize this is confusing, I mean dates without times), is likely to lead to mistakes, especially when your default time zone isn't UTC/GMT. I recommend using LocalDate and the LocalDate.parse method.
I am developing a library to store complex data in an Object. One of the field in this object is a date. When I set the date using setter method, it is assumed that the date object is in GMT timezone. Internally, the Date is stored as a long with the number of milliseconds from epoch. In my get() method, I am doing the following :
return new Date(storedDateinMilliseconds);
The problem is that if anyone is calling toString() on the returned object, it uses the default timezone to return the date. Therefore, the returned date does not always match with the date provided in GMT. Is there a way to fix this? so that the user of this implementation will always get the GMT date when they invoke toString()?
I tried the following :
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
But this would modify the default timezone of the application using it.
As Sotirios Delimanolis’ comment said, you are giving a java.util.Date object to the calling programmer. What she does with it is up to her. And it is up to her to understand all the goofy problems that come with that object including its toString method applying the JVM’s current default time zone in generating a string representation of its date-time value.
If you want to return a date-time value with an assigned time zone, then return a different object.
Alternative Date-Time Objects
You have at least three alternatives to returning a java.util.Date object.
java.time
In Java 8 and later, the obvious choice is to use the new java.time framework (Tutorial). Give the calling programmer a ZonedDateTime object which is basically a Instant object plus a ZoneId object.
Tip: When specifying a time zone, use a proper time zone name. Never use the 3-4 letter codes like EST or IST.
Joda-Time
Joda-Time was the inspiration for java.time. This 3rd-party library is excellent, and well-worn from popular use. It supports multiple versions of Java and Android too.
The DateTime class is a moment on the timeline plus a time zone, similar to java.time’s ZonedDateTime.
ISO 8601
A third alternative is to give the calling programmer a string representation of a date-time value. The obvious choice of formats is to use those defined by the ISO 8601 standard. These formats are sensible, well thought-out, and unambiguous.
2015-09-16T18:06:14Z
…or…
2015-09-16T11:06:14-07:00
Both java.time and Joda-Time use these formats by default in parsing and generating strings. The formats are wisely extended by java.time to append the proper name of the time zone in square brackets.
2015-09-16T11:06:14-07:00[America/Los_Angeles]
Never Adjust Default Time Zone
You stated that setting the default time zone affected your entire app. Wrong. It affects all code of all apps in all threads running in that JVM. Worse, it does so immediately during runtime while that other code is running.
Set the default time zone only as a last resort when all other approaches to resolve a date-time problem have been exhausted. This is rare. The usual solution is to:
Use java.time or Joda-Time.
Always specify the desired/expected time zone rather than rely implicitly on the default.
Use UTC in most of your business logic, data storage, and data exchange.
Avoid whenever possible the mess that is java.util.Date/.Calendar.
Search StackOverflow
All of these topics have been discussed many times over on StackOverflow.com. Please search for more information and examples.
AFAIK, you have 2 options:
Option 1. This may sound like an overkill, but you could roll out your own Date object just for this complex class of yours, and overwrite the toString() method. Maybe something like
public class GMTDate extends java.util.Date {
#Override
public String toString() {
//return GMTDate
}
}
Option 2: Keep your date as java.util.Date, but don't expose a public getter for it. Expose instead a public getter that returns your date in GMT format, and maybe a public getter that returns your date as a long (with the number of milliseconds from epoch)
EDIT:
And a 3rd option: AspectJ. You can use aspect oriented programming to intercept calls to the toString() method and return a GMT string date
Relevant Stack Overflow Question: AspectJ: Intercept method execution/call and make it return
I wrote some code today in VB6 which would get me the number of milliseconds since 1/1/1970, so I could then send the value off to a java application which would parse that value like new Date(Long.parse(milliseconds)). I understand that the milliseconds the Date(Long) is looking for is the number of milliseconds since epoch in GMT. The machine I am running on is on CDT here in the US. When I get the toString value of the date parsed from the milliseconds, this is the value I get:
Tue Aug 11 15:40:50 CDT 2015
Is the CDT just there because the local machines timezone is CDT? I just think its a little weird that the constructor for Date would assume that a date derived from the milliseconds since epoch in GMT would implicitly be in the local machines timezone, rather than being offset (in this case) by -5 hours.
Is the CDT just there because the local machines timezone is CDT?
The timezone for display purposes is based on the default time zone.
The millis in the Date is relative to epoch and it doesn't have a time zone of its own.
It is taken since 00:00 1/1/1970 GMT or if you prefer 17:00 12/31/1969 CDT.
would implicitly be in the local machines timezone
The use of the local time zone is for display purposes only. Use another time zone or serialize the Date and send it to a machine in another timezone and it will use the local timezone again.
You're correct it's showing CDT in the toString() because your locale indicates that is the correct timezone for you. The Date object itself doesn't care about timezones and is a glorified wrapper around the Unix epoch in milliseconds. Generally you should use toString() for debugging purposes, and use a date formatter to actually display dates to the user (optionally specifying an explicit timezone instead of the one specified by the user's locale).
The Javadoc for Date.toString() only specifies the format of the string, it doesn't actually say anything about which timezone is used. I wouldn't rely on toString() always returning the default Locale in every implementation of Java.
You can use a custom representation of a date by using the correct format
Read this post, it might help you
Change date format in a Java string
The number of milliseconds since epoch began is NOT in the timezone known as UTC. It is not in any time zone. The epoch value is the same in ALL time zones. That epoch millisecond value is the same in London as it is in New York or San Francisco for that instant in time.
The Date function always uses the current default time zone if you don't set one. So for you, yes, the local machines timezone is CDT. Again, the epoch value in CDT is exactly the same as everywhere else on the planet, so there is no real reason to pick UTC when your machine thinks it is in central time.
I'm struggling from a couple of hours to understand what's going on with the TimeStamps in my code.
Both the Oracle DB and the java application are in PDT
Select from DB:
select id, time_stamp from some_Table where id = '3de392d69c69434eb907f1c0d2802bf0';
3de392d69c69434eb907f1c0d2802bf0 09-DEC-2014 12.45.41.354000000 PM
select id, time_stamp at time zone 'UTC' from some_Table where id = '3de392d69c69434eb907f1c0d2802bf0';
3de392d69c69434eb907f1c0d2802bf0 09-DEC-2014 12.45.41.354000000 PM
The field in the Oracle database is TimeStamp, hence no timezone information is stored.
Timestamp dbTimeStamp = dbRecord.getLastLoginTime();
System.out.println(dbTimeStamp.toString()); // 2014-12-09 12:16:50.365
System.out.println(dbTimeStamp.getTime()); // 1418156210365 --> Tue Dec 09 2014 20:16:50 UTC?
According to the documentation, getTime()
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
represented by this Timestamp object.
Why are 8 hours (PDT - UTC) of extra time added to the response of getTime() ?
TimeStamp.toString() internally uses Date.getHours() whose javadoc states:
Returns the hour represented by this Date object. The
returned value is a number (0 through 23)
representing the hour within the day that contains or begins
with the instant in time represented by this Date
object, as interpreted in the local time zone.
So toString is using your local time zone whereas getDate doesn't.
These two are consistent with each other. The getTime() method gives you the absolute millicecond value, which you chose to interpret in UTC. The toString() method gives you that same millisecond value interpreted in the associated timezone. So it is not getTime() which is adding the time, but toString() which is subtracting it. This is not really documented, but that is how it behaves.
The most important takeaway should be not to rely on Timestamp.toString because it is misleading. The whole timezone mechanism within Date (and Timestamp is a subclass) has been deprecated a long time ago. Instead use just the getTime() value and have it formatted by other APIs, such as Java 8 Date/Time API.
Update
Apparently, the toString() output is actually the correct one, which for me is just one small addition to the thick catalog of all things wrong with Java's date/time handling. You probably receive the timestamp from the database as a formatted string, not the millisecond value. JDBC then parses that into a millisecond value according to the timezone associated with the Timestamp instance, such that the output of toString() matches what was returned by the database, and the actual millisecond value being secondary.
Thanks to the answers above and the references on SO. This answer finally helped me in understanding where I was going wrong in understanding TimeStamps.
Qouting from the linked answer
Note: Timestamp.valueOf("2010-10-23 12:05:16"); means "create a timestamp with the given time in the default timezone".
TimeStamp represents an instant of time. By default, that instant of time in the current Timezone.
The timestamps being written to the DB were UTC instants. i.e. current UTC time was being written. Hence, no matter where the application was deployed, the value being written to the DB was the same TimeStamp.
However, while reading the TimeStamp generated assumes the default TimeZone as read from the deployment JVM. Hence, the value read was the instant in PST timezone. The actual UTC Value being 8 hours more than the PST time. Hence, the difference.
TimeStamp.getTime() returns milliseconds from UTC.
TimeStamp.toString() returns the representation of time in the current TimeZone. Thanks #marko-topolnik
To take an example,
Value in the DB : 2014-12-09 12:16:50.365
When this value is read in a TimeStamp, the instant is 2014-12-09 12:16:50.365 in PST
Convert this to UTC, it would be 2014-12-09 20:16:50
Hence, the solution was to add the TimeZone offset to the values read from the database to get the instants as UTC TimeStamps.
The key here was "TimeStamp is a time instant without TimeZone information. The timestamp is assumed to be relative to the default system TimeZone." - It took me a really long while to comprehend this.
One of my project implemented the below method, i am looking into the one of the date issue and trying to understand below method which converts given date to GMT, but confused with the output.
Input Date value : 2010-11-29 04:00:00.0
Output Date value : Sun Nov 28 20:00:00 PST 2010
My machine is running in pacific timezone(PST), if it is returning GMT, i would expect "2010-11-29 11:00:00.0", can you please clarify what is the purpose of getRawOffset() method and why it is returning that output?
public static Date convertToGMT(Date date) {
TimeZone jvmTimeZone = TimeZone.getDefault();
long newTime = date.getTime() + jvmTimeZone.getRawOffset();
if (jvmTimeZone.inDaylightTime(date)) {
newTime = newTime + jvmTimeZone.getDSTSavings();
}
return new Date(newTime);
}
PST is UTC-8, therefore getRawOffset() returns a negative value:
2010-11-29 04:00:00.0 + (-8 hours) = 2010-11-28 20:00:00.0
However, the whole thing you are trying to do is wrong.
Date represents an instant, a point on the timeline that's not associated with any timezone. Therefore it makes no sense to convert Date from one timezone to another. The only thing you can do with Date is to convert it to local date/time in certain timezone, and vice versa.
Also I'd suggest you to use Joda Time too. Jode Time makes distinction between an instant (DateTime) and a local representation of that instant (LocalDateTime) more clear.
The code is just crap because a java.util.Date is always GMT. It is never a local timestamp so trying to convert it from an imaginary local timestamp to GMT is conceptual nonsense.
The original intention was probably to misuse a Date as a kind of local timestamp (in contradiction to its specification) that is as thin wrapper around local time millis. Remember following relation: [UTC-millis] + [offset-millis] = [local-millis] I would just have used a long primitive for this calculation, not j.u.Date.
So you can see many inconsistencies in the code. The newTime variable appears to be a kind of local millis but is wrapped then as j.u.Date and returned result of a method which pretends to convert to GMT (more chaos is hardly possible).
Edit 8 years later when we have now got the java.time-package.
An instance of java.util.Date can be converted to a java.time.Instant. New conversion methods had been added to java.util.Date for this purpose. And we should all know that an instant is related to GMT, and nothing else. So will someone try to tell us that following code makes any sense?
public static Instant convertToGMTNew(Instant instant) {
java.util.Date date = java.util.Date.from(instant);
return convertToGMTOld(date).toInstant(); // using the method above
}
Not really. It is the same error. The new changed!!! instant would indeed be based on a fake calculation. Instant and java.util.Date have no conversion methods involving any zone calculations for a good reason. Both are just related to GMT and not to any "local" instants.