Reputation: 3762
I am getting the following exception while trying to convert java.util.Date
to java.time.LocalDate
.
java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: 2014-08-19T05:28:16.768Z of type java.time.Instant
The code is as follow:
public static Date getNearestQuarterStartDate(Date calculateFromDate){
int[] quaterStartMonths={1,4,7,10};
Date startDate=null;
ZonedDateTime d=ZonedDateTime.from(calculateFromDate.toInstant());
int frmDateMonth=d.getMonth().getValue();
Is there something wrong in the way I am using the ZonedDateTime
class?
As per documentation, this should convert a java.util.Date
object to ZonedDateTime
. The date format above is standard Date?
Do I have to fallback on Joda time?
If someone could provide some suggestion, it would be great.
Upvotes: 110
Views: 120021
Reputation: 338171
The Answer by assylias and the Answer by JB Nizet are both correct:
java.util.Date::toInstant
. Instant::atZone
, passing a ZoneId
, resulting in a ZonedDateTime
. But your code example is aimed at quarters. For that, read on.
No need to roll-your-own handling of quarters. Use a class already written and tested.
org.threeten.extra.YearQuarter
The java.time classes are extended by the ThreeTen-Extra project. Among the many handy classes provided in that library you will find Quarter
and YearQuarter
.
First get your ZonedDateTime
.
ZonedId z = ZoneID.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = myJavaUtilDate.toInstant().atZone( z ) ;
Determine the year-quarter for that particular date.
YearQuarter yq = YearQuarter.from( zdt ) ;
Next we need the start date of that quarter.
LocalDate quarterStart = yq.atDay( 1 ) ;
While I do not necessarily recommend doing so, you could use a single line of code rather than implement a method.
LocalDate quarterStart = // Represent a date-only, without time-of-day and without time zone.
YearQuarter // Represent a specific quarter using the ThreeTen-Extra class `org.threeten.extra.YearQuarter`.
.from( // Given a moment, determine its year-quarter.
myJavaUtilDate // Terrible legacy class `java.util.Date` represents a moment in UTC as a count of milliseconds since the epoch of 1970-01-01T00:00:00Z. Avoid using this class if at all possible.
.toInstant() // New method on old class to convert from legacy to modern. `Instant` represents a moment in UTC as a count of nanoseconds since the epoch of 1970-01-01T00:00:00Z.
.atZone( // Adjust from UTC to the wall-clock time used by the people of a particular region (a time zone). Same moment, same point on the timeline, different wall-clock time.
ZoneID.of( "Africa/Tunis" ) // Specify a time zone using proper `Continent/Region` format. Never use 2-4 letter pseudo-zone such as `PST` or `EST` or `IST`.
) // Returns a `ZonedDateTime` object.
) // Returns a `YearQuarter` object.
.atDay( 1 ) // Returns a `LocalDate` object, the first day of the quarter.
;
By the way, if you can phase out your use of java.util.Date
altogether, do so. It is a terrible class, along with its siblings such as Calendar
. Use Date
only where you must, when you are interfacing with old code not yet updated to java.time.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Upvotes: 17
Reputation: 2173
The answer didn't work for me on Java 10 storing util.Date in UTC.
Date.toInstant() seems to convert the EpochMillis into the local time zone of the server.
ZDT.ofInstant(instant, zoneId) and instant.atZone(zoneId) seem to just tag on a TZ on the instant, but it's already messed up with.
I couldn't find a way to prevent Date.toInstant() from messing with the UTC time with the system time zone.
The only way I found to work around this was to go through the sql.Timestamp class:
new java.sql.Timestamp(date.getTime()).toLocalDateTime()
.atZone(ZoneId.of("UTC"))
.withZoneSameInstant(desiredTZ)
Upvotes: 0
Reputation: 691625
To transform an Instant
to a ZonedDateTime
, ZonedDateTime
offers the method ZonedDateTime.ofInstant(Instant, ZoneId)
. So
So, assuming you want a ZonedDateTime
in the default timezone, your code should be
ZonedDateTime d = ZonedDateTime.ofInstant(calculateFromDate.toInstant(),
ZoneId.systemDefault());
Upvotes: 151
Reputation: 328568
To obtain a ZonedDateTime from a Date you can use:
calculateFromDate.toInstant().atZone(ZoneId.systemDefault())
You can then call the toLocalDate
method if you need a LocalDate. See also: Convert java.util.Date to java.time.LocalDate
Upvotes: 46