Spring's #DateTimeFormat produces a Date object with the previous day - java

I've got a requestParam that takes in a date (ie. 2017-01-24T06:00:00.000Z).
I'm using DateTimeFormat to format it into a date to pass into my controller.
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date myDate
but when I print myDate to my console I get "Mon Jan 23, 18:00:00 CST 2017", but in my example above it should be Jan 24th. Why is it changing my date back 1 day?

There are several things at play here.
First, Spring's #DateTimeFormat, when annotating a java.util.Date field or parameter, uses a SimpleDateFormat with its timezone set to UTC.
Second, you've used DateTimeFormat.ISO.DATE which represents
The most common ISO Date Format yyyy-MM-dd, e.g. "2000-10-31".
In other words, it does not consider any timezone information in your date string (this doesn't really matter because your date string was rooted at Zulu anyway).
Third, you've provided a date string where everything but the iso pattern gets ignored. The SimpleDateFormat only cares about the 2017-01-24 part.
Since the timezone is set to UTC, it considers the 2017-01-24 date as being rooted at UTC, at midnight, zero'ed hours, minutes, and seconds.
Finally, since your system's default time zone is Central Standard Time, ie. UTC-6), when you call toString on the Date object, it'll return a String that is formatted with that time zone, ie. 6 hours before midnight.
Remember also that a Date has no concept of a timezone. It is a timestamp.
To "fix" this, construct your #DateTimeFormat with an appropriate pattern that interprets both time and time zone. I would use
#DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX") Date myDate

For me it works without #JsonFormat when json has the pattern 'yyyy-mm-dd'
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate startDate;

If you want to configure the time zone in general you can use the following:
spring.jackson.time-zone=EST
The documentation indicates: "Time zone used when formatting dates. For instance, 'America/Los_Angeles' or 'GMT+10'".

This will work. Tried and tested
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
#JsonFormat(pattern = "MM/dd/yyyy")
private LocalDate startDate;

Related

Selenium java Date Time validation issue

I have a requirement where I have to extract the date and time displayed on the screen, which is in following format: 2021 Jul 12 # 06:30
And I have to compare this with a specific timezone to check whether they are equal or not.
Can anyone please help me with the way to handle this logic in Selenium Java (any version)?
Assuming you are retrieving the date time as a string, you can use a combination of ZonedDateTime and LocalDateTime as follows:
First we get your system zone and zoned datetime:
ZoneId timeZone = ZoneId.systemDefault();
LocalDateTime nowLocalDateTime = LocalDateTime.now();
ZonedDateTime nowZonedDateTime = ZonedDateTime.of(localDateTime, timeZone);
Then we define the pattern using formatter, and use it to format the example string to a ZonedDateTime object:
DateTimeFormatter exampleFormatter = DateTimeFormatter.ofPattern("yyyy MMM dd # HH:mm");
String example = "2021 Jul 12 # 06:30";
ZonedDateTime exampleZonedDateTime = LocalDateTime.parse(example, formatter).atZone(timeZone);
Here, I used the system timezone but you can change this to the zone you like assuming you know the time zone of the example.
This way we can compare exampleZonedDateTime with nowZoned DateTime where:
nowZonedDateTime holds the systems current defined timezone
exampleZonedDateTime holds the Zoned date time you want to compare with.
Also you can convert both to LocalDateTime objects using .toLocalDateTime() method in the ZonedDateTime class.

#JsonFormat converts Date with incorrect timezone

I have a simple POJO with a Date field with initial value coming in:
1985-09-17T01:00:00.000+0400
then this Date value gets mapped to a DTO with the Date field annotated:
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssX")
private Date dateOfBirth;
Then the result is shown:
1985-09-16T21:00:00Z
I have tried setting the timestamp property in #JsonFormat, but that didn't help and the date is still invalid.
How can I correctly convert the date?
The value within a java.util.Date is the number of milliseconds since the Unix epoch, which occurred at midnight January 1st 1970, UTC. As it's a number of milliseconds since a fixed epoch, the value within java.util.Date is the same around the world at any particular instant, regardless of local time zone.
So in your case it's better to use ZonedDateTime class if you use java 8 ZonedDateTime
Both dates represents the same instant:
1985-09-17T01:00:00.000+0400
1985-09-16T21:00:00Z
When you print dates in java it uses the current timezone of the VM, but internally the Date class stores that information in a long representing the time in milliseconds since the epoch.
If you like you can get the a String representation of the date using a custom timezone using the setTimeZone method of DateFormat:
Sets the time zone for the calendar of this DateFormat object.
Here a simple snippet of code:
Date date = ...
DateFormat formatter = ...
TimeZone timeZone = ...
// Set a custom timezone
formatter.setTimeZone(timeZone);
// Get a string representation of the daet with a custom timezone
String formattedDateWithCustomTimezone = formatter.format(date);

convert UTC timestamp to any other zone timestamp

I'm using MongoDB to store my data. Mongo stores timestamps in UTC as a default.
We process data in different time zones. I'm struggling to convert UTC timestamp to PDT or IST timestamps.
Trying to construct a method to pass timezone(into which my timestamp is to be converted) and timestamp(UTC). Method to return the timestamp of specified time zone.
public Date getDateBasedOnZone(Date date, "America/Los_Angeles") {
return dateInAmerica/Los_Angeles;
}
You could use something like the following to get the time in a particular zone:
date.toInstant().atZone( ZoneId.of( "America/Los_Angeles" ) )
A java.util.Date object does NOT contain timezone information so it's impossible to convert from one timezone to another in a java.util.Date (it doesn't make sense). It's simply a wrapper around long which is milliseconds since EPOCH.
You only start seeing timezone in java.util.Calendar or when a java.util.Date is converted to String.
There's also Joda-Time which has far better date API's than the core Java libraries.
You can use a dateformat with the required timezone and apply it to the date
public Date convertToZone(Date date, String tz) {
DateFormat TFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
TFormat.setTimeZone(TimeZone.getTimeZone(tz));
return df.parse(currentTFormat.format(date));
}

