I'm new to the java.time formats in Java 8 and later, but I'm reasonably comfortable with Joda-Time and I'm very familiar with Java's java.util.Date, java.util.Calendar, and DateFormat classes along with ISO 8601.
I'm using PostgreSQL 9.3 with jOOQ 3.6.4, with a foo table column containing a timestamp:
bar timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP
I retrieve that bar value using jOOQ, and try to print it out using java.time's DateTimeFormatter.ISO_OFFSET_DATE_TIME:
DateTimeFormatter timestampFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
Cursor<FooRecord> fooRecordCursor = createDSLContext().selectFrom(FOO).fetchLazy();
for(FooRecord fooRecord : fooRecordCursor) {
System.out.println(timestampFormatter.format(fooRecord.getBar().toInstant());
}
This throws an UnsupportedTemporalTypeException:
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: Year
at java.time.Instant.getLong(Instant.java:608)
at java.time.format.DateTimePrintContext$1.getLong(DateTimePrintContext.java:205)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2543)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1745)
at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1719)
But if I use my own custom ISO8601DateFormat which extends the old-school SimpleDateFormat, I can parse the value just fine:
final DateFormat timestampFormatter = new ISO8601DateFormat();
...
System.out.println(timestampFormatter.format(fooRecord.getBar());
I find this very confusing:
The jOOQ bar field accessor returns a java.sql.Timestamp. In the Java 8 version I convert that to an Instant, but why would that reduce the amount of information available?
An Instant is supposed to be an absolute point of time --- isn't it simply based upon a long offset just like JodaTime and Java Date?
Why is DateTimeFormatter.ISO_OFFSET_DATE_TIME expecting a Year field from an Instant? Shouldn't the formatter just convert the long offset to a date/time in the current time zone, and retrieve the year from that? I wouldn't expect any instant to contain a Year field.
In short: If my SimpleDateFormat-based ISO8601DateFormat works fine for a Timestamp from PostgreSQL, why can't DateTimeFormatter.ISO_OFFSET_DATE_TIME figure out how to format the Instant version of the same value?
Short answer:
It's because the java.time classes are separating the concepts "point in time" and "time as a human sees it" whereas Timestamp/Date don't.
Long answer:
You are right, an Instant is representing a single point in the time line. That's why it is not possible to give a correct/unique answer to the question "what's the year/day/time?". It depends on where on the world the question is asked: In New York it differs from Sidney.
But your DateTimeFormatter is asking exactly this question. And that is why you get an UnsupportedTemporalTypeException.
Date and its subclass Timestamp on the other hand are mixing up the two concepts. While internally storing a long "point in time", they "answer" if asked for their year. Usually they are assuming the local time zone of the system to pin the the long-offset to an specific time zone.
This is error-prone and let to introduction of Calendar, JodaTime and java.time.
Now, why is your DateTimeFormatter not smart enough to align Instant to the default TimeZone?
DateTimeFormatter works on the TemporalAccessor interface and does not differ between concrete implementations like Instant, LocalDateTime or ZonedDateTime. There are legitimate formatting cases for all of those implementations and I assume it is simply not feasible to check the concrete object's compatibility with the given format let alone to perform correct conversions.
The solution:
You have to align your timestamp to a timezone/offset yourself:
System.out.println(timestampFormatter.format(
fooRecord.getBar().toLocalDateTime().atZone(ZoneId.systemDefault()));
Related
I have a timestamp in string and I am using DateTimeFormatter to parse the string as below and assign that to a timestamp type variable
import java.sql.Timestamp
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAccessor
import java.time.Instant
String myTime = "2020-08-03T20:15:49"
String myTimeFormat = "yyyy-MM-dd'T'HH:mm:ss"
DateTimeFormatter timestampFormatter = DateTimeFormatter.ofPattern(myTimeFormat);
TemporalAccessor ta = timestampFormatter.parse(tempValue);
// getting error that Cannot create Instant from java.time.format.Parsed
Timestamp finalTime = Timestamp.from(Instant.from(ta));
How to convert it to java.sql.Timestamp?
Context: I am trying to convert a string column in a spark dataframe (using timestamp format) to a timestamp column and for which I am using the above logic in my udf (using udf as I need to perform other checks in addition to just casting) and thus trying to convert to Timestamp to apply the spark schema with this column as Timestamp
Ref: https://spark.apache.org/docs/latest/sql-ref-datatypes.html
You do not need a DateTimeFormatter
The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.
Once parsed into LocalDateTime, you can obtain java.sql.Timestamp using Timestamp#valueOf.
Demo:
import java.sql.Timestamp;
import java.time.LocalDateTime;
public class Main {
public static void main(String[] args) {
String myTime = "2020-08-03T20:15:49";
LocalDateTime ldt = LocalDateTime.parse(myTime);
Timestamp finalTime = Timestamp.valueOf(ldt);
System.out.println(finalTime);
}
}
Output:
2020-08-03 20:15:49.0
ONLINE DEMO
Note: The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. Since java.sql.Timestamp extends java.util.Date, it inherits the same drawbacks. It is recommended to stop using them completely and switch to the modern Date-Time API*. Check this answer and this answer to learn how to use java.time API with JDBC.
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Your issue isn't that you can't create a Timestamp: it's that you can't create an Instant.
An Instant identifies a single point on the timeline, identified via an offset from Unix epoch (1970-1-1 00:00:00 UTC).
The problem with your input is that it doesn't identify a timezone. As such, it doesn't uniquely identify a single point in time, because 2020-08-03T20:15:49 isn't the same instant in London vs New York vs Shanghai vs Delhi (for example).
As such: parse your string to a LocalDateTime; then specify the time zone; then convert to an Instant; then convert to a Timestamp:
LocalDateTime ldt = LocalDateTime.parse(myTime, timestampFormatter);
// Or whichever time zone.
Instant instant = ldt.atZone(ZoneId.of("UTC")).toInstant();
Timestamp finalTime = Timestamp.from(instant);
What is a timestamp?
Wikipedia defines a timestamp as
a sequence of characters or encoded information identifying when a
certain event occurred …
So your string is not a timestamp or at least can only be considered one if we know which time zone (or UTC offset) is assumed for the date and time of day it contains. Today most IT systems are not confined to one time zone, so it is generally recommended to include UTC offset information with your timestamps and/or keep them in UTC. I am assuming that you asked for an old-fashioned java.sql.Timestamp for use with your SQL database. Depending on your adherence to the recommendations you will need different types both in SQL and in Java.
Recommended: Use explicit offset, preferably UTC. With most database engines this means using its timestamp with time zone or timestamptz data type. The JDBC standard since 4.2 says that you should then use OffsetDateTime in Java. Many drivers also handle Instant, the class we would normally prefer for an unambiguous timestamp in Java. Your attempt to create an Instant may hint that this agrees with your intentions.
Not recommended: Use implicit offset, preferably UTC. Many old applications would use their own time zone. In any case use timestamp (without time zone) in SQL and LocalDateTime in Java. The lack of offset in your string may hint that this was your approach.
The java.sql.Timestamp class that you mentioned is poorly designed, in fact a true hack on top of the already poorly designed java.util.Date class. So Timestamp is not among the classes I recommend for sending your tiemstamp value to the database, whether for storage or for use in a query.
Saving your timestamp to SQL
Here’s a code example using OffsetDateTime and a custom assumed time zone.
String myTime = "2020-08-03T20:15:49";
OffsetDateTime odt = LocalDateTime.parse(myTime)
.atZone(ZoneId.of("Asia/Colombo"))
.toOffsetDateTime();
PreparedStatement ps = yourDatabaseConnection
.prepareStatement("insert into your_table(your_timestamptz_column) values (?);");
ps.setObject(1, odt);
ps.executeUpdate();
Since JDBC 4.2 the setObject method accepts java.time types including OffsetDateTime.
If your time string is UTC, the conversion to OffsetDateTime is a bit simpler:
OffsetDateTime odt = LocalDateTime.parse(myTime).atOffset(ZoneOffset.UTC);
Using Instant: You may convert the OffsetDateTime from before simply:
Instant inst = odt.toInstant();
Now you can pass inst to setObject() in the same way that we passed odt before.
If you are using timestamp without time zone in SQL and LocalDateTime in Java, the answer by Arvind Kumar Avinash already shows the simple way to parse your string. Also a LocalDateTime can be passed to setObject() in the same way as above.
By the way, we most often neither need to nor want to use the TemporalAccessor interface. Its documentation says:
This interface is a framework-level interface that should not be
widely used in application code. …
I want to convert a timestamp to a string given a timezone argument (in Java). From the code I'm looking at internally the timestamp has nanosecond precision (or at least one can convert it to nanoseconds and I don't care since the output format I want to generate isn't that precise).
The DateFormat allows an S specifier and will apply a TimeZone, but it seems to do only 3 digits (milliseconds?) precision. Using toString gives 6 digits of precision within the seconds (microseconds?) but doesn't seem to take a TimeZone argument.
I need something that does both, allows a TimeZone specifier and gives 6 digits of precision within a second.
What to use?
I am assuming you mean a java.sql.Timestamp that you are getting from an SQL database where it was a timestamp either with or without time zone.
Use java.time
First, you don’t need that. The Timestamp class is poorly designed and long outdated. Instead prefer to get from your database:
If your database column is a timestamp with time zone, which it should be, then get an OffsetDateTime (with some JDBC drivers an Instant works too).
If your database column is timestamp without time zone (not recommended), then get a LocalDateTime. The problem with this is that a LocalDateTime is a date and time without time zone, so not a unique point in time, so unsuited for a timestamp.
The mentioned types are all from java.time, the modern Java date and time API, and they all have nanosecond precision.
Example:
OffsetDateTime odt = yourResultSet.getObject("my_timestamp_col", OffsetDateTime.class);
System.out.println(odt);
Example output:
2018-11-29T22:34:56.123456789Z
The trailing Z in the output means Zulu time zone, UTC or offset zero.
You wanted to apply a given time zone. So for example:
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("America/Guyana"));
System.out.println(zdt);
2018-11-29T18:34:56.123456789-04:00[America/Guyana]
Getting a type from java.time from the result set using ResultSet.getObject requires JDBC 4.2 (or a modern JPA implementation or what you use for data access). Most of us have that.
Handling a Timestamp from a legacy API
In case you either haven’t got JDBC 4.2 yet or you are getting the Timestamp from a legacy API that you can’t afford to change just now:
ZonedDateTime zdt = yourTimestamp.toInstant()
.atZone(ZoneId.of("America/Guyana"));
If you have specific requirements for your string output, use a DateTimeFormatter to format your ZonedDateTime. This is described in many places, just search.
Link
Oracle tutorial: Date Time explaining how to use java.time.
I need to parse a UTC date and time string, e.g. 20180531_132001Z into a Java 8 date and time object. How do I go about doing this using Java 8's new date and time libraries? Most examples I see is for LocalDateTime, like this:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss'Z'");
LocalDateTime localDateTime = LocalDateTime.parse("20180531_132001Z", formatter);
System.out.println(localDateTime);
System.out.println(localDateTime.atOffset(ZoneOffset.UTC));
The code outputs:
2018-05-31T13:20:01
2018-05-31T13:20:01Z
Is this considered local time or UTC time? The string value I am parsing is based on UTC, so I am wondering if I need to do anything further before persisting to the database.
If the former, how do I convert that to UTC date and time?
I ultimately need to persist this to a SQL Server database table (column type is [datetime2](7), using [Spring] JDBC.
Update: Based on the comments and answers, I think my question is not well thought out. Putting it another way, if I get an input string and I parse it without factoring any zone or offset, I will get a LocalDateTime object. How do I take that object and convert the encapsulated value to UTC date and time?
LocalDateTime can be misleading. It doesn't represent your local date/time, it represents a local date/time.
It carries no time zone info at all.
That is, it just says for example "it's 13:20". It doesn't say where it's 13:20. It's up to you to interpret the where part.
Due to this LocalDateTime is usually not very useful for carrying timestamps, it's only useful for situations when the timezone is dependent on some context.1
When working with timestamps it's better to use ZonedDateTime or OffsetDateTime instead. These carry the date, time and offset.
So localDateTime.atOffset(ZoneOffset.UTC) will actually return an instance of OffsetDateTime, by interpreting localDateTime as UTC time.
One could argue that you can avoid the interpreting part by parsing with the timezone info in the first place (even though it's always Z):
String example = "20180531_132001Z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmssX");
OffsetDateTime dateTime = OffsetDateTime.parse(example, formatter);
System.out.println(dateTime); // look ma, no hardcoded UTC
Will print:
2018-05-31T13:20:01Z
The added value is that your code automatically supports timezones (e.g. "20180531_132001+05").
JDBC 4.2 compliant driver may be able to directly address java.time types by calling setObject.
For older JDBC drivers you can convert dateTime to a java.sql.Timestamp or java.util.Date:
java.sql.Timestamp.from(dateTime.toInstant());
java.util.Date.from(dateTime.toInstant());
1 There is almost always some context in which LocalDateTime operates. For example "Flight KL1302 arrives at airport X tomorrow at 13:20". Here the context of "tomorrow at 13:20" is the local time at airport X; it can be determined by looking up the time zone of X.
tl;dr
myPreparedStatement.setObject( // Pass java.time objects directly to database, as of JDBC 4.2.
… , // Indicate which placeholder in your SQL statement text.
OffsetDateTime.parse( // Parse input string as a `OffsetDateTime` as it indicates an offset-from-UTC but not a time zone.
"20180531_132001Z" , // Define a formatting pattern to match your particular input.
DateTimeFormatter.ofPattern( "uuuuMMdd_HHmmssX" ) // TIP: When exchanging date-time values as text, use use standard ISO 8601 formats rather than inventing your own.
) // Returns a `OffsetDateTime` object.
.toInstant() // Returns a `Instant` object, always in UTC by definition.
)
Details
There is some helpful information in the other Answers, but all of them have some misinformation which I tried to correct by posting comments.
Most importantly, your code is using the wrong Java class and the wrong database data type for that given input.
Below is explanation along with a complete code example, using the modern java.time classes with JDBC 4.2 or later.
Z = UTC
DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss'Z'")
Never put single-quotes around vital parts of your input such as you did here with Z. That Z means UTC and is pronounced “Zulu”. It tells us the text of the date and time-of-day should be interpreted as using the wall-clock time of UTC rather than, say, America/Montreal or Pacific/Auckland time zones.
Do not use the LocalDateTime for such inputs. That class lacks any concept of time zone or offset-from-UTC. As such, this class does not represent a moment, and is not a point on the timeline. A LocalDateTime represents the set of potential moments along a range of about 26-27 hours (across all time zones). Use LocalDateTime when you mean any or all time zones rather than one particular zone/offset. In contrast, the Z tells us this input uses the wall-clock time of UTC specifically.
Parsing
Define a formatting pattern to match all important parts of your input string.
String input = "20180531_132001Z" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMdd_HHmmssX" ) ;
By the way, whenever possible, use standard ISO 8601 formats rather than a custom format as seen in your Question. Those formats are wisely designed to be easy to parse by machine and easy to read by humans across cultures while eliminating ambiguity.
Parse as a OffsetDateTime because your input indicates an offset-from-UTC (of zero hours). An offset-from-UTC is merely a number of hours and minutes, nothing more, nothing less.
Use the ZonedDateTime class only if the input string indicates a time zone. A time zone has a Contintent/Region name such as Africa/Tunis. A zone represents the history of past, present, and future changes in the offset used by the people of a particular region.
OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;
odt.toString(): 2018-05-31T13:20:01Z
Database
To communicate this moment to a database using JDBC 4.2 and later, we can directly pass the java.time object.
myPreparedStatement.setObject( … , odt ) ;
If your JDBC driver does not accept the OffsetDateTime, extract the simpler class Instant. An Instant is in UTC always, by definition.
Instant instant = odt.toInstant() ;
myPreparedStatement.setObject( … , instant ) ;
And retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Beware - Wrong datatype in your database
I am not a MS SQL Server user, but according to this documentation, the column data type DATETIME2 is not appropriate to your input. That data type seems to be equivalent to the SQL-standard type DATETIME WITHOUT TIME ZONE. Such a type should never be used when recording a specific moment in history.
Lacking any concept of time zone or offset-from-UTC, that column type should only be used for three situations:
The zone or offset is unknown.This is bad. This is faulty data. Analogous to having a price/cost without knowing the currency. You should be rejecting such data, not storing it.
The intention is “everywhere”, as in, every time zone.Example, a corporate policy that states “All our factories will break for lunch at 12:30" means the factory in Delhi will break hours before the factory in Düsseldorf which breaks hours before the factory in Detroit.
A specific moment in the future is intended, but we are afraid of politicians redefining the time zone.Governments change the rules of their time zones with surprising frequency and with surprisingly little warning (even [no warning at all][10]). So if you want to book an appointment at 3 PM on a certain date, and you really mean 3 PM regardless of any crazy decision a government might make in the interim, then store a LocalDateTime. To print a report or display a calendar, dynamically apply a time zone (ZoneId) to generate a specific moment (ZonedDateTime or Instant). This must be done on-the-fly rather than storing the value.
Since your input is a specific moment, a certain point on the timeline, you should be storing it in the database using a column type akin to the SQL-standard type TIMESTAMP WITH TIME ZONE.
About 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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
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?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
Maybe this can help you.
public static void main(String... strings) {
OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println(utc.toString());
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy mm dd hh:mm a");
System.out.println(utc.format(format));
}
While you certainly can use LocalDateTime and format it to look like a zoned date time using offset, it would be easier to use an Object designed to store time zone.
ZonedDateTime zonedDateTime = ZonedDateTime.parse("20180531_132001Z", DateTimeFormatter.ofPattern("yyyMMdd_HHmmssX"));
This gives you the option to use Instant to convert to SQL timestamp or any other format without having to hard-code the time zone, especially if time zone is added in the future or changes.
java.sql.Timestamp timestamp = new java.sql.Timestamp(zonedDateTime.toInstant().toEpochMilli());
You can view the timestamp's instant and compare it to the toString, which should be pegged to your timezone, and instant.toString, which pegs to UTC.
System.out.print(timestamp + " " + timestamp.toInstant().toString());
this should do the trick to parse string to LocalDateTime :
String example = "20180531_132001Z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmssX");
ZonedDateTime dateTime = ZonedDateTime.parse(example, formatter);
See that code run live in IdeOne.com.
dateTime.toString(): 2018-05-31T13:20:01Z
Timestamp timestamp = Timestamp.from(dateTime.toInstant());
Timestamp then is saved into db
Consider a code:
TemporalAccessor date = DateTimeFormatter.ofPattern("yyyy-MM-dd").parse("9999-12-31");
Instant.from(date);
The last line throws an exception:
Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 9999-12-31 of type java.time.format.Parsed
How to create Instant from yyyy-MM-dd pattern?
The string "9999-12-31" only contains information about a date. It does not contain any information about the time-of-day or offset. As such, there is insufficient information to create an Instant. (Other date and time libraries are more lenient, but java.time avoids defaulting these values)
Your first choice is to use a LocalDate instead of an `Instant:
LocalDate date = LocalDate.parse("9999-12-31");
Your second choice is to post process the date to convert it to an instant, which requires a time-zone, here chosen to be Paris:
LocalDate date = LocalDate.parse("9999-12-31");
Instant instant = date.atStartOfDay(ZoneId.of("Europe/Paris")).toInstant();
Your third choice is to add the time-zone to the formatter, and default the time-of-day:
static final DateTimeFormatter FMT = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd")
.parseDefaulting(ChronoField.NANO_OF_DAY, 0)
.toFormatter()
.withZone(ZoneId.of("Europe/Paris"));
Instant instant = FMT.parse("9999-31-12", Instant::from);
(If this doesn't work, ensure you have the latest JDK 8 release as a bug was fixed in this area).
It is worth noting that none of these possibilities use TemporalAccessor directly, because that type is a low-level framework interface, not one for most application developers to use.
The problem isn't the fact that you are using the year 9999. The Instant.MAX field evaluates to the timestamp 1000000000-12-31T23:59:59.999999999Z, so 9999 as a year is fine.
Dealing with TemporalAccessors instead of the more semantically rich types like LocalDateTime or ZonedDateTime is like using a Map to model an object and its properties instead of writing a class -- you have to assure that the value has the fields (like seconds, nanoseconds, etc) that are expected by something receiving it, rather than depending on formally declared operations in a higher level class to prevent dependencies from going unmet.
In your case it is likely that the temporal accessor contained the parsed date fields it was given, but didn't have a "seconds" field that the Instant needed. It is best to use the more semantically rich types like LocalDateTime in most instances.
Since you only have date fields, you should parse it as a date, then add the time fields before converting it to an Instant. Here is one way, using LocalDate to parse the date:
LocalDate localDate = LocalDate.parse("2016-04-17");
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant instant = localDateTime.toInstant(ZoneOffset.UTC);
Either you are only interested in the date itself (31st of December 9999), in which case the appropriate type would be a LocalDate:
LocalDate date = LocalDate.parse("9999-12-31");
Or you do want an Instant, in which case you need to set a time and time zone, for example, 00:00 in Tokyo:
Instant instant = date.atStartOfDay(ZoneId.of("Asia/Tokyo")).toInstant();
public static void main(String[] args) throws ParseException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd").parse("2016-12-31").toInstant());
}
the above code gives the following output:
2016-12-31T00:00:00Z
i have answered this question using features('toInstant' method) of java 8. hope this answers your question...
I have a date/time string which needs to be sent to the Google Tasks API but I can't figure out how to convert a Joda-Time library DateTime object to a Java DateTime object. I'm using Android as the platform.
The string starts off as "2012/07/19 22:00:00" and is first converted to Iso format.
Here is my code:
Task task = new Task();
task.setTitle(title);
task.setNotes(note);
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss");
DateTime dt = formatter.parseDateTime(dateToIso("2012/07/19 22:00:00"));
task.setDue(dt);
private String dateToIso(String date) {
date = date.replace("/", "-");
date = replaceCharAt(date, 10, 'T');
date = date + ".000Z";
return date;
}
The error I am getting is:
"Type mismatch: cannot convert from org.joda.time.DateTime to
com.google.api.client.util.DateTime"
Please assist. Information with regards to ISO conversion would also be useful.
Let Formatter Parse String
The problem is your "dateToIso" method. No need for that. The DateTimeFormatter object's job is to parse the string when given the correct format. You did indeed give it the correct format. And then you went and morphed the string into a different format!
Solution: (a) Kill your dateToIso method. (b) Delete the call to that method. Just pass the original string to parseDateTime.
Side-Problem: You ignored the issue of time zone. So when parsing that string, Joda-Time will assume the event of that date-time occurred in your JVM's default time zone. So running this same code with same inputs but on another computer/JVM with different time zone settings will result in different output. Probably not what you want. Lesson Learned: Always specify a time zone rather than rely on default.
Yet Another Problem: The error you quoted is a different problem, converting from Joda-Time to Google time. Read on.
Read The Doc
If you are trying to convert your org.joda.time.DateTime object to a com.google.api.client.util.DateTime object, just look at the JavaDoc. There you will see that the constructor of the Google DateTime takes a java.util.Date. Joda-Time has a built-in toDate method to convert to a java.util.Date object for interoperability with other classes.
Food-Chain
Create a food chain of objects like this:
org.joda.time.DateTime → java.util.Date → com.google.api.client.util.DateTime
Some untested code…
org.joda.time.DateTimeZone = org.joda.time.DateTimeZone.forID( "Africa/Johannesburg" );
org.joda.time.DateTime jodaDateTime = new DateTime( timeZone );
// Convert from Joda-Time to old bundled j.u.Date
java.util.Date juDate = jodaDateTime.toDate();
// Convert from j.u.Date to Google Date.
com.google.api.client.util.DateTime googleDateTime = new com.google.api.client.util.DateTime( juDate );
Milliseconds
Alternatively, you could extract and pass milliseconds.
Generally I recommend avoiding dealing directly with milliseconds where possible. Using milliseconds can be confusing, sloppy, and error-prone. A milliseconds count is difficult to debug as humans cannot readily decipher the date-time meaning of a long. While Joda-Time and java.util.Date use milliseconds-since-Unix-epoch as their internal time-tracking mechanism…
Some software uses seconds or nanoseconds rather than milliseconds.
Some software uses other epochs rather than the Unix epoch.
Going The Other Direction
[The following section assumes Google has supplanted the API referenced by the Question with a newer API. Not sure if this assumption is correct.]
When going from a com.google.gdata.data.DateTime object to a Joda-Time DateTime, I would use the milliseconds count-from-epoch provided by the getValue method. Note that it returns a 64-bit long, rather than a 32-bit int.
Be sure to assign the desired time zone to the Joda-Time DateTime rather than rely on implicitly assigning the JVM’s current default time zone.
long millisecondsFromUnixEpoch = myGoogleDateTime.getValue();
org.joda.time.DateTimeZone zone = DateTimeZone.forID( "Africa/Johannesburg" );
org.joda.time.DateTime jodaDateTime = new DateTime( millisecondsFromUnixEpoch, zone );
The Google API provides a few other choices.
toStringRfc822
You could call the toStringRfc822 method to generate a string to be parsed by Joda-Time. Unfortunately, RFC 822 is awkward and ambiguous to parse. Among other faults it uses the non-standard non-unique 3-4 letter time zone codes rather than proper time zone names. Joda-Time refuses to attempt parsing those codes because of their ambiguity. I assume Google only includes it here for backward-compatibility with old APIs/libraries. The modern Internet protocols have moved on to ISO 8601.
toUiString
Perhaps you could call the toUiString method to create a string to be parsed by Joda-Time. Unfortunately, their documentation fails to explain what format is used by that method.
toString
You could call the toString method that is documented as producing a xs:dateTime string. The doc fails to explain precisely, but I'm guessing they mean the XML Schema spec’s inclusion of ISO 8601. You might try this method to see what it generates. It may be useful if you want to preserve the offset-from-UTC embedded in the Google object. But remember that a time zone is more than an offset-from-UTC, so you should still assign the desired/expected time zone to your Joda-Time DateTime object. Therefore, I'm not sure if this better than just passing the long count-from-epoch to the constructor of Joda-Time DateTime.
java.time
Now that Java 8 is released, perhaps Google may modernize its APIs to use the java.time package.
Note that java.time extends the ISO 8601 format to append the formal name of the time zone, a very helpful idea.