I need to format the Java Date object into a String like yyyyMMdd (round to day). For e.g, 20180129. I have the following implementation:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.format(roundedDate);
The code works most the time, but sometimes it'll generate results like 2018129, which is not what I want. So I'll have both 20180129 and 2018129 in my database.
The app consumes messages from a MQ and ummarshalls the timestamp in the message into a Java Date object. And it formats the date into a the above String.
The issue is that I cannot reproduce the issue in debug mode. It always produces the expected results in the debugger. But after I ran it on a server (in Docker) for some time, I see such corrupted data.
I wonder why the SimpleDateFormat could have such undetermined behavior given a valid Date object? Any idea will be appreciated.
SimpleDateFormat is not thread-safe, see this excellent article.
java.time.format.DateTimeFormatter is the modern thread-safe implementation of this functionality in the core Java.
tl;dr
Use the thread-safe java.time classes instead.
Specifically, use LocalDate and DateTimeFormatter.BASIC_ISO_DATE.
LocalDate.parse(
"2018129" ,
DateTimeFormatter.BASIC_ISO_DATE
)
2018-01-29
LocalDate.now()
.format( DateTimeFormatter.BASIC_ISO_DATE )
20180129
Thread-safety
You do not provide enough information to diagnose your problem. I would guess either:
You are using those legacy date-time objects across threads, and they were not designed to be thread-safe. Instead use the java.time classes which are designed to be thread-safe by design via immutable objects pattern.
Something is going wrong during whatever you are doing in this mysterious “date rounding” which you mention but neglect to explain.
Wrong data type
timestamp in the message into a Java Date object.
You are putting a date-only value into a date-with-time-of-day type. Square peg, round hole.
Instead, use a date-only type for a date-only value: LocalDate.
ISO 8601
Your desired format YYYYMMDD happens to be defined in the ISO 8601 standard, as the “basic” variant where the use of delimiters is minimized.
Java provides a DateTimeFormatter object for this purpose: DateTimeFormatter.BASIC_ISO_DATE. So no need to define a formatting pattern.
String input = "2018129" ;
LocalDate ld = LocalDate.parse( input , DateTimeFormatter.BASIC_ISO_DATE ) ;
To generate such a string, use the same formatter.
LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
String output = today.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
By the way, I recommend using the full-length versions of ISO 8601 formats rather than the compact “basic” variants. The few bytes saved are not worth giving up the readability and reduced ambiguity, in my experience. Plus, the java.time classes use the full-length ISO 8601 formats by default when parsing/generating String objects, so you can dispense with DateTimeFormatter objects entirely.
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.
Related
I have a column in my table of Date type in MYSQL and inserting the date format of 25-March-2019 hh:mm:ss returns an error telling me incorrect data value.
So I have my code written like this:
String startdt=request.getParameter("startdate");
String enddate=request.getParameter("enddate");
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
Date Startdate=dateFormat.parse(startdt);
Date Enddate=dateFormat.parse(enddate);
And I am passing Startdate and Enddate to a function that inserts into my table column.
Is there a way I can have Startdate and Enddate above just return in yyyy-mm-dd without the time so I can insert to my db without error?
tl;dr
myPreparedStatement
.setObject(
LocalDate.parse( "2019-01-23" )
) ;
DATE in MySQL is date-only
The DATE type in MySQL is a date-only value, without time-of-day and without time zone.
Excerpting from MySQL 8.0 documentation:
The DATE type is used for values with a date part but no time part. MySQL retrieves and displays DATE values in 'YYYY-MM-DD' format. The supported range is '1000-01-01' to '9999-12-31'.
Use a date-only type in Java for data coming from a date-only type in your database. The java.util.Date class you are trying to use is not a date, it is a moment in UTC, a date with time-of-day and offset-from-UTC of zero, all tracked as a count of milliseconds from the first moment of 1970 in UTC. The misnaming of that class is only the first of many poor design choices made by those programmers. Move on to java.time classes instead. Stop using Date.
MM = month number, not name
Your format of "yyyy-MM-dd" is for a numeric month, not the string of month name shown in your example value of 25-March-2019.
Avoid legacy date-time classes
The SimpleDateFormat and Date classes are terrible, a wretched mess of bad design. They were supplanted years ago with the adoption of JSR 310, implemented in the java.time classes.
Smart objects, not dumb strings
Exchange objects with your database where possible, not text.
As of JDBC 4.2, we can directly exchanged java.time objects with the database. For a date-only value, as with SQL-standard DATE type, use the java.time.LocalDate class.
Apparently, your text inputs for date values is YYYY-MM-DD which is standard ISO 8601 format. The java.time classes use ISO 8601 formats by default. So no need to specify a formatting pattern.
LocalDate localDate = LocalDate.parse( "2019-01-23" ) ;
myPreparedStatement.setObject( … , localDate ) ;
Retrieval.
LocalDate localDate = myResultSet.getObject( … , LocalDate.class ) ;
localDate.toString(): 2019-01-23
If you want to produce a string representing the value of that LocalDate object in a different textual format, use the DateTimeFormatter class. Search Stack Overflow for more info as it, like the rest of your Question, has been covered many times already on Stack Overflow. Do search Stack Overflow before posting.
Tip: Generally best to use a PreparedStatement in your JDBC work. One major benefit is thwarting SQL Injection security attacks.
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.
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?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - 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
Most 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.
Java 7 and ThreeTen Backport
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("d-MMMM-uuuu HH:mm:ss", Locale.ENGLISH);
String dateFromHtmlForm = "25-March-2019 22:43:55";
LocalDateTime dateTime = LocalDateTime.parse(dateFromHtmlForm, formatter);
// We are discarding the time of day and only saving the date
java.sql.Date dateToSave = DateTimeUtils.toSqlDate(dateTime.toLocalDate());
String insertSql = "insert into your_table (your_date_column) values (?);";
try (PreparedStatement insertStatement
= yourDatabaseConnection.prepareStatement(insertSql)) {
insertStatement.setDate(1, dateToSave);
int rowsInserted = insertStatement.executeUpdate();
}
As has already been said, pass date objects to MySQL, not strings. In Java 8 and later these would have been LocalDate objects, but in Java 7 we will need to make do with the poorly designed java.sql.Date class. It’s still better than strings. And the conversion from LocalDate is straightforward.
On Java 7 we can use java.time through the backport, ThreeTen Backport (ThreeTen for JSR-310). My imports are:
import org.threeten.bp.DateTimeUtils;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.format.DateTimeFormatter;
Why would we want to use an external library for this? There are pros and cons, of course. Advantages include:
java.time is so much nicer to work with than the old-fashoined Date and SimpleDateFormat and gives clearer code.
It’s future-proof: once you move to Java 8 or later, all you need to do is change your import statements (and discard the library and retest).
Links
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.
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
while comparing future days it occurs some fail in Java. Look at the code if you can
DateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd");
Date date = dateFormat.parse("2258-11-01");
Date date1 = dateFormat.parse("2258-10-31");
System.out.println(date.after(date1));
Output is:false
Anyone has idea why it does't work?
The m format represents a minute in the hour. You probably meant to use M, representing the month in the year:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
You should use the capital MM for month, overwise it does not parse like you want it to.
new SimpleDateFormat("yyyy-MM-dd");
tl;dr
Use the modern java.time classes to parse your strings that happen to be in standard format.
LocalDate.parse( "2258-11-01" )
.isAfter(
LocalDate.parse( "2258-10-31" )
)
true
Details
As others mentioned, the formatting pattern is case-sensitive, and yours is incorrect.
Another problem, you are inappropriately squeezing a date-only value into a type intended for a date with time-of-day in UTC.
Also, you are using the terrible old date-time classes that were supplanted years ago by the modern java.time classes.
Your input strings happen to comply with the excellent ISO 8601 standard. The java.time classes use these formats by default when parsing/generating strings. So no need to even bother with defining a formatting pattern.
LocalDate ld1 = LocalDate.parse( "2258-11-01" ) ;
LocalDate ld2 = LocalDate.parse( "2258-10-31" ) ;
Compare.
boolean isAfter = ld1.isAfter( ld2 ) ; // true
All this has been covered many many times already on Stack Overflow. Please learn to search Stack Overflow thoroughly before posting.
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, Java SE 11, and later - 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
Most 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.
I have CSV data to import into data base where I have date column in that CSV in that some dates are like 1-DEC-16 without a leading zero (padding zero). How to make that String as 01-DEC-2016? Can it be done with SimpleDateFormat or is there any String format method? I tried with below but it’s not happening.
String d="1-DEC-17";
String newstring = new SimpleDateFormat("yyyy-MM-dd").format(d);
System.out.println(newstring);
d vs dd
To parse a string with a leading zero on the month or day-of-month, use a pair of formatting pattern characters. That would be dd for day-of-month.
To parse a string without a leading zero, use a single character, d for day-of-month.
Unfortunately, your input has the month name abbreviation in all uppercase. That violates the norm of the English-speaking locales I know of, such as Locale.US. So by default, a DateTimeFormatter will refuse to process that improper input. To tolerate the all-uppercase, we can set the formatter to be “lenient”.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "d-MMM-uu" , Locale.US ).withResolverStyle( ResolverStyle.LENIENT ) ;
LocalDate ld = LocalDate.parse( "1-DEC-17" , f ) ;
See this code run live at IdeOne.com.
ld.toString(): 2017-12-01
If sending this value to a database, do not use a string for date-time value. Use a date-time object for date-time values.
For JDBC drivers compliant with JDBC 4.2 and later, pass the java.time types directly via setObject & getObject.
myPreparedStatement.setObject( … , ld ) ;
If not compliant, convert briefly to the troublesome old legacy type, java.sql.Date. Use the new methods added to the old classes.
java.sql.Date d = java.sql.Date.valueOf( ld ) ;
myPreparedStatement.setDate( … , d ) ;
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, Java 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 Java 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.
I want to do some formatting in my webapp, using MessageFormat, DateFormat, DecimalFormat, etc.
Since these are not thread-safe, one static instance for each usage won't work, but it seems wasteful to create a new XXXXFormat object each time one is needed. Caching and re-using them with a ThreadLocal seems like an obvious optimization.
This seems like a very common pattern, so I'm wondering if there are any appropriate libraries.
Instead of calling:
DecimalFormat formatter = new DecimalFormat("###,##0.00");
String formatted = formatter.format(value);
every time I need to format something, why not:
String formatted = FormatCache.formatDecimal("###,##0.00",numberValue);
where FormatCache would do the ThreadLocal caching with a HashMap keyed on the format pattern?
Presumably there'd be other methods like:
String FormatCache.formatDecimal(String, Number);
String FormatCache.formatDate(String, Date);
String FormatCache.formatMessage(String, Object...);
tl;dr
Cache a thread-safe DateTimeFormatter object (immutable).
Never use SimpleDateFormat. Use only java.time package for date-time work.
java.time
The troublesome old date-time classes such as DateFormat & SimpleDateFormat are now supplanted by the modern java.time classes. Specifically here, the DateTimeFormatter class.
Immutable objects, thread-safe
The java.time classes were designed to be Immutable Objects. This means that rather than modifying any content in the object, a new distinct object is generated. The original is left intact.
This, and other techniques, make the java.time classes thread-safe by design and are so documented.
DateTimeFormatter
DateTimeFormatter dateTimeFormatterFullQuébec = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
You can cache that object dateTimeFormatterFullQuébec, keep it around.
ZoneId
Likewise, you could keep a ZoneId time zone object cached.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId zoneMontréal = ZoneId.of( "America/Montreal" ) ;
Then use them any time, even across threads.
ZonedDateTime zdt = ZonedDateTime.now( zoneMontréal ) ;
String output = zdt.format( dateTimeFormatterFullQuébec ) ;
dimanche 4 mars 2018 à 18:36:32 Eastern Standard Time
The java.time objects such as ZonedDateTime and Instant are also immutable and thread-safe, just like the ZoneId & DateTimeFormatter. You can cache all of these, and use them across threads.
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, 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.
Apache Commons Lang has FastDateFormat, which solves the problem the right way (in my opinion), by just being threadsafe to begin with:
FastDateFormat is a fast and thread-safe version of SimpleDateFormat.
This class can be used as a direct replacement to SimpleDateFormat in most formatting situations. This class is especially useful in multi-threaded server environments. SimpleDateFormat is not thread-safe in any JDK version, nor will it be as Sun have closed the bug/RFE.
You should be really careful with something like that. The standard (simple) formaters are not threadsafe. I've ran into some multithread related issues with some shared/cached formaters, but that was some years ago (Java 1.4). If you check the JavaDocs (SimpleDateFormat), you will notice the following:
Synchronization
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
I have one Calendar object which is as per the user's time zone which may be PST etc, now i want to convert the same to GMT and retain the time i.e. is the calendar initially was set # 00:00:00 at PST it should be converted to 08:00:00 after the conversion taking into consideration the time/date difference . Can someone provide me some help on this.
Appreciate the help in advance.
Thanks,
Vaibhav
Just create a new Calendar in GMT, set the time in that calendar to the same as the original calendar, and you're done:
gmtCalendar.setTime(userCalendar.getTime());
That should be fine, as the getTime() call returns the instant in time (i.e. a java.util.Date with no associated time zone).
As ever though, if you're doing any significant amount of date/time work in Java you should strongly consider using Joda Time instead.
tl;dr
( ( GregorianCalendar ) myCal ) // Cast from a general `Calendar` to specific subclass `GregorianCalendar`.
.toZonedDateTime() // Convert from troublesome legacy class to modern java.time class, `ZonedDateTime`.
.toInstant() // Extract a UTC-specific value, an `Instant` object.
java.time
The modern approach uses java.time classes.
Convert your legacy Calendar object (if GregorianCalendar) to a ZonedDateTime. Call new conversion methods added to the old classes.
GregorianCalendar gc = ( GregorianCalendar ) myCal ;
ZonedDateTime zdt = gc.toZonedDateTime() ;
Now extract an Instant, a value always in UTC. You can think of it this way conteptually: ZonedDateTime = ( Instant + ZoneId )
Instant instant = zdt.toInstant() ;
For more flexibility such as generating strings in various formats, convert to an OffsetDateTime object.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
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.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java 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 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, 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.