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
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. …
This question already has answers here:
How to convert a String to a Date using SimpleDateFormat?
(10 answers)
Closed 7 years ago.
I am working in Eclipse .
I have string date = "12-DEC-2016"
now i want to convert it into util date in same format. Please help me with this query.
Conversion
To convert a String into a java.util.Date of a specific format, you can use a java.text.DateFormat. DateFormat objects can perform conversions in both directions, from String to Date by calling format() and from Date to String by calling parse(). DateFormat objects can be obtained in multiple ways, here are some:
Obtain an instance via one of the static get*Instance() methods in DateFormat. This is especially useful when you want the format to be in the user's locale. For example, DateFormat.getDateInstance(DateFormat.SHORT).
Create your very own specific format by creating an instance of SimpleDateFormat. For example, new SimpleDateFormat("dd-MMM-yyyy")
You should consider whether you need a particular fixed format or whether you need the format of whatever the user's locale uses. Keep in mind that different countries use different formats.
In case the format is not for a user, but for machine to machine data interchange, you should consider using ISO 8601 or RFC 1123 as a format.
Also consider using the java.time package instead of java.util.Date. The java.time package is more powerful in case you need to perform calculations. It usually leads to code which is easier to understand and more precise, especially regarding the handling of time zones, daylight savings, local time vs. UTC and such.
Notes:
That you're working in Eclipse doesn't matter to the problem.
References
ISO 8601 https://en.wikipedia.org/wiki/ISO_8601
RFC 1123 https://www.ietf.org/rfc/rfc1123.txt
DateFormat https://docs.oracle.com/javase/8/docs/api/java/text/DateFormat.html
SimpleDateFormat https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html
Java 8 java.time package https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html
java.time
The accepted Answer by Hujer is correct but focuses on the troublesome outmoded classes of java.data.Date/.Calendar & SimpleDateFormat. As suggested, you should be using the java.time framework built into Java 8 and later.
LocalDate
The new classes include LocalDate to represent a date-only value, without time-of-day or time zone.
Parsing requires a Locale when your string includes words to be translated, name of day or month. Better to specify explicitly than depend on JVM’s current default Locale.
String input = "12-DEC-2016";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "d-MM-uuuu" );
f = f.withLocale( Locale.ENGLISH );
LocalDate ld = LocalDate.parse( input , f );
this is maybe a simple question. I am Using SimpleDateFormat to transform a String into a date. I searched through the internet to solve my problem, but i didn't find anything.
But the transformation is wrong. I don't know why.
I want to get the format for example 2015.09.30
This is the Code
Date date1 = null;
String sd ="2015.09.30";
try {
SimpleDateFormat sdToDate = new SimpleDateFormat("yyyy.MM.dd");
date1 = sdToDate.parse(sd);
} catch (ParseException ex2) {
ex2.printStackTrace();
}
When i know output date1, I get this:
Wed Sep 30 00:00:00 CEST 2015
I hope someone can help me. It's maybe a simple question but i don't get it.
When you print date1 as e.g.:
System.out.println(date1);
Java uses Date::toString() function - so you print date in default format.
If you want to print it in different you need to use formatter, e.g.:
System.out.println(sdToDate.format(date1));
The Answer by Joanna Kotuła is correct, but uses old classes. We now have a better alternative.
java.time
You are using outmoded classes. In Java 8 and later use the java.time framework. See Tutorial.
The new classes include a class for date-only values, without time-of-day nor time zone: LocalDate.
Standard Format
Your input strings are in a format close to that used by the ISO 8601 standard, but the standard uses a HYPHEN rather than a FULL STOP, year-month-day. The standard formats are used java.time classes by default for parsing and generating textual representations of date-time values. So if I were you I would simply replace the characters, and avoid bothering to define a custom parsing format.
String input = "2015.09.30".replace( "." , "-" );
LocalDate localDate = LocalDate.parse( input );
Custom Format
The toString method on LocalDate automatically uses the standard ISO 8601 format of uuuu-MM-dd.
If you want to generate output strings in your own format, you will need to define a custom format pattern. Use the java.time.format package.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "uuuu.MM.dd" );
String output = localDate.format( formatter );
You can also parse with that formatter.
LocalDate localDate = LocalDate.parse( "2015.09.30" , formatter );
I am trying to create a String in a format like 2015-08-20T08:26:21.000Z
to 2015-08-20T08:26:21Z
I know it can be done with some String splitting techniques, but i am wondering if there is an elegant solution for that (with minimal code changes).
Both of the above are time strings, the final one which i need is Date in ISO 8601 . https://www.rfc-editor.org/rfc/rfc3339#section-5.6
I have tried a few similar questions like converting a date string into milliseconds in java but they dont actually solve the purpose.
Also tried using :
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());
But it still does not do any String to String conversions. Getting the following error:
23:04:13,829 WARN [RuntimeExceptionMapper] caught RuntimeException: {}: java.lang.IllegalArgumentException: Cannot format given Object as a Date
Is there some library which someone can suggest ?
Thanks.
tl;dr
Instant.parse( "2015-08-20T08:26:21.000Z" )
.toString()
2015-08-20T08:26:21Z
Date-Time Formatter
If all you want to do is eliminate the .000, then use date-time objects to parse your input string value, then generate a new string representation of that date-time value in a different format.
ISO 8601
By the way, if that is your goal, the Question’s title make no sense as both strings mentioned in the first sentence are valid ISO 8601 formatted strings.
2015-08-20T08:26:21.000Z
2015-08-20T08:26:21Z
java.time
Java 8 and later has the new java.time package. These new classes supplant the old java.util.Date/.Calendar & java.text.SimpleDateFormat classes. Those old classes were confusing, troublesome, and flawed.
Instant
If all you want is UTC time zone, then you can use the Instant class. This class represents a point along the timeline without regard to any particular time zone (basically UTC).
DateTimeFormatter.ISO_INSTANT
Calling an Instant’s toString generates a String representation of the date-time value using a DateTimeFormatter.ISO_INSTANT formatter instance. This formatter is automatically flexible about the fractional second. If the value has a whole second, no decimal places are generated (apparently what the Question wants). For a fractional second, digits appear in groups of 3, 6, or 9, as needed to represent the value up to nanosecond resolution. Note: this format may exceed ISO 8601 limit of milliseconds (3 decimal places).
Example code
Here is some example code in Java 8 Update 51.
String output = Instant.parse( "2015-08-20T08:26:21.000Z" ).toString( );
System.out.println("output: " + output );
output: 2015-08-20T08:26:21Z
Changing to a fractional second, .08
String output = Instant.parse( "2015-08-20T08:26:21.08Z" ).toString( );
output: 2015-08-20T08:26:21.080Z
If interested in any time zone other than UTC, then make a ZonedDateTime object from that Instant.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , ZoneId.of( "America/Montreal" ) ) ;
Your format is just not right try this :-
try {
String s = "2015-08-20T08:26:21.000Z";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
Date d = df.parse(s);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
System.out.println(sdf.format(d));
} catch (ParseException e) {
e.printStackTrace();
}
Conversion of a date String of unknown formatting into a date String that uses known formatting can be accomplished using two DateFormat objects- one dynamically configured to parse the format of the input String, and one configured to generate the formatted output String. For your situation the input String formatting is unspecified and must be provided by the caller, however, the output String formatting can be configured to use ISO 8601 formatting without additional input. Essentially, generating an ISO 8601 formatted date String output requires two inputs provided by the caller- a String containing the formatted date and another String that contains the SimpleDateFormat format.
Here is the described conversion as Java code (I deliberately have left out null checks and validations, add these as appropriate for your code):
private String formatDateAsIso8601(final String inputDateAsString, final String inputStringFormat) throws ParseException {
final DateFormat iso8601DateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.ENGLISH);
iso8601DateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
final DateFormat inputDateFormatter = new SimpleDateFormat(inputStringFormat, Locale.ENGLISH);
final Date inputDate = inputDateFormatter.parse(inputDateAsString);
return iso8601DateFormatter.format(inputDate);
}
If you want to modify that method please note that SimpleDateFormat is not thread-safe, and that you should not use it from a static context without a workaround for multi-threaded code (ThreadLocal is commonly used to do just such a workaround for SimpleDateFormat).
An additional "gotcha" is the use of a Locale during the construction of the SimpleDateFormat objects- do not remove the Locale configuration. It is not safe to allow the system to choose to use the default Locale because that is user/machine specific. If you do allow it to use the default Locale, you run the risk of transient bugs because your development machine uses a Locale different than the Locale of your end-user. You do not have to use my selected ENGLISH Locale, it is perfectly fine to use a different Locale (you should understand the rules of that Locale and modify the code as appropriate however). Specification of no Locale and utilization of the system default is incorrect however, and likely will lead to many frustrating hours trying to diagnose an elusive bug.
Please understand this solution is not ideal as of Java 8 and the inclusion of the JodaTime based classes, like Instant. I chose to answer using the outdated API's because those were what you seemed concerned with in your question. If you are using Java 8 I strongly urge to learn and utilize the new classes as they are an improvement in almost every conceivable way.
In my program I am trying to convert the date to string to specified format and then back to date. I need the date to be in dd-MMM-yy format. So, I am converting the date to dd-MMM-yy format using SimpleDateFormat like,
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yy");
String bookingDate = sdf.format(myDate);
The result is what I expected, that is 23-May-12 but when I convert the string back to date
using parse(), it is changing to Wed May 23 13:16:14 IST 2012.
Is there any way to convert the string back to date without changing format? I strictly need to pass the date object in the specified format to the query.
when i convert the string back to date using parse(), it is changing to Wed May 23 13:16:14 IST 2012.
That is not true, It converts back to Date correctly, When you try to print Date instance, It invokes toString() method and it has fixed formated output so if you want the formatted date you need to use format() method
In short parse method parses the String to Date there is no property of Date which holds format so you need to use format() method anyhow
How are you passing the date object in your query, if you are simply appending date in your query string why you need to convert your string date back to date object ? And If you are using prepared statement then you need not worry about the format. And as suggested above Date object does not hold any format information
If You strictly need to pass the date object then there is no worries about its format as Date object has understanding with its format either Java, any java framework or SQL..
And if you are passing the date directly in sql query (concatenating) then you can pass Date String in the same format you see in DB, it will process the same correctly.
You can use DateFormat.getDateInstance(DateFormat.SHORT, <locale>).parse(myDate);.
You will, however, have a date in a standard format like dd/MM/yy, not custom. Template depends on which Locale you use.
You can try building your own Pattern using the standard Java Library or through ThreeTen/JSR-310
We now have a more modern way to do this work.
java.time
The java.time framework is bundled with Java 8 and later. See Tutorial. These new classes are inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project. They are a vast improvement over the troublesome confusing old classes, java.util.Date/.Calendar et al.
Date-only class
The new framework offers a class, LocalDate, to represent a date-only without any time-of-day nor time zone.
By the way, using two-digits for year is asking for trouble. I strongly recommend using four-digit years whenever possible. The java.time framework assumes any two-digit years are in the 20xx century, years 2000 to 2099 inclusive.
To parse the string, specify the expected format. You are not using any of the standard ISO 8601 formats, so we must define a format pattern. Specify a Locale that includes the language we expect to find for name-of-month.
// Parse String representation.
String input = "23-May-12";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "d-MMMM-yy" , Locale.ENGLISH ); // Using four "M" characters means we expect the full name of the month.
LocalDate localDate = formatter.parse ( input , LocalDate :: from );
To go the other direction, to generate a string representation of the date value, we can recycle the same formatter.
// Generate String representation.
String output = localDate.format ( formatter );
Dump to console.
System.out.println ( "input: " + input + " → localDate : " + localDate );
System.out.println ( "localDate : " + localDate + " → output: " + output );
When run.
input: 23-May-12 → localDate : 2012-05-23
localDate : 2012-05-23 → output: 23-May-12