This question already has answers here:
How to set time zone of a java.util.Date?
(12 answers)
Closed 5 years ago.
I have a problem whereby the Calendar.getTime() method changes the timezone (probably to be in line with the JVM).
Calendar cal = javax.xml.bind.DatatypeConverter.parseDateTime("2017-10-20T07:10:08.123458Z");
Date datrFromCal = cal.getTime();//Adds two hours(GMT+2:00)
Is there any way to stop this movement from GMT+0 to GMT+2 when calling cal.getTime()?
P.s. We use Java 7 at my company.
Another thing related to this is the support for microseconds. I have read a lot about Java 7 and below not supporting microSeconds (when parsing a String), but is there any suggestions to get around this?
It's not the Date that has the timezone. Dates are simply a number of milliseconds since the "epoch" (1 Jan 1970 GMT). They do not contain timezone information. You only see time zones when you format a date for display. By default, it uses the timezone for your locale. You can use SimpleDateFormat to print a date with a different Locale or TimeZone.
Make sure your Calendar instance has the right TimeZone (e.g. you might have to explicitly set it: cal.setTimeZone(TimeZone.getTimeZone("GMT"));).
If I were you, I'd switch to the Joda time library or the ThreeTen Backport and use the far better designed java.time. The built-in java.util.Date/Calendar classes are a nightmare to work with. They are poorly designed and mutable, which means you can't trust them as value objects to be passed around.
Though i agree with #ELEVATE, i have to add that the iso 8601 date format uses a time zone.
We can see that you are effectively setting the timezone with the 'Z' indicator but not specify it. Therefore, the calendar is built using the your local time zone but with the time defined as UTC (or GMT if you prefer, therefore as GMT+2h00 in your case).
If, however, you remove the 'Z' indicator, you'll the time set with your timezone as it is.
See https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators for instance
Related
I should preface this with I use Apache Spark, which uses java.sql.Date, in case anyone suggests I should use dates from java.time. The example below is in Scala.
The API that I use (which is deprecated) to get the month for a date is as follows:
val date: java.sql.Date = ???
val month = date.getMonth()
However if I look at how it appears I should do this based on the deprecation, the above code would be re-written as follows:
val date: java.sql.Date = ???
val cal = Calendar.getInstance()
cal.setTime(date)
cal.get(Calendar.MONTH)
The simplicity and readability of the code is significantly different, and the date being a side effect on the calendar is not terribly nice from a functional programming point of view. Can someone explain why they think this change was made?
Prior to JDK 1.1, the class Date had two additional functions. It
allowed the interpretation of dates as year, month, day, hour, minute,
and second values. It also allowed the formatting and parsing of date
strings. Unfortunately, the API for these functions was not amenable
to internationalization. As of JDK 1.1, the Calendar class should be
used to convert between dates and time fields and the DateFormat class
should be used to format and parse date strings. The corresponding
methods in Date are deprecated.
The JavaDoc explains. Internationalization.
"in case anyone suggests I should use dates from java.time"
There is nothing to stop you from converting to java.time classes as soon as possible, performing whatever calculations/modifications you need and, if you need to re-insert, converting back to java.sql.Date again.
val date: java.sql.Date = ???
val month = date.toLocalDate().getMonthValue()
You said it yourself, and I still think: You should use java.time, the modern Java date and time API. When you get an old-fashioned java.sql.Date from a legacy API not yet upgraded to java.time, convert it to a modern LocalDate and enjoy the natural code writing with java.time.
Why were getMonth() and the other getXxx methods deprecated?
While Michael has already answered the question with respect to java.util.Date, I have something to add when it comes to java.sql.Date. For this class the situation is quite a bit worse than what Michael reported.
What is left undeprecated (apprecated?) of java.util.Date after the deprecations is that a Date is a point in time. java.sql.Date on the other hand was never meant to be a point in time. One way to illustrate this fact is that its toInstant method — which should convert it to an Instant, a point in time — unconditionally throws an UnsupportedOperationException. A java.sql.Date was meant to be a calendar date to be used with an SQL database and its date datatype, which in most cases is also a date, defined by year, month and day of month. Since a Date is no longer year, month and day of month, they have virtually deprecated everything that a java.sql.Date was supposed to be. And they didn’t give us a replacement until with JDBC 4.2 we can exchange LocalDate objects with SQL databases.
The observations that lead to deprecation have got very practical consequences. Let’s try this (in Java because it is what I can write):
void foo(java.sql.Date sqlDate) {
System.out.println(sqlDate);
TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("Pacific/Samoa")));
System.out.println(sqlDate.getMonth());
}
In one call the method printed:
2020-11-02
9
So we had the 2nd day of the 11th month, and month prints as 9? There are two things going on:
Confusingly the month number that getMonth() returns is 0-based, so 9 means October.
The Date is internally represented as a count of milliseconds since the epoch to the start of the day in the default time zone of the JVM. 2020-11-02 00:00:00 in my original time zone (set to Pacific/Kiritimati for this demonstration) is the same point in time as 2020-10-31 23:00:00 in Samoa. Therefore we get October.
You don’t have to change the time zone yourself for this to happen. Situations where it can happen include:
The default time zone of the JVM can be changed from any part of your program and from any other program running in the same JVM.
The date may be serialized in a program running in one JVM and deserialized in a different JVM with a different time zone setting.
BTW the first snippet I presented at the top often won’t help against unexpected results in these situations. If things go off track before you convert from java.sql.Date to LocalDate, the conversion too will give you the wrong date. If you can make it, convert to LocalDate before anyone messes with the JVM time zone setting and be on the safe side.
I'm aware that Java 8 has a much improved date and time library based on Joda Time, but I'm very curious about the decisions made in the old libraries. I haven't found any good explanation about the java.util.Date constructor deprecation rationale (the closest question I've found is this: Difference between new Date() and Calendar date but it doesn't ask about deprecated methods/constructors and doesn't have an accepted answer).
The constructor java.util.Date(year, month, day) is considered deprecated and we should use new GregorianCalendar(year + 1900, month, date). If we call getTime() (which returns a Date...) on the Calendar instance, what have we gained, other than avoiding a deprecated constructor? Even java.sql.Date.toLocalDate uses some deprecated methods internally.
I have a codebase littered with this pattern (new GregorianCalendar followed by getTime) just to avoid the deprecated methods of java.util.Date (I need java.util.Date and java.sql.Date in JPA and JDBC), but I'm not sure what's the point or what was the point back then (*).
(*) Nowadays I can finally change them all to LocalDate because that's what I really needed anyway — saving what the user typed in without any timezone conversions.
See second paragraph in the javadoc of java.util.Date:
Prior to JDK 1.1, the class Date had two additional functions. It allowed the interpretation of dates as year, month, day, hour, minute, and second values. It also allowed the formatting and parsing of date strings. Unfortunately, the API for these functions was not amenable to internationalization. As of JDK 1.1, the Calendar class should be used to convert between dates and time fields and the DateFormat class should be used to format and parse date strings. The corresponding methods in Date are deprecated.
So, to answer your question "What have we gained?", the answer is "support for internationalization":
Ability to specify time zone (using Calendar).
Ability to use non-Gregorian calendar (using Calendar).
Ability to use localized formatting and parsing of date strings (using DateFormat).
The old libraries permitted the construction of java.util.Date items from entries in a Gregorian calendar, by passing in the year, month, day, etc items.
This was problematic for a number of reasons. First, the Gregorian calendar system is a hybrid calendar system that transitioned from the Julian calendar system. This transition included the need to "skip" dates to realign the Julian calendar system with the seasons. So, there are missing days. Surprisingly, the java.util.Date does a decent job of capturing this behavior, except:
The dates to be skipped are dependent on when the transition was adopted, which mostly maps out to be Locale dependent.
The strong binding to the Gregorian Calendar of the core java.util.Date object means that implementing other calendar systems is problematic, as you need to implement them on top of a Gregorian System.
The date being tied to Locale and TimeZone also meant that you had to adjust the platform's Locale and TimeZone to get the appropriate Date behavior you wished, often adjusting it back for out-of local date computations.
The new calendar system attempts to avoid this by:
Having an API that passes in a field to set with the value, preventing direct binding of the calendar fields to the API methods.
Having an API that permits subclassing a Calendar such that one could implement calendars with vastly different definitions of months, days, and years (think lunar calendars, Jewish calendars, Arabic Calendars, Chinese Calendars, etc).
Going forward, one should use java.util.Date only as a thin wrapper around a timestamp, and that's more to have compatibility with the older APIs. All Date manipulations should be done in the appropriate Calendar instance.
This question already has answers here:
Parsing ISO 8601 date format like 2015-06-27T13:16:37.363Z in Java [duplicate]
(2 answers)
Closed 4 years ago.
I need to transform a Twitter timestampe into a Java Date object,
here is an example of a value of a Timestampe: "2015-01-06T21:07:00Z"
Can you please give me sample of java code (standard Java) doing the job?
Thank you
I recommend you take advantage of the new Date/Time API introduced in Java 8, specifically Instant as follows:
Instant.parse("2015-01-06T21:07:00Z");
You can then perform a multitude of operations, but keep in mind that the object is immutable, so any changes to the instance (that aren't chained) must be stored in a separate variable.
Actually it is ISO 8601 format for UTC time zone.
It conforms with XML DateTime format as well.
So, to get actual java.util.Calendar or java.util.Date out of it you simply can use available in JDK
Calendar twitterCalendar = javax.xml.bind.DatatypeConverter.parseDateTime("2015-01-06T21:07:00Z");
Date twitterDate = javax.xml.bind.DatatypeConverter.parseDateTime("2015-01-06T21:07:00Z").getTime();
Just be aware: java.util.Date has no Time Zone information in it. Your string is in UTC, so if you try to print value of twitterDate you will see Date/Time in TimeZone of your computer/server. Still actual value of twitterDate stays the same
millisecond value that is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian).
This question already has answers here:
Closed 10 years ago.
I need to get real world date and time in Java. I use:
Date date = new Date();
But I'm not sure that it is not just system time. I don't need to be dependent on PC local date and time.
If it is so, then is there any way to abstract from it? I mean I need correct time and date. If today is the 1st of May, 2012 and user changed (maybe there was a system error) it to the 1st of December 2000, it shouldn't affect business logic. So is there any alternative to achieve this?
Date only represents an instant in time, in milliseconds since the Unix epoch of January 1st 1970 UTC (modulo leap seconds). It has no concept of a time zone in its data. However, if you use the toString method it will always convert that UTC instant to a local date/time using the system time zone. That confuses a lot of users, making them think that Date contains a time zone - it's just an illusion.
Likewise Date doesn't have any concept of a calendar system (Gregorian, Julian etc) or a "format". Basically it's just a long :)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Timezone conversion
I have a date in UTC, how to convert it to other timezone?
java.util.Date
Despite what the output of Date.toString() suggests, Date instances are not timezone aware. They simply represent a point in time, irrespective to the timezone. So if you have a Date instance, there is nothing more you need to do. And what if you have time in one time zone and you want to know what is the time in other time zone? You need
java.util.Calendar
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Asia/Tokyo"))
cal.set(Calendar.HOUR_OF_DAY, 15) //15:00 in Tokyo
cal.set(Calendar.MONTH, Calendar.NOVEMBER)
cal.setTimeZone(TimeZone.getTimeZone("Australia/Melbourne"))
cal.get(Calendar.HOUR_OF_DAY) //17:00 in Melbourne
Note that after changing the time zone the date (point in time) didn't changed. Only the representation (current hour in this particular time zone). Also note that November is important there. If we change the month to July suddenly the hour in Melbourne changes to 16:00. That's because Tokyo does not observe DST, while Melbourne does.
java.text.DateFormat
There is another catch in Java with time zones. When you are trying to format a date you need to specify time zone explicitly:
DateFormat format = DateFormat.getTimeInstance
format.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"))
Otherwise DateFormat always uses current computer's time zone which is often inappropriate:
format.format(cal.getTime())
Since format() method does not allow Calendar instances (even though it accepts Object as a parameter - sic!) you have to call Calendar.getTime() - which returns Date. And as being said previously - Date instances are not aware of time zones, hence the Tokyo and Melbourne settings are lost.
You can try Joda-Time library. They have 2 functions called withZone() and withZoneRetainFields() to perform timezone calculations.