Convert java.util.Date to different time zone requested - java

Depending on a request url, I have to convert a Date to different requested time zone and return date and time as String. I am using java 8 with spring boot and mongo 3.2
So inside the service method, I first set the time zone as below,
TimeZone.setDefault(TimeZone.getTimeZone(TIME_ZONE))
But I notice, it will change the time zone of whole java application. So even the method exit, the time zone would be remain the time zone I set previously.
So instead setDefault method level, I set it specifically in the SimpleDateFormat as below,
(assignment is a Assignmet document class having java.util.Date as a property named assignmentEndDate which map to a mongodb collection. In mongo db assignmentEndDate is store as UTC)
java.text.DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy'T'HH:mm:ss.SSS");
formatter.setTimeZone(TimeZone.getTimeZone(timezone));
Date assignmentEndDate = assignment.getAssignmentEndDate();
formatter.format(assignmentEndDate);
This way it wont change the application level time zone. Is this the correct approach for such scenario?

Take advantage of new date time api included in Java 8.
ZoneId zoneId = ZoneId.of("America/Chicago");
You can start with Instant, a java util date equalivent.
Instant instant = Instant.now();
ZonedDateTime zonedDateTime = instant.atZone(zoneId);
Or
You can also start with
using ZonedDateTime
You can take datetime as LocalDateTime, time zone agnostic class and convert to ZonedDateTime.
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(zoneId);
You can easliy switch betweeen old date time classes & new time by accessing the helper methods on each of the new/old date time classes.
Change to java util date while saving to mongo database
//From ZonedDateTime to java util date.
Date oldDate = Date.from(zdt.toInstant());
//From Instant to java util date
Date oldDate = Date.from(instant);
//From Date to Instant.
Instant instant = date.toInstant();
All the new date time api have default formatter built into it.
//2007-12-03T10:15:30-06:00[America/Chicago]
String zonedDatetime = zonedDateTime.toString();
For specfic format you can always pass the DateTimeFormatter to the below method.
zonedDateTime.format(formatter)

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.

How to format time objects in Java into the correct timezone

I want to use the Java Time API to get the central Europen summer time (CEST) and format it correctly. I have the following code:
LocalDateTime localDateTime= LocalDateTime.now();
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
localDateTime.format(myFormatObj);
ZoneId europeBerlin = ZoneId.of("Europe/Berlin");
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, europeBerlin);
The command zonedDateTime.toString()leaves to the following output:
2020-09-27T08:42:33.660+02:00[Europe/Berlin]
But I would like to have an output as specified before in the DateTimeFormatter ("dd-MM-yyyy HH:mm:ss"). I have already formatted the localDateTime into this format and now I just want to get the CEST time. How can I do that? I'd appreciate every comment.
Please note that date-time objects from the Java Time API are immutable. Therefore, whenevery you want to modify an existing date-time instance, a new fresh copy is returned, leaving the old one untouched.
Also, a minor optimization: DateTimeFormatter is thread-safe. Thus, there is no need to construct a new instance every time, since the format is constant. You could declare it at the top like this:
private static final DateTimeFormatter FORMATTER;
static {
FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
}
To print a formatted String, use the following:
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId europeBerlin = ZoneId.of("Europe/Berlin");
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, europeBerlin);
// please note that #format has a return value
// originally, you called 'localDateTime.format(myFormatObj);' while ignoring
// the return value
String formatted = FORMATTER.format(zonedDateTime);
System.out.println(formatted); // e.g. 27-09-2020 11:44:27
Edit 1: Regarding thread-safety
Thread-safety refers to when an object can safely be used by mutliple threads concurrently, without breaking internals of the class. If a class is thread-safe, you can call it from mutliple threads at the same time (therefore you do not need to create a new instance every time, but only one). If a class is not thread-safe, a new instance is needed for each thread.
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
ZoneId europeBerlin = ZoneId.of("Europe/Berlin");
ZonedDateTime zonedDateTime = ZonedDateTime.now(europeBerlin);
String formattedDateTime = zonedDateTime.format(myFormatObj);
System.out.println(formattedDateTime);
Output when running in UTC time zone just now:
27-09-2020 20:33:53
We got the Berlin time (not the UTC time).
What went wrong in your code?
Two things:
LocalDateTime.now() gives you the current time in the default time zone of the JVM. It seems that this was not Eurpoe/Berlin (perhaps it was UTC, it could be something else). Then ZonedDateTime.of(localDateTime, europeBerlin) takes that date and time of day and claims that it is Europe/Berlin time zone, which is wrong and the reason why you got an incorrect result. You don’t often need the LocalDateTime class and virtually never the no-arg LocalDateTime.now() method.
To get the time in a specific format you need to format the date and time into a string. The LocalDateTime and the ZonedDateTime objects haven’t got any format.
Links
Related questions:
Can’t rid of 'T' in LocalDateTime
String to ZonedDateTime is changing format

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));
}

XMLGregorianCalendar to GregorianCalendar

I was simply trying to convert the instance of XMLGregorianCalendar (which I got from JAXWS) to GregorianCalendar in specific TimeZone using below code.
The date is coming in EST and I want to convert it into GMT for further saving to DB
//soap response <ns4:TimeStamp>2016-06-18T04:43:54-04:00</ns4:TimeStamp>
//dtime is what i got from JAXB for the above date, so I wrote::
Date date = dTime.toGregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.US, null).getTime();
System.out.println(date);
Output: Sat Jun 18 14:13:54 IST 2016
Since above is not working as expected so i tried DateFormat and its giving the expected result.
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
GregorianCalendar gc = dTime.toGregorianCalendar();
System.out.println(df.format(gc.getTime()));
Output: 2016-06-18 08:43:54 +0000
What could be the issue here as toGregorianCalendar(...) is not giving the desired result?
Also I noticed the GregorianCalendar instance obtained above from toGregorianCalendar has fieldSet= false. Not sure if this is causing the issue.
java.util.GregorianCalendar[time=1468382241000,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=6,WEEK_OF_YEAR=29,WEEK_OF_MONTH=3,DAY_OF_MONTH=12,DAY_OF_YEAR=194,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=11,HOUR_OF_DAY=23,MINUTE=57,SECOND=21,MILLISECOND=0,ZONE_OFFSET=-14400000,DST_OFFSET=0]
Any help will be appreciated..!!
tl;dr
myPreparedStatement
.setObject( // Exchange java.time objects with your database in JDBC 4.2 and later.
… , // Specify which `?` placeholder in your SQL statement.
myXMLGregorianCalendar // A legacy class. Better to use *java.time* whenever possible.
.toGregorianCalendar() // Convert from the one legacy class to another, as a bridge towards the modern `ZonedDateTime` class.
.toZonedDateTime() // Convert to the modern class.
.toInstant() // Adjust from a time zone to UTC. Same moment, same point on the timeline, different wall-clock time.
.atOffset( // Adjust from basic `Instant` class to the more flexible `OffsetDateTime` class, if your JDBC driver does not offer the optional support for `Instant`.
ZoneOffset.UTC // Specify UTC using this constant.
) // Returns a `OffsetDateTime` object.
)
java.time
You are using terrible old date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310.
convert the instance of XMLGregorianCalendar (which I got from JAXWS) to GregorianCalendar
First call XMLGregorianCalendar::toGregorianCalendar().
GregorianCalendar gc = myXMLGregorianCalendar.toGregorianCalendar() ;
Convert from the legacy class GregorianCalendar to the modern java.time.ZonedDateTime. Call the new conversion method added to the old class.
ZonedDateTime zdt = gc.toZonedDateTime() ;
date is coming in EST and I want to convert it into GMT
The java.time.Instant class represents a moment in UTC, always in UTC. You can extract an Instant from the ZonedDateTime. Same moment, different wall-clock time.
Instant instant = zdt.toInstant() ;
for further saving to DB
You may be able to pass an Instant to the database if your JDBC driver supports that. The Instant type is optional in JDBC 4.2.
myPreparedStatement.setObject( … , instant ) ;
If not supported, use OffsetDateTime as support is required by JDBC 4.2.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
The date is coming in EST
EST is not a real time zone.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Remember that Java Date objects don't have a time zone. They are internally in UTC. Time zone only manifests when printed (formatted).
This simple code works:
XMLGregorianCalendar xmlCal = XMLGregorianCalendarImpl.parse("2016-06-18T04:43:54-04:00");
GregorianCalendar cal = xmlCal.toGregorianCalendar();
java.util.Date date = cal.getTime();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(format.format(date)); // prints: 2016-06-18 08:43:54
Since your goal is to save it to a database, you really don't care about formatting it to text. Assuming you're using JDBC (not some NoSQL), you need a Timestamp.
XMLGregorianCalendar xmlCal = XMLGregorianCalendarImpl.parse("2016-06-18T04:43:54-04:00");
GregorianCalendar cal = xmlCal.toGregorianCalendar();
java.sql.Timestamp date = new java.sql.Timestamp(cal.getTimeInMillis());
Now you can give that to a PreparedStatement using setTimestamp().
I'm using the following code to convert an XMLGregorianCalendar from a given source with a given timezone (e.g. GMT+0) to a GregorianCalendar with the current system timezone :
GregorianCalendar.from(xmlGregorianCalendar
.toGregorianCalendar()
.toZonedDateTime()
.withZoneSameInstant(ZoneId.systemDefault()))
When you use only XMLGregorianCalendar.toGregorianCalendar(), the returned GregorianCalendar has the same timezone as the source system, not the timezone of the current system. Converting the timezone when you receive the data is safer: this way, you reduce the number of potential issues in your code because all dates are based on the system timezone.
For example:
XMLGregorianCalendar xmlGregorianCalendarFromSource = DatatypeFactory.newInstance()
.newXMLGregorianCalendar("1983-09-30T23:00:00.000Z"); // the source system is on GMT+0
GregorianCalendar gregorianCalendarWithSourceTZ = xmlGregorianCalendarFromSource.toGregorianCalendar();
GregorianCalendar gregorianCalendarWithSystemTZ = GregorianCalendar.from(xmlGregorianCalendarFromSource
.toGregorianCalendar()
.toZonedDateTime()
.withZoneSameInstant(ZoneId.systemDefault()));
System.out.println(xmlGregorianCalendarFromSource); // displays "1983-09-30T23:00:00.000Z" (i.e. GMT+0)
System.out.println(gregorianCalendarWithSourceTZ.toZonedDateTime()); // displays "1983-09-30T23:00Z[GMT]" (i.e. GMT+0)
System.out.println(gregorianCalendarWithSystemTZ.toZonedDateTime()); // displays "1983-10-01T00:00+01:00[Europe/Berlin]" (my system timezone is GMT+1 or GMT+2 depending on daylight saving)
As another route, you could consider using Date's instead of XMLGregorianCalendars in your code by using jaxb bindings as discussed in this stack overflow question.

Creating timestamps and dates in java

There are many java classes that handle time (date, calander..etc) and there are even more references and tutorials online which makes it all very confusing and I don't know which class to use when.
Can anyone give me straightforward statements to do the following:
Create an instance of a timestamp to keep track of transactions on a database
Create an object that holds today's date in DD/MM/YY format (or anything similar)
Create an object that holds ANY given date in DD/MM/YY format (or anything similar)
Much appreciated!
Ans1
You can get current date using.
Date date = new Date();
In SQL you can mark the date field to update to current time automatically.
Ans2
SimpleDateFormat allows a variety of date formats. An example usage is:
Date d = new Date(secondsSunceEpoch);
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yy");
String time = df.format(d);
Ans3
Use parse method from SimpleDateFormat for any string would work.
try {
DateFormat todaysDateFormat = new SimpleDateFormat("dd/mm/yy");
Date date = new Date();
//2. datestring hold your today's object in DD/MM/YY format
String datestring = todaysDateFormat.format(date);
System.out.println("datestring "+datestring);
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/mm/yy");
java.util.Date parsedDate;
parsedDate = dateFormat.parse(datestring);
Timestamp timestamp = new java.sql.Timestamp(parsedDate.getTime());
//1. Create an instance of a timestamp to keep track of transactions on a database
System.out.println(timestamp); // Use this time stamp as today's date foramt
// 3.Create an object that holds ANY given date in DD/MM/YY format
SimpleDateFormat dateFormat3 = new SimpleDateFormat("dd/mm/yy");
java.util.Date parsedDate3;
parsedDate3 = dateFormat.parse("30/12/14"); // any given date
String anyDatestring = todaysDateFormat.format(date);
// it will hold any date string
}catch (ParseException e) {
e.printStackTrace();
}
The other Answers are correct but outdated. They use troublesome old legacy classes. Instead use java.time classes.
1
Create an instance of a timestamp to keep track of transactions on a database
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
In Java 8 the current moment is captured with milliseconds resolution. In Java 9, up to nanosecond resolution. In both versions of Java, the Instant class is capable of holding a nanosecond value.
Instant now = Instant.now();
In JDBC 4.2 and later, exchange with your database via the PreparedStatement::setObject and ResultSet::getObject. If your driver cannot do so, convert to a java.sql.Timestamp.
java.sql.Timestamp ts = java.sql.Timestamp.from( instant );
Going the other direction.
Instant instant = ts.toInstant();
2
Create an object that holds today's date in DD/MM/YY format (or anything similar)
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
To generate a String you can specify a formatting pattern, or just let DateTimeFormatter localize. A Locale determines (a) the human language used for translation, and (b) the cultural norms for deciding issues like capitalization, abbreviation, and punctuation.
DateTimeFormatter f = DateTimeFormatter.ofLocalizeDate( FormatStyle.SHORT ).withLocale( Locale.UK );
String output = today.format( f );
3
Create an object that holds ANY given date in DD/MM/YY format (or anything similar)
Do not conflate a date-time object with a String representation of that date-time value. The object can parse or generate such strings but is separate and distinct from the string.
So we already saw the solution above: a LocalDate object holds the date-only value. When needed for presentation to the user, generate a String to represent the value.
By the way, calling toString gets you a String in standard ISO 8601 format, YYYY-MM-DD.
String output = localDate.toString();
The java.time classes follow the immutable object pattern. So you do not modify an existing object to alter part of its value. Instead you create a new object with parts of its value based on the original object.
LocalDate tomorrow = today.plusDays( 1 );

Categories