Get the Gregorian date from a java.sql.Timestamp - java

i have executed a query with entity manager.
it’s returning data from multiple tables. in that case i am getting list of object arrays. so i have written a loop as below.
for (Object[] row : rows) {
row[0]; //row[0] has the date from database as timestamp.
}
here row[0] is a sql Timestamp.
if we evaluate with debugging, i am getting Timestamp with result: 2020-05-27 18:37:39.0.
i can see cdate, a private variable which has value as 2020-05-27T18:37:39.000+0530. it’s the Gregorian date.
i can't use it because it’s a private variable and it is of type BaseCalendar.Date.
if you do something and convert it in to UTC, i am getting as 2020-05-27T13:07:39Z
BUT i want it as 2020-05-27T18:37:39.000+0530

I too recommend that you use java.time, the modern Java date and time API. If you can, modify your query not to return an old-fashioned Timestamp object but rather an Instant or at least a LocalDateTime.
Then you may do for example:
// Example row
Object[] row = { Instant.parse("2020-05-27T13:07:39.000Z") };
System.out.println(row[0]);
ZonedDateTime zdt = ((Instant) row[0]).atZone(ZoneId.systemDefault());
System.out.println(zdt);
Output from this example is, when running in Asia/Kolkata time zone:
2020-05-27T13:07:39Z
2020-05-27T18:37:39+05:30[Asia/Kolkata]
If you can’t change the return type from your query, the correct conversion is:
// Example row
Object[] row = { Timestamp.from(Instant.parse("2020-05-27T13:07:39.000Z")) };
System.out.println(row[0]);
ZonedDateTime zdt = ((Timestamp) row[0]).toInstant()
.atZone(ZoneId.systemDefault());
System.out.println(zdt);
Output is:
2020-05-27 18:37:39.0
2020-05-27T18:37:39+05:30[Asia/Kolkata]
Please note: Don’t use any strings for the conversion, a more direct conversion exists.
I have assumed that you were after that value, not necessarily after the same format that you saw in your debugger. In case you did want that format: What you saw was the result of BaseCalendar.Date.toString(), and it’s a variant of ISO 8601 format, the international standard. To obtain it, use a formatter. For example:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendPattern("HH:mm:ss.SSSxx")
.toFormatter();
String formattedDateTime = zdt.format(formatter);
System.out.println(formattedDateTime);
2020-05-27T18:37:39.000+0530
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601

Use the modern date/time API as follows:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String args[]) {
// Define the format
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
// Parse the date/time string using the defined format
OffsetDateTime odt = OffsetDateTime.parse("2020-05-27T18:37:39.000+0530", formatter);
// Display
System.out.println(odt);
}
}

