Up until now we have been using joda-time class DateTime to represent date-time data with UTC timezone, and this meets our requirements nicely.
Example: 2014-11-07T14:10:00Z
Now, we have a requirement to represent "date" data (in UTC timezone).
Example: 2014-11-07
There exists a LocalDate joda-time class, and a method to convert from DateTime via DateTime.toLocalDate().
I looked for a joda-time class which I thought would exist DateUTC - but it doesn't seem to exist!
Can someone please point me in the right direction, or in fact specify what is the best joda-time class for representing "date-UTC" data (without timestamp) ?
P.s. we are not ready to move to java 8 yet, since we have a lot of code using joda-time library
If your DateTime object is in UTC, converting it to LocalDate is fine if you don't care about time. If it's not already in UTC, you can convert it to UTC using DateTime.withZone(DateTimeZone.UTC).toLocalDate()
LocalDate represents only the date components, without timezone information. Therefore, your code can just use it and assume it's in UTC, as long as you're consistent. For a string representation, you can use LocalDate.toString().
However, if all you want is to format your existing DateTime object so that the string representation only shows the date components, then you shouldn't need to use LocalDate. Just format it to only show the dates: DateTime.toString("yyyy-MM-dd").
Related
I have to convert a date (that is already in UTC) to a java.sql.Timestamp.
Issue
But when doing that, the time is changed to machine time:
new Timestamp(date.getTime());
So I get another date on the server.
Expected
When I convert back to Date I want to have the same date as before conversion.
I want to keep the same date (in UTC).
How could I do that?
It does not change the time. Timestamp and Date don't have a concept of a timezone, they represent an instant of time since the Epoch(1970-01-01T00:00:00Z).
Their .toString() methods on the other hand, have the bad habit of applying the default timezone of the JVM, when generating the string representation. I would advise to stay away from those classes, and instead use java.time, the modern java datetime API, it's available since java 8.
I've an input string as
2020-01-21T02:16:51.8320Z
I need to parse this string into a java Date object.
I tried using following code.
LocalDate localDate = LocalDate.parse(date, flexUtcDtf);
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
Output:
Wed Jan 22 00:00:00 EST 2020
Is it possible to get the output as following Date object instead?(i.e. preserving the time details as well)
Wed Jan 21 02:46:51.8320 EST 2020
Thanks.
java.util.Date
.from(
Instant.parse(
"2020-01-21T02:16:51.8320Z"
)
)
.toString()
Beware of data loss. Your input has a fourth digit of decimal fraction of a second. That means microseconds. The Instant class can handle that. But the legacy Date class you asked for cannot, and is limited to milliseconds. So any microseconds will be lopped off, truncated to milliseconds.
The terrible legacy classes such as java.util.Date have been given new methods to facilitate converting back and forth between the modern java.time classes. Here we are using Date.from( Instant ) to produce a legacy date from the modern Instant parsed from your input.
Beware that Date has many flaws and problems. Among those is the behavior of its toString method. That method takes the value of the Date which is a moment in UTC, and then applies the JVM’s current default time zone while generating the text. This creates the illusion of that time zone being part of the Date.
I suggest you avoid Date entirely, and use only the java.time classes. But my code here answers the Question as asked.
Also, your desired output format is a terrible one. Instead, use ISO 8601 standard formats for data exchange. For presentation to the user, use DateTimeFormatter.ofLocalizedDateTime. Both of these topics have been addressed many times on Stack Overflow, so search to learn more.
First - congratulations on using the Java 8 time functions - wise choice!
Per your question:
This is the way to convert "LocalDate" to "java.util.Date":
Date myDate = Date.from(localDate.atZone(ZoneId.systemDefault()).toInstant());
... or ...
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
Per the documentation:
https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
LocalDate is an immutable date-time object that represents a date,
often viewed as year-month-day. Other date fields, such as
day-of-year, day-of-week and week-of-year, can also be accessed. For
example, the value "2nd October 2007" can be stored in a LocalDate.
This class does not store or represent a time or time-zone. Instead,
it is a description of the date, as used for birthdays. It cannot
represent an instant on the time-line without additional information
such as an offset or time-zone.
So a better choice might be LocalDateTime
In either case, "java.util.Date" automatically has "everything you need". It is a "date/time" object. It stores date and time, irrespective of any time zone.
I am developing a library to store complex data in an Object. One of the field in this object is a date. When I set the date using setter method, it is assumed that the date object is in GMT timezone. Internally, the Date is stored as a long with the number of milliseconds from epoch. In my get() method, I am doing the following :
return new Date(storedDateinMilliseconds);
The problem is that if anyone is calling toString() on the returned object, it uses the default timezone to return the date. Therefore, the returned date does not always match with the date provided in GMT. Is there a way to fix this? so that the user of this implementation will always get the GMT date when they invoke toString()?
I tried the following :
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
But this would modify the default timezone of the application using it.
As Sotirios Delimanolis’ comment said, you are giving a java.util.Date object to the calling programmer. What she does with it is up to her. And it is up to her to understand all the goofy problems that come with that object including its toString method applying the JVM’s current default time zone in generating a string representation of its date-time value.
If you want to return a date-time value with an assigned time zone, then return a different object.
Alternative Date-Time Objects
You have at least three alternatives to returning a java.util.Date object.
java.time
In Java 8 and later, the obvious choice is to use the new java.time framework (Tutorial). Give the calling programmer a ZonedDateTime object which is basically a Instant object plus a ZoneId object.
Tip: When specifying a time zone, use a proper time zone name. Never use the 3-4 letter codes like EST or IST.
Joda-Time
Joda-Time was the inspiration for java.time. This 3rd-party library is excellent, and well-worn from popular use. It supports multiple versions of Java and Android too.
The DateTime class is a moment on the timeline plus a time zone, similar to java.time’s ZonedDateTime.
ISO 8601
A third alternative is to give the calling programmer a string representation of a date-time value. The obvious choice of formats is to use those defined by the ISO 8601 standard. These formats are sensible, well thought-out, and unambiguous.
2015-09-16T18:06:14Z
…or…
2015-09-16T11:06:14-07:00
Both java.time and Joda-Time use these formats by default in parsing and generating strings. The formats are wisely extended by java.time to append the proper name of the time zone in square brackets.
2015-09-16T11:06:14-07:00[America/Los_Angeles]
Never Adjust Default Time Zone
You stated that setting the default time zone affected your entire app. Wrong. It affects all code of all apps in all threads running in that JVM. Worse, it does so immediately during runtime while that other code is running.
Set the default time zone only as a last resort when all other approaches to resolve a date-time problem have been exhausted. This is rare. The usual solution is to:
Use java.time or Joda-Time.
Always specify the desired/expected time zone rather than rely implicitly on the default.
Use UTC in most of your business logic, data storage, and data exchange.
Avoid whenever possible the mess that is java.util.Date/.Calendar.
Search StackOverflow
All of these topics have been discussed many times over on StackOverflow.com. Please search for more information and examples.
AFAIK, you have 2 options:
Option 1. This may sound like an overkill, but you could roll out your own Date object just for this complex class of yours, and overwrite the toString() method. Maybe something like
public class GMTDate extends java.util.Date {
#Override
public String toString() {
//return GMTDate
}
}
Option 2: Keep your date as java.util.Date, but don't expose a public getter for it. Expose instead a public getter that returns your date in GMT format, and maybe a public getter that returns your date as a long (with the number of milliseconds from epoch)
EDIT:
And a 3rd option: AspectJ. You can use aspect oriented programming to intercept calls to the toString() method and return a GMT string date
Relevant Stack Overflow Question: AspectJ: Intercept method execution/call and make it return
I am struggling on this for days.
I have a date field, that gives a date on 'yyyy-MM-dd' format.
My Object have this field like this
#Temporal(TemporalType.DATE)
private Date finishdate;
I am on UTC, and this need to work all over the world, so on UTC-7 or UTC+7
On DataBase this value need to be store with 0 hours.
When the finishdate is filled, the format give me the timezone, so, for example:
I want 2014-10-01, with ZERO HOURS AND MINUTES AND SECONDS, on diferent timezones I catch:
2014-10-01 07:00:00:000
or
2014-09-01 17:00:00:000
The problem seams to be because of the Date liybrary, and i've found a solution with JODA Library, but i was told not to used it, and I need to find another solution.
So, need to convert to UTC Date, all dates,or other thing, but the day must be the same, like 1 October.
Anyone pass through this?
The Joda-Time library fixes issues like this, and I believe that is also the basis of the java.time package in Java 8, but for older Java versions this kind of problem occurs constantly.
The only consistent way I have seen for dealing with this without Joda time is to treat pure dates as a String ("2014-10-01") or Integer type (20141001) instead of a Date. and only convert to dates when needed in calculations. It is a real pain though.
Don't forget that SimpleDateFormat is not thread-safe. The answer saga56 gives may work but you'll have some very weird dates if there's any simultaneous use of the deserialiser. You need to 'new' the SimpleDateFormats each time, or (less favourably) do something else to ensure SimpleDateFormat is strictly limited to 1 thread at a time.
Solution to this issue.
We made an Custom Deserializer to every object of the type Date.
On ObjectMapperFactory, where we serialize or deserialize, i mapped to another class like this:
module.addDeserializer(Date.class, new DateDeserializerByDefault());
Then, on this class we did:
private static SimpleDateFormat dateFormatWithoutTimezome = new SimpleDateFormat("yyyy-MM-dd");
private static SimpleDateFormat dateFormatWithTimezone= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
private static Pattern pattern = Pattern.compile("([0-9]{4})-([0-9]{2})-([0-9]{2})");
#Override
public Date deserialize(JsonParser jparser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String content = jparser.getValueAsString();
DateFormat format=(pattern.matcher(content).matches()) ? dateFormatWithoutTimezome : dateFormatWithTimezone;
try {
return format.parse(content);
} catch (ParseException e) {
throw new JsonParseException("Date parse failed", jparser.getCurrentLocation(),e);
}
}
And with this, when we receive Dates on diferent format, or with timezone to be stor we can change it to what we want.
I Hope this solution can help, I was stuck on this for 3,5 days. Dates are a pain in the a**.
The other Answers are correct but outdated.
java.time
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat. The Joda-Time team also advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
LocalDate
A LocalDate represents a date-only value without time-of-day and without time zone.
Your input string is in standard ISO 8601 format, so it can be parsed directly by LocalDate. No need to specify a formatting pattern.
String input = "2014-10-01";
LocalDate localDate = LocalDate.parse( input );
ZonedDateTime
You assume the day starts at time 00:00:00. But that is not always the case. In some time zones Daylight Saving Time (DST) or possibly other anomalies can mean the day starts at some other time on the clock such as 01:00:00. Let java.time determine the starting time of the first moment of a day. Specify a time zone, and assuming the tz database bundled with Java is up-to-date, then a call to LocalDate::atStartOfDay produces a ZonedDateTime for your date and first moment.
ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = localDate.atStartOfDay( zoneId );
If you want the first moment of the day in UTC, specify the constant ZoneOffset.UTC (ZoneOffset being a subclass of ZoneId).
ZonedDateTime zdt = localDate.atStartOfDay( ZoneOffset.UTC );
Alternatively, use the more appropriate OffsetDateTime class. This is for values with a mere offset-from-UTC but lacking the set of rules for handling anomalies such as DST found in a full time zone. In UTC the day always starts at 00:00:00 which is stored in a constant LocalTime.MIN.
OffsetTime ot = OffsetTime.of( LocalTime.MIN , ZoneOffset.UTC );
OffsetDateTime odt = localDate.atTime( offsetTime );
Database
For database work, if you want a date-only value stored you should be using a data type along the lines of the SQL Standard type of DATE.
For a date-time value, nearly every serious database converts incoming data into UTC for storage in a TIMESTAMP WITH TIME ZONE type column. Your JDBC driver should help with this. But test and experiment as the behavior of drivers and databases varies tremendously.
With JDBC 4.2 and later, you may be able to pass/fetch the java.time types directly via setObject/getObject. If not, convert to java.sql types via new methods added to the old classes.
Which data type in Java can hold just the date and doesn't require a time component? For example, just to store 12/07/2012. I'm working with persisting the data to/from a database that has a date-only data type, so I'm looking for the best equivalent data type in Java.
from the JDK: java.sql.Date:
A thin wrapper around a millisecond value that allows JDBC to identify
this as an SQL DATE value. A milliseconds value represents the number
of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.
To conform with the definition of SQL DATE, the millisecond values
wrapped by a java.sql.Date instance must be 'normalized' by setting
the hours, minutes, seconds, and milliseconds to zero in the
particular time zone with which the instance is associated.
or from JodaTime: DateMidnight or LocalDate (thanks
#cdeszaq)
DateMidnight defines a date where the time component is fixed at
midnight. The class uses a time zone, thus midnight is local unless a
UTC time zone is used.
It is important to emphasise that this class represents the time of
midnight on any given day. Note that midnight is defined as 00:00,
which is at the very start of a day.
The other answers are out-dated.
The old date-time classes are notoriously troublesome and should be avoided.
java.time
The java.time framework is built into Java 8 and later. See Oracle Tutorial. Much of the java.time functionality is back-ported to Jave 6 & 7 and further adapted to Android.
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate localDate = LocalDate.of( 2012 , 12 , 7 );
Textual representation
The toString method generates a String using standard ISO 8601 format.
localDate.toString() → 2012-12-07
For other formats use DateTimeFormatter.
SQL
JDBC drivers compliant with JDBC 4.2 can use the getObject and setObject methods to directly fetch/pass the java.time types such as LocalDate to SQL type DATE.
If your driver cannot do so, fall back to using the java.sql types. New methods have been added to the old classes to facilitate conversion.
java.sql.Date sqlDate = java.sql.Date.valueOf( localDate );
And the other direction.
LocalDate localDate = sqlDate.toLocalDate();
Search Stack Overflow
Search Stack Overflow for many more discussions and examples of using java.time. For example, my answer to this similar Question.
Date class. It holds a UNIX timestamp. In most databases, you can specify a field to hold a timestamp as well. You can use DateFormat to format the timestamp however you want.
If you are using Java 8, you can use java.time.LocalDate.
Use Date class that is available.
It shows how hold only date(without time)
formatter = new SimpleDateFormat("dd/MM/yyyy");
Date date= new Date();
Date todayWithOutTime =formatter.parse(formatter.format(date));
Unfortunatelly, java.util.Date is something, that in SQL have name Timestamp. There's no pure type for Date only, javax.sql.Date extends java.util.Date and using this type for date manipulation in Java gives you no advantage.
I'm dealing with this using apache commons-lang class DateUtils:
Date myDate = DateUtils.truncate(timestamp, Calendar.DAY_OF_MONTH);
This will remove the time part and leave only date part.
Use Date class. This is the better way.