I tried searching answer for different formats of ISO 8601 date only but not able to identify answer or material which contains these details
I am trying to receive ISO 8601 date format(date only as its date of birth) string and convert it into date object and later persist in dB. Is yyyy-MM-dd only date format that is considered as ISO 8601 date format. If so I can handle this accordingly but is there multiple date ISO 8601 date formats, if so can you please guide what is the best way to parse given string and convert to date object in Java
Yes, yyyy-MM-dd is the ISO 8601 format for a date without time of day and without time zone.
To store into an SQL database using either a JDBC 4.2 or later driver or a modern JPA implementation such as Hibernate 5, you have got nothing to use a Date object for (no matter if you meant java.util.Date or java.sql.Date). I recommend that instead you use java.time, the modern Java date and time API. The class to use for a date without time of day is LocalDate. And you can store one into your database without any conversion.
LocalDate parses ISO 8601 format as its default, that is, without any explicit formatter:
String receivedString = "1962-11-27";
LocalDate dateOfBirth = LocalDate.parse(receivedString);
System.out.println("Date of birth is " + dateOfBirth);
LocalDate also gives ISO 8601 format back when we print it:
Date of birth is 1962-11-27
I haven’t given you the full story yet, though. yyyy-MM-dd is the extended format that is by far most often used. There is also a basic format that is compacter in that it leaves out the hyphens: yyyyMMdd. I suggest that you insist on getting your date string in the extended format. If you cannot do that, you will have to specify a formatter for parsing:
String receivedString = "19621127";
LocalDate dateOfBirth = LocalDate.parse(
receivedString, DateTimeFormatter.BASIC_ISO_DATE);
This will give you a LocalDate equal to and indistinguishable from the one we had before.
To save into your database using JDBC:
PreparedStatement pStmt
= yourDatabaseConnection.prepareStatement(
"insert into your_table (date_of_birth) values (?);");
pStmt.setObject(1, dateOfBirth);
int insertedRows = pStmt.executeUpdate();
Note the use of setObject(), not setDate().
Links
Wikipedia article: ISO 8601
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Related question: Insert & fetch java.time.LocalDate objects to/from an SQL database such as H2
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. …
In my Spring Boot project, I have this array of objects (List<Object> values)
["2021-06-13T08:50:04.707Z", 3197691, 1933]
The first element is a String and represents a timestamp with timezone.
I can get the first element like this:
String time = (String) values.get(0);
How can I convert it in date or time format in order to insert in a PostgreSQL table?
The given timestamp string conforms to the ISO 8601 standards.
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.
Demo:
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.parse("2021-06-13T08:50:04.707Z");
System.out.println(odt);
}
}
Output:
2021-06-13T08:50:04.707Z
Check this answer to learn how to use OffsetDateTime 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.
First thing you must understand the timestamp format, and for your timestamp format is
yyyy-MM-dd'T'hh:mm:ss.SSS'Z'
Don't forget to add 'T' and 'Z'
Then, to convert from string date to Date class you can use SimpleDateFormat class
String dateInString = "2021-06-13T08:50:04.707Z";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'Z'");
Date date = dateFormat.parse(dateInString);
Then use the data object to insert to your query. Or if you are using JPA, simply just create the entity and put data object to the variable.
I'm having a problem with SimpleDateFormat. I have inputfields in my HTML-page with type = date. I want to save these values into my database where they should be saved as dates. I already figured out how to do this and it works. The only probem I encouter is the way the dates are represented in the database.
I want them to be representated as dd-MM-yyyy. Let's say I want to display 01-06-2016 into my database. When doing this with the code I have..it gives me 0006-12-07. Strangely..when I change my pattern into yyyy-MM-dd...it does give me exactly what the pattern says: 2016-06-01. But it doesn't work the other way round.
String parameter = request.getParameter("instroomdatum");
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
try {
Date parsed = sdf.parse(parameter);
java.sql.Date sql = new java.sql.Date(parsed.getTime());
student.setInstroomdatum(sql);
} catch (ParseException ex) {
Logger.getLogger(StudentController.class.getName()).log(Level.SEVERE, null, ex);
}
Can somebody please explain me what's going on and how to fix this problem? It's really annoying.
EDIT: I tried printing the value of parameter with a simple PrintWriter-object for the specific date 01-06-2016. It shows me 2016-06-01, even though my pattern in the code above is set to dd-MM-yyyy.
You are confusing the display format with the internal representation.
Dates in a database are not represented in any specific display format, such as YYYY-MM-DD. Database dates are normally stored in a numeric form that represents a certain number of seconds and milliseconds (or nanoseconds) from some fixed starting point.
The display format is applied dynamically when you query the database and ask for the date/time as a string, but if you ask for it as a Date object, you get the internal representation, encapsulated in a java.sql.Date.
It is up to your Java code to format the date as you need it.
In your particular example (according to your comment), the string returned by your input method is 2016-06-01, so you need to parse it with the pattern yyyy-MM-dd. This will correctly convert the external representation to a valid Date object.
But how should i specifically change this representation to dd-MM-yyyy
Once you have it as Date, you can immediately turn around and convert the Date back into a String with a different SimpleDateFormat specification.
Date-Time != String
As explained in the correct Answer by Garrison, you must understand that a date’s value internally in a database or in a language such as Java is distinct is distinct from a String generated to represent or communicate that value.
How the date is internally tracked varies amongst databases and languages, and is irrelevant really. What matters is the interface provided by which you can fetch or put your app’s values. A separate issue is how to represent those values as Strings for presentation to your user.
Database (internal) ↔ Driver (JDBC) ↔ App (java.time) ↔ Presentation (String)
java.time
Also, the Question and the other Answers are using old outmoded classes, the date-time classes bundled with the earliest versions of Java. Those classes have been supplanted by the java.time classes built into Java 8 and later. See Oracle Tutorial. Much of the functionality has been back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
LocalDate
Amongst the java.time classes is LocalDate to represent a date-only value without time-of-day and without time zone. The old java.util.Date class, despite its unfortunate name, tracks both a date and a time-of-day. The old java.sql.Date pretends to represent a date-only but in fact, in an unfortunate design decision, extends from java.util.Date so it inherits both a date and a time-of-day, but you are instructed in the class doc to pretend that it is not a subclass. (yes, that is an unpleasant mess)
Do all your business logic using the java.time classes such as LocalDate.
Strings & ISO 8601
As for strings, use the standard ISO 8601 formats. For serializing date-only values, that means YYYY-MM-DD. The java.time classes use ISO 8601 formats by default when parsing/generating strings that represent date-time values.
LocalDate localDate = LocalDate.parse( "2016-06-01" );
But try to stick with objects. Serialize to strings only when you must.
Database
No need for strings when getting data to/from a database. The job of a JDBC driver is to figure out how to move a Java object to/from a data type of your database column.
With a driver that complies with JDBC 4.2, you should be able to use the getObject and setObject methods on a PreparedStatement to deal directly with java.time types.
myPreparedStatement.setObject( 1 , localDate );
If your driver does not support that, you must fall back onto the java.sql.Date class. Look for new methods added to the old classes to go back and forth with java.time types.
java.sql.Date sqlDate = java.sql.Date.valueOf( localDate );
And the other direction.
LocalDate localDate = sqlDate.toLocalDate();
Generate Strings
Apply a format to generate a string as needed for presentation to a user. Use the DateTimeFormatter class. You can define your own formatting pattern.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "dd-MM-yyyy" );
String output = localDate.format( formatter ); // 01-06-2016
Better yet, let java.time localize to the human language and cultural norms of the user’s desired/expected Locale.
Locale locale = Locale.CANADA_FRENCH;
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT , locale );
String output = localDate.format( formatter );
You will need to use the formatter to generate a String for presentation to the user, and to parse input made by the user. You or your users may wish instead to take data-entry as three separate fields: year, month, and day-of-month.
LocalDate localDate = LocalDate.of( 2016 , 6 , 1 );
If all you want to do is format your date into 01-06-2016 format. Try this
String parameter = "0006-12-07";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date parsed = sdf.parse(parameter);
sdf = new SimpleDateFormat("dd-MM-yyyy");
System.out.println(sdf.format(parsed)); //Prints out your desired format 07-12-0006
java.sql.Date sql = new java.sql.Date(parsed.getTime());
student.setInstroomdatum(sql);
} catch (ParseException ex) {
Logger.getLogger(StudentController.class.getName()).log(Level.SEVERE,null, ex);
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
java.sql.Date someDate;
Date anotherDate = format.parse(/*needVariables*/.getOutDate());
someDate = new java.sql.Date(anotherDate.getTime());
work for me
I have a specification which would return the payment history JSON after successful transaction. 3rd party JSON response has a field for the total time taken for the transaction. As example total time spent while doing the payment history was "00:10:10.0". How do I convert this format this String object to integer primitive.
If you don't mind using external library, then using Joda's org.joda.time.LocalTime can help with the string parsing:
String duration = "00:10:10.0";
int seconds = LocalTime.parse(duration).getMillisOfDay() / 1000;
//returns 610
Please note, that since you're complying to ISO formatting you don't even need to explicitly specify the parsed format.
Also, if you're using Java 8 already, than Joda was used as an inspiration for the new date/time library available there, therefore you'll find a similar class in the standard library: LocalTime
The answer by Radyk is correct. Since the Question mentions ISO 8601 Duration, I will add that string output.
java.time
The java.time framework is built into Java 8 and later. Inspired by Joda-Time. Extended by the ThreeTen-Project. Brought to Java 6 & 7 by the ThreeTen-Backport project, and to Android by the ThreeTenABP project.
String durationAsLocalTimeString = "00:10:10.0";
LocalTime durationAsLocalTime = LocalTime.parse( durationAsLocalTimeString );
Duration duration = Duration.between( LocalTime.MIN , durationAsLocalTime );
String output = duration.toString();
PT10M10S
ISO 8601 Duration Format
That output of PT10M10S is the standard Duration format of PnYnMnDTnHnMnS defined by ISO 8601. The P marks the beginning, the T separates the years-months-days portion from the hours-minutes-seconds portion.
I suggest serializing to strings in this format. Using time-of-day format such as 00:10:10.0 to represent an elapsed time is confusing and error-prone. The ISO 8601 format is obvious and intuitive and solves the ambiguity problem.
Both java.time and Joda-Time use these ISO 8601 formats by default when parsing/generating textual representations of date-time values.
Duration duration = Duration.parse( "PT10M10S" );
I have a JODA DateTime 2012-12-31T13:32:56.483+13:00. I would like to convert it to Date in dd/MM/yy format. So I'm expecting code to return Date like - 31/12/12.
Code -
// Input dateTime = 2012-12-31T13:32:56.483+13:00
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yy");
Date date = simpleDateFormat.parse(dateTime.toString("dd/MM/yy"));
Results:
Output - Mon Dec 31 00:00:00 NZDT 2012
Expected Output - 31/12/12
When I do the following, I get the expected output but I don't know how to convert it to Date-
String string = simpleDateFormat.format(date);
Please help me.
Thx
EDIT - I want my end result to be Util Date in dd/MM/yy format. I Do not want String output. My input is Joda DateTime yyyy-MM-ddThh:mm:ss:+GMT. I need to convert JodaDateTime to UtilDate.
As I said originally, Date objects do not have an inherent format. java.util.Date holds a millisecond time value, representing both date & time. Dates are parsed from string, or formatted to string, via your choice of DateFormat.
The strings may be formatted per specification, but the Date objects behind them are always full precision & do not have any inherent notion of format.
To truncate a combined "date and time" java.util.Date to just the date component, leaving it effectively at midnight:
public static Date truncateTime (Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime( date);
cal.set( Calendar.HOUR_OF_DAY, 0);
cal.set( Calendar.MINUTE, 0);
cal.set( Calendar.SECOND, 0);
cal.set( Calendar.MILLISECOND, 0);
return cal.getTime();
}
If you're coming from JodaTime DateTime, you can do this more easily working mostly in the JodaTime API.
public static Date truncateJodaDT (DateTime dt) {
java.util.Date result = dt.toDateMidnight().toDate();
return result;
}
Hope this helps!
See:
http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTime.html#toDateMidnight()
http://joda-time.sourceforge.net/apidocs/org/joda/time/base/AbstractInstant.html#toDate()
Now I'm unsure again, what you want. You want the date in string format now?
return simpleDateFormat.format( date); // from java.util.Date
Or with JodaTime:
return dateTime.toString( "dd/MM/yy"); // from org.joda.time.DateTime
Here is how you do it
Format formatter = new SimpleDateFormat("dd/MM/yy");
String string = formatter.format(date);
tl;dr
OffsetDateTime.parse( "2012-12-31T13:32:56.483+13:00" ).toLocalDate()
Joda-Time supplanted by java.time
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
ISO 8601
Your input string is in standard ISO 8601 format.
The java.time classes use the standard formats by default, so no need to specify a formatting pattern.
Date-time objects vs strings
As the accepted Answer explains, you should not conflate date-time objects with strings that may textually represent their value. A java.util.Date object has no format as it has no text. Ditto for the java.time classes. You can use a java.time object to parse a string, or generate a string, but the object is distinct and separate from the string.
OffsetDateTime
Parse your input string as a OffsetDateTime as it includes an offset-from-UTC though it lacks a time zone.
OffsetDateTime odt = OffsetDateTime.parse( "2012-12-31T13:32:56.483+13:00" );
LocalDate
If you want a date-only value, use the LocalDate class. Remember that for any given moment, the date varies around the globe by time zone. A minute after midnight is a new day in Paris while still “yesterday” in Montréal Québec. If you want the date from that same offset of +13:00, simply call toLocalDate.
LocalDate localDate = odt.toLocalDate();
The Question says you do not want a string, only a date object. So there you go. If you later want a string, call toString for a String to be generated in standard ISO 8601 format, 2012-12-31. For other formats, search Stack Overflow for DateTimeFormatter.
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.
Where to obtain the java.time classes?
Java SE 8 and SE 9 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 SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
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.
Using Java 8 provided date-time classes
LocalDate parsedDate = LocalDate.parse(dateStr,DateTimeFormatter.ISO_ZONED_DATE_TIME);