In Java, Can the Date type just hold MM-dd-yyyy or just hh:mm:ss?

I am converting epoch format time to the normal format, but when I convert it to date I get, MM-dd-yyyy hh:mm:ss.
If I want to single out just the date or the time I have to use SimpleDateFormat. But this returns a String. I was wondering if there was a way to make this string a Date type.
The type java.util.Date is actually a timestamp, it is not much more than a wrapper for a number of milliseconds since 01-01-1970, 00:00:00 UTC. (The class name Date is unfortunately badly chosen).
It is not very well suited for holding just a date or just a time value.
If you are using Java 8, use the new date and time API (package java.time); use for example LocalDate if you need to store a year/month/day, or a LocalTime if you need to store just a time-of-day (hours, minutes, seconds, milliseconds).
If you are using Java 7 or older, consider using the equivalent classes in the Joda Time library.
You can format the date as MM-dd-yyyy HH:mm:ss not (MM-dd-yyyy hh:mm:ss)
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
DateFormat dateformat= new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
Date date = dateformat.parse("01-25-1988 23:54:59");
System.out.println(date);
System.out.println(dateformat.format(date));

Convert LocalTime (Java 8) to Date

I'm trying to convert a java.time.LocalTime object to java.util.Date but can't find any suitable method. What's the correct way to do this?
Is there any reason why java doesn't seem to ship with a built-in direct conversion method?
To possible duplicates:
How to convert joda time - Doesn't work for me, probably I'm missing some "joda" libraries?
How to convert Date to LocalTime? - This adresses conversion the other way around.
LocalTime actually can't be converted to a Date, because it only contains the time part of DateTime. Like 11:00. But no day is known. You have to supply it manually:
LocalTime lt = ...;
Instant instant = lt.atDate(LocalDate.of(A_YEAR, A_MONTH, A_DAY)).
atZone(ZoneId.systemDefault()).toInstant();
Date time = Date.from(instant);
Here's a blog post which explains all the conversions between the new and the old API.
There's no simple built-in conversion method, because these APIs approach the idea of date and time in completely different way.
LocalTime lt = ...;
Instant instant = lt.atDate(LocalDate.of(A_YEAR, A_MONTH, A_DAY)).
atZone(ZoneId.systemDefault()).toInstant();
Date time = Date.from(instant);
From :
http://blog.progs.be/542/date-to-java-time
I added the data (hour, minute, second) one by one (from localtime to date):
reta.setHours(vol.getRetard().getHour());
reta.setMinutes(vol.getRetard().getMinute());
reta.setSeconds(vol.getRetard().getSecond());
Note :
reta: Date veriabble ;
vol.getRetard (): localtime variable
As others have said, it’s a problematic question in that a LocalTime and a Date really represent quite different and almost unrelated concepts. A LocalTime is a time of day without time zone, such as 19:45 (or 7:45 PM). A Date is a point on the time line; if it happens to coincide with 19:45 on some date in some time zone, it will not in other time zones.
I believe that the conventional way of misusing (indeed) a Date for an hour of day is setting it to that time of day on January 1, 1970 in the default time zone of the JVM. This practice carries all of the liabilities already mentioned. In particular the JVM default time zone setting can be changed at any time from another part of your program or any other program running in the same JVM. This means that a completely unrelated program may suddenly cause your Date to indicate a different time of day than the one you had initialized it to.
There’s nothing better we can do, so here goes:
LocalTime time = LocalTime.of(11, 0);
Instant timeOnEpochDayInDefaultTimeZone = LocalDate.EPOCH
.atTime(time)
.atZone(ZoneId.systemDefault())
.toInstant();
Date oldfashionedDateObject = Date.from(timeOnEpochDayInDefaultTimeZone);
System.out.println(oldfashionedDateObject);
In my time zone output from this snippet is:
Thu Jan 01 11:00:00 CET 1970
Here is another approach:
We can add a LocalDate to the LocalTime in order to make it a LocalDateTime and then convert it to Date using the valueOf method of java.sql.Timestamp like this:
LocalTime localTime = LocalTime.now();
Date date = java.sql.Timestamp.valueOf(localTime.atDate(LocalDate.now()));
As #Dariusz said, we cannot convert LocalTime to Date directly as it contains only time part but Date must contain all the value along with the timeZone.
In order to get the date part, we can use LocalDate.now(). It will give us LocalDate object with today's date.
Now, we have both LocalDate and LocalTime, we can now use the LocalDateTime.of(date: LocalDate, time: LocalTime) or localTime.atDate(date: LocalDate) to get the LocalDateTime object.
And now we can convert the LocalDateTime to Date using below kotlin extension function.
fun LocalDateTime.toDate(): Date {
return Date.from(this.atZone(ZoneId.systemDefault()).toInstant())
}

Categories