You can make use of java.time, which enables you to parse the datetime without considering a zone or offset but provides the possibility of adding one afterwards without changing or adjusting the values parsed:
public static void main(String[] args) {
// let's assume you have a timestamp with the following value
Timestamp ts = Timestamp.valueOf("2020-05-27 18:37:39");
// then you can parse it to a datetime that doesn't consider a zone or offset
LocalDateTime ldt = LocalDateTime.parse(ts.toString(),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"));
// print it once
System.out.println(ldt);
// then add an offset without changing / adjusting the time values
OffsetDateTime odt = ldt.atOffset(ZoneOffset.of("+05:30"));
// and print that
System.out.println(odt);
// or use a default format to exactly meet your requirements
System.out.println(odt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")));
}
This outputs
2020-05-27T18:37:39
2020-05-27T18:37:39+05:30
2020-05-27T18:37:39.000+0530

Related

Convert UTC datetime to local datetime using java.time

I have a UTC date-time like this (a String): 2022-11-22T17:15:00
And a ZoneID like this: "America/Tijuana"
Using java.time API, I want to get the actual datetime for that zone, which is: 2022-11-22T09:15:00 (the time is 09:15 instead of 17:15)
ZonedDateTime.toLocalDateTime() returns: 2022-11-22T17:15
ZonedDateTime.toString() returns:
2022-11-22T17:15-08:00[America/Tijuana]
None of the above gives me what I'm looking for.
This is my code:
ZoneId zonaID = ZoneId.of('America/Tijuana');
CharSequence dateUTC = "2022-11-22T17:15:00";
LocalDateTime dateTimeL = LocalDateTime.parse(dateUTC);
ZonedDateTime myZDT = ZonedDateTime.now();
ZonedDateTime myZDTFinal = myZDT.of(dateTimeL, zonaID);
System.out.println("using toLocalDateTime: " + myZDTFinal.toLocalDateTime());
System.out.println("using toString: " + myZDTFinal.toString());
I know that this might be a duplicated question but there's so many questions about date-times and I just haven't been able to figure out this.
Any help will be really appreciated.
You have to convert your date to UTC, then convert the convert this zone to your expected zone using withZoneSameInstant like this:
ZonedDateTime toUTCZone = ZonedDateTime.of(dateTimeL, ZoneOffset.UTC);
ZonedDateTime myZDTFinal = toUTCZone.withZoneSameInstant(zonaID);
Output
2022-11-22T09:15-08:00[America/Tijuana]
There can be many ways to achieve the result. A simple approach would be
Parse the given string into LocalDateTime.
Convert it into an OffsetDateTime at UTC using LocalDateTime#atOffset.
Use OffsetDateTime#atZoneSameInstant to convert the resulting OffsetDateTime into a ZonedDateTime at ZoneId.of("America/Tijuana").
Get LocalDateTime out of the resulting ZonedDateTime by using ZonedDateTime#toLocalDateTime.
If required, format this LocalDateTime into the desired string.
LocalDateTime
.parse("2022-11-22T17:15:00") // Parse the given date-time string into LocalDateTime
.atOffset(ZoneOffset.UTC) // Convert it into a ZonedDateTime at UTC
.atZoneSameInstant(ZoneId.of("America/Tijuana")) // Convert the result into a ZonedDateTime at another time-zome
.toLocalDateTime() // Get the LocalDateTime out of the ZonedDateTime
.format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss", Locale.ENGLISH))); // If required
Demo:
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
LocalDateTime ldtInTijuana = LocalDateTime.parse("2022-11-22T17:15:00")
.atOffset(ZoneOffset.UTC)
.atZoneSameInstant(ZoneId.of("America/Tijuana"))
.toLocalDateTime();
System.out.println(ldtInTijuana);
// Custom format
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
String formatted = ldtInTijuana.format(formatter);
System.out.println(formatted);
}
}
Output:
2022-11-22T09:15
2022-11-22T09:15:00
Note that LocalDateTime#toString removes second and fraction-of-second values if they are zero. Suppose you want to keep them (as you have posted in your question), you can use a DateTimeFormatter as shown above.
An alternate approach:
Alternatively, you can append Z at the end of your ISO 8601 formatted date-time string to enable Instant to parse it and then convert the Instant into a ZonedDateTime corresponding to the ZoneId.of("America/Tijuana") by using Instant#atZone. The symbol, Z refers to UTC in a date-time string.
The rest of the steps will remain the same.
Demo:
public class Main {
public static void main(String[] args) {
String text = "2022-11-22T17:15:00";
text = text + "Z"; // Z refers to UTC
Instant instant = Instant.parse(text);
LocalDateTime ldt = instant.atZone(ZoneId.of("America/Tijuana")).toLocalDateTime();
System.out.println(ldt);
}
}
Output:
2022-11-22T09:15
Learn more about the modern Date-Time API from Trail: Date Time.

Java Instant.parse cannot validate date

I have an instant field and trying to validate the values in this field using the following approach:
Instant.parse("2021-09-29 09:35:07.531")
However, it throws the error:
java.time.format.DateTimeParseException: Text '2021-09-29
09:35:07.531' could not be parsed at index 10.
So, how can I test if the given Instant date in String format is a valid Instant date?
I am implementing an Import feature and I need to check the date cells. So, the date is normally kept in Instant format in db and for this reason I need to check if the cell date value is a valid Instant date. So, if there is a more proper way, of course I can follow that approach.
I do not use the value, I just need to check if the date is a valid date.
Your Date-Time string does not have timezone information and therefore you can not parse it into an Instant without introducing a timezone. I recommend you parse it into LocalDateTime and use the same for DB work if it is supposed to be used independent of timezones.
Demo:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String args[]) {
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS", Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse("2021-09-29 09:35:07.531", dtfInput);
System.out.println(ldt);
}
}
Output:
2021-09-29T09:35:07.531
ONLINE DEMO
How to use LocalDateTime in JDBC?
Given below is a sample code to insert a LocalDateTime into columnfoo (which is of TIMESTAMP type):
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, ldt);
st.executeUpdate();
st.close();
Given below is a sample code to retrieve a LocalDateTime from columnfoo:
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM mytable WHERE <some condition>");
while (rs.next()) {
// Assuming the column index of columnfoo is 1
LocalDateTime ldt = rs.getObject(1, LocalDateTime.class));
System.out.println(ldt);
}
rs.close();
st.close();
In case you want to parse the given Date-Time string into Instant:
As described above, you need to introduce a timezone in order to parse it into an Instant.
Demo:
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String args[]) {
// Change the ZoneId to the applicable one e.g. ZoneId.of("Etc/UTC")
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS", Locale.ENGLISH)
.withZone(ZoneId.systemDefault());
Instant instant = Instant.from(dtfInput.parse("2021-09-29 09:35:07.531"));
System.out.println(instant);
}
}
Output in my timezone, Europe/London:
2021-09-29T08:35:07.531Z
ONLINE DEMO
Learn more about the modern Date-Time API* from Trail: Date Time.
* 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. Note that Android 8.0 Oreo already provides support for java.time.
A reference to the time zone is mandatory if you are trying to use the Instant class. So, let's try this:
LocalDateTime.from(DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm:ss.SSS").parse("2021-09-29 09:35:07.351")).atZone(ZoneId.systemDefault()).toInstant();
So, how can I test if the given Instant date in String format is a
valid Instant date?
It is not.
An instant is a (unique) point in time. Your string holds a date and time of day. Without knowing the time zone this may denote some point within a range of 24 or 27 hours — so pretty far from being one point in time.
Edit: I understand that you are importing the string from somewhere, that you cannot decide the format or content of the string, and you need to validate it. You can validate it as a date and time. You basically cannot convert it to an Instant, or at least you only can under assumptions the validity of which I can’t know. For validation I suggest this formatter:
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter(Locale.ROOT);
The formatter reuses built-in formatters and accepts a variable number of decimals in the seconds, which I think will make sense in many contexts. You know better whether it does in yours.
Validate like this:
String importedDateTimeString = "2021-09-29 09:35:07.531";
try {
LocalDateTime.parse(importedDateTimeString, PARSER);
System.out.format("Valid date and time: %s%n", importedDateTimeString);
} catch (DateTimeParseException dtpe) {
System.out.format("Not a valid date and time: %s. Validation error: %s%n",
importedDateTimeString, dtpe);
}
Output:
Valid date and time: 2021-09-29 09:35:07.531
Original recommendation: So instead use a format that includes offset from UTC. In particular the ISO 8601 format for an instant in UTC is a recommended option for several purposes, like 2021-09-29T01:35:07.531Z.
Link: Wikipedia article: ISO 8601

Get 1 year back dateTime from current dateTime in yyyy-MM-dd HH:mm:ss.SSS format

I need to get the datetime of 1 year back considering the current datetime. The format needed to be in "yyyy-MM-dd HH:mm:ss.SSS"
ex : 2019-08-13 12:00:14.326
I tried following. But getting an error.
LocalDate now = LocalDate.now();
LocalDate localDate = LocalDate.parse(now.toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")).minusYears(1);
Below Exception returned:
DateTimeParseException: Text '2020-08-13' could not be parsed
What's the best way to do this in Java 8+ ?
A LocalDate does not hold any information about hours, minutes, seconds or any unit below, instead, it holds information about year, month and day. By calling LocalDate.now() you are getting the date of today (the day of code execution).
If you need the time as well, use a LocalDateTime, which has a method now(), too, and actually consists of a LocalDate and a LocalTime.
Your error message tells you that the content of a LocalDate cannot be formatted using the given pattern (-String) "yyyy-MM-dd HH:mm:ss.SSS" because that pattern requires values for hours (HH), minutes (mm), seconds (ss) and milliseconds (SSS are fraction of seconds and three of them make it be milliseconds).
For parsing Strings or formatting datetimes, a LocalDateTime may be suitable but if you want to reliably add or subtract a year or any other amount of time, you'd rather use a class that considers time zones, offsets and daylight saving like ZonedDateTime or OffsetDateTime...
The LocalDate is the wrong class for your requirement as it does not hold the time information. You can use LocalDateTime but I suggest you use OffsetDateTime or ZonedDateTime so that you can get the flexibility of using the Zone Offset and Zone ID. Check https://docs.oracle.com/javase/tutorial/datetime/iso/overview.html for an overview of date-time classes.
Also, keep in mind that a date or time or date-time object is an object that just holds the information about date/time; it doesn't hold any information about formatting and therefore no matter what you do when you print their objects, you will always get the output what their toString() methods return. In order to format these classes or in other words, to get a string representing a custom format of these objects, you have formatting API (e.g. the modern DateTimeFormatter or legacy SimpleDateFormat) at your disposal.
A sample code:
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
// Get the current date & time at UTC
OffsetDateTime odtNow = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println("Now at UTC: " + odtNow);
// Get the date & time one year ago from now at UTC
OffsetDateTime odtOneYearAgo = odtNow.minusYears(1);
System.out.println("One year ago at UTC: " + odtNow);
// Define a formatter for the output in the desired pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
// Format the date & time using your defined formatter
String formattedDateTimeOneYearAgo = formatter.format(odtOneYearAgo);
System.out.println("Date Time in the pattern, yyyy-MM-dd HH:mm:ss.SSS: " + formattedDateTimeOneYearAgo);
}
}
Output:
Now at UTC: 2020-08-13T08:50:36.277895Z
One year ago at UTC: 2020-08-13T08:50:36.277895Z
Date Time in the pattern, yyyy-MM-dd HH:mm:ss.SSS: 2019-08-13 08:50:36.277
May not be the best way, but this will do it
LocalDateTime date = LocalDateTime.now().minusYears(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(date.format(formatter));
You say you want date+time from 1 year back, but you give it only a date (LocalDate). If you just want the date, all you need to do is:
LocalDate now = LocalDate.now();
LocalDate then = now.minusYears(1);
And if you want the timestamp also, then:
LocalDateTime now = LocalDateTime.now();
LocalDateTime then = now.minusYears(1);
And so on for other objects.
As mentioned you should use LocalDateTime instead of LocalDate.
Your exception was thrown because your input String is in ISO_DATE_TIME format
Java Doc
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
String now = dateTimeFormatter.format(LocalDateTime.now());
LocalDateTime localDate = LocalDateTime.parse(now, dateTimeFormatter);

parse String variable from database (type datetime) to LocalDateTime variable using Resultset

I'm trying to convert a String value (initially a LocalDateTime variable) that was stored in a database (as datetime) and parse it into a LocalDateTime variable. I've tried it with a formatter:
String dTP;
dTP=(rs.getString("arrivedate"));
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime dateTimeParked = LocalDateTime.parse(dTP,formatter);
And without a formatter:
String dTP;
dTP=(rs.getString("arrivedate"));
LocalDateTime dateTimeParked = LocalDateTime.parse(dTP);
But I get the same error each time:
Exception in thread "AWT-EventQueue-0" java.time.format.DateTimeParseException: Text '2016-07-09 01:30:00.0' could not be parsed at index 10
My thinking is that index 10 is the space between date and time.
Could anyone help me with this? I've been at it for hours :(
There is a error in the format of the that causes the issue. Please refer https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html.The ISO date time is of the format '2011-12-03T10:15:30' . The following will give you the idea
public static void main(String[] args) throws Exception {
String isoDate = "2016-07-09T01:30:00.0";
// ISO Local Date and Time '2011-12-03T10:15:30'
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime dateTimeParked = LocalDateTime.parse(isoDate, formatter);
System.out.println(dateTimeParked);
String date = "2016-07-09 01:30:00.0";
DateTimeFormatter formatterNew = DateTimeFormatter.ofPattern("yyyy-LL-dd HH:mm:ss.S");
LocalDateTime dateTimeParkedNew = LocalDateTime.parse(date, formatterNew);
System.out.println(dateTimeParkedNew);
}
This prints :
2016-07-09T01:30
2016-07-09T01:30
The other answers are correct, your string is in SQL format which differs from the canonical version of ISO 8601 format by using a space character in the middle rather than a T. So either replace the space with a T or define a formatting pattern for parsing.
Use smart objects, not dumb strings
But the bigger problem is that you are retrieving the date-time value from your database as a string. You should be retrieving date-time types of data as date-times types in Java.
For drivers compliant with JDBC 4.2 and later, you should be able to use setObject and getObject with java.time objects.
For SQL type of TIMESTAMP WITHOUT TIME ZONE use LocalDateTime. For TIMESTAMP WITH TIME ZONE, use Instant or perhaps ZonedDateTime depending on the database.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class );
Store in database.
myPreparedStatement.setObject( … , ldt ) ;
try this formatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
I'm not sure about the millisecond part though (In case it is more than 1 character long).

What I am doing wrong when parsing an ISO8601 date time?

I am expecting the test below to pass. Could someone tell me what I am doing wrong here? Most likely I am using a wrong pattern but I can't see what is wrong.
#Test
public void parseDateTest() {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.sss'Z'");
DateTime dt = formatter.parseDateTime("1983-03-06T05:00:03.000Z");
assertEquals("1983-03-06T05:00:03.000Z", dt.toString());
}
FYI dt.toString() does print: 1983-03-06T05:00:00.000Z
Thanks!
P.S.
Please note that on this snippet I rely on the default timezone. This is not production code and how to handle correctly the timezone based on needs is covered by many other questions.
The default time zone is derived from the system property user.timezone. If that is null or is not a valid identifier, then the value of the JDK TimeZone default is converted. If that fails, UTC is used.
This checks to see if "1983-03-06T05:00:03.000Z" is equal to dt.toString(). You say that dt.toString() is equal to "1983-03-06T05:00:00.000Z".
"1983-03-06T05:00:03.000Z" !== "1983-03-06T05:00:00.000Z"
Now the problem is why dt.toString() does not have the correct amount of seconds. Let's look at your DateTimeFormat pattern:
"yyyy-MM-dd'T'HH:mm:ss.sss'Z'"
According to the docs, s is for "second of minute" and S is for "fraction of second" (note the case). This means in your input string, both 03 and 000 are being parsed as seconds (when the later should be fractions) and your DateTime's seconds are being overridden with 00. Try updating this format string:
#Test
public void parseDateTest() {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
DateTime dt = formatter.parseDateTime("1983-03-06T05:00:03.000Z");
assertEquals("1983-03-06T05:00:03.000Z", dt.toString());
}
java.time
Quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time API: java.time API is based on ISO 8601 and therefore you do not need a DateTimeFormatter to parse a date-time string which is already in ISO 8601 format (e.g. your date-time string, 1983-03-06T05:00:03.000Z).
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
class Main {
public static void main(String[] args) {
String strModifiedDate = "1983-03-06T05:00:03.000Z";
Instant instant = Instant.parse(strModifiedDate);
System.out.println(instant);
// It can also be directly parsed into a ZonedDateTime
ZonedDateTime zdt = ZonedDateTime.parse(strModifiedDate);
System.out.println(zdt);
// or even into an OffsetDateTime
OffsetDateTime odt = OffsetDateTime.parse(strModifiedDate);
System.out.println(odt);
}
}
Output:
1983-03-06T05:00:03Z
1983-03-06T05:00:03Z
1983-03-06T05:00:03Z
Learn more about the modern Date-Time API from Trail: Date Time.
Don't use dt.toString(), use formatter.format(dt) instead. That's what the formatter is for:
#Test
public void parseDateTest() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
LocalDateTime dt = formatter.parse("1983-03-06T05:00:03.000Z", LocalDateTime::from);
assertEquals("1983-03-06T05:00:03.000Z", formatter.format(dt));
}

Categories

Resources