Java Converting Retrieved TimeStamp to Instant Gives Wrong Day - java

I've made a simple method which is used to convert a timestamp retrieved from a database into a LocalDate. However for some reason I keep getting the wrong day in the conversion. I've shared the code below.
private LocalDate getLocalDateFromTimeStamp(Row row, String key){
return LocalDate.parse(row.getTimestamp(key).toInstant().atZone(ZoneOffset.UTC).toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
So the date I'm expecting is 2022-12-21 but what I get is 2022-12-22.
When I debug and check what
row.getTimestamp(key)
gets me a Date object of Wed Dec 21 20:47:46 CST 2022 which is what I expect.
When I check what
row.getTimestamp(key).toInstant()
does, I get "2022-12-22T02:47:46.299Z". And I think this is where the problem is popping up and I'm not sure why it's happening. The LocalDate that's returned by the method is "2022-12-22".
If anyone could shine a light on this I'd really appreciate it as I'm lost as to why this is happening.

Try it like this. Check out DateTimeFormatter for details on the following arguments.
String date = "Wed Dec 21 20:47:46 CST 2022";
EEE three letter day of week
MMM three letter month
dd integer day
HH:mm:ss time using 24 hour clock
z time zone name (CST)
yyyy year
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy");
LocalDate dt = LocalDateTime.parse(date, dtf).toLocalDate();
System.out.println(dt);
prints
2022-12-21
Updated
If you actually have an instance of Date you might try the following:
LocalDate ldt = LocalDate.ofInstant(date.toInstant(),
ZoneId.systemDefault());

tl;dr
Avoid unnecessary string manipulation. Use date-time types for date-time values.
myResultSet
.getObject( … , OffsetDateTime.class ) // For any database column of a data type akin to the SQL standard type of `TIMESTAMP WITH TIME ZONE`.
.toLocalDate() // Extract the date portion from the returned `OffsetDateTime` object.
.toString() // Generate text in standard ISO 8601 format.
Details
The Timestamp class is part of the terrible date-time classes that are now legacy. Use only their replacements, the modern java.time classes defined in JSR 310.
Instead of Timestamp, use OffsetDateTime with JDBC 4.2 and later. Do this for any database column of a data type akin to the SQL standard type of TIMESTAMP WITH TIME ZONE.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Your Question is not clear, but you seem to want the date portion of that moment as seen with an offset from UTC of zero hours-minutes-seconds.
The retrieved OffsetDateTime is likely already in UTC. But let’s be sure:
OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;
Extract the date portion.
LocalDate localDate = odtUtc.toLocalDate() ;
To generate text in standard ISO 8601 format, call toString.
String output = localDate.toString() ;

Related

Saving a timestamp value from a given string value

I am having a string value in format "Tue Apr 30 00:00:00 UTC 1996";
. I want this value to be converted into a timestamp field in "30-APR-96 05:30:00.000000000 AM"
What i tried here is
DateFormat formatter = new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy");
Date date = formatter.parse(str);
Timestamp ts = new Timestamp(date getTime());
SimpleDateFormat fo = new SimpleDateFormat("dd-MMM-yy hh:mm:ss.SSSSSSSSS a");
fo.format(ts);
//When i try here Timestamp.valueOf(fo.format(ts));
I am getting an exception Timestamp format must be yyyy-mm-dd hh:mm:ss[.ffffff]
In DB when i see i have the type as Timestamp and values are stored in "30-APR-96 05:30:00.000000000 AM"
tl;dr
myPreparedStatement.setObject(
… ,
ZonedDateTime
.parse(
"Tue Apr 30 00:00:00 UTC 1996" ,
DateTimeFormatter
.ofPattern( "E MMM dd HH:mm:ss zzz uuuu" )
.withLocale( Locale.US )
)
.toOffsetDateTime()
);
Avoid legacy date-time classes.
You are using terribly flawed date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310. Never use Date, Calendar, SimpleDateFormat, etc.
In particular, your input data uses a resolution of nanoseconds, while thé java.util.Date class is limited to milliseconds.
ISO 8601
Let me mention that data exchange should be using standard ISO 8601 formats for date-time values transmitted as text. The standard formats are concise, unambiguous, and easily read by both humans and machines.
Use custom or localized formats only for presentation to user, not for storage and data exchange.
So, "Tue Apr 30 00:00:00 UTC 1996" would be 1996-04-30T00:00:00Z where Z is short for +00:00, an offset from UTC of zero hours-minutes-seconds.
java.time
The java.time classes do support the nanoseconds resolution needed for your data inputs.
Define a formatting pattern to match the input. Specify a Locale to determine the human language and cultural norms used in translation.
Locale locale = new Locale( "en" , "IN" ) ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E MMM dd HH:mm:ss zzz uuuu" ) ;
Parse your input.
ZonedDateTime zdt = ZonedDateTime.parse( "Tue Apr 30 00:00:00 UTC 1996" , f ) ;
See this code run live at IdeOne.com.
zdt.toString(): 1996-04-30T00:00Z[UTC]
Apparently you want to see this moment as it appears in the India 🇮🇳 time zone. Specify the desired time zone as a ZoneId object.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
Apply the zone to get another ZonedDateTime object.
ZonedDateTime zdtKolkata = zdt.withZoneSameInstant( z ) ;
See this code run live at IdeOne.com.
zdtKolkata.toString(): 1996-04-30T05:30+05:30[Asia/Kolkata]
You asked for a java.sql.Timestamp object. That class is one of the terrible legacy classes to avoid. And it is unnecessary. JDBC 4.2 and later requires that a JDBC driver support java.time.
To write a moment to a database, we need to use OffsetDateTime rather than ZonedDateTime. The SQL standard does not specify time zones, only offsets.
And, there is no need for the India-specific value. Most databases saving into a column of a type akin to the SQL standard type TIMESTAMP WITH TIME ZONE will automatically adjust inputs into UTC (an offset of zero).
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject( … , odt ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Beware: Verify the data type of your database column. If you are using a column of a type akin to the SQL standard type TIMESTAMP WITHOUT TIME ZONE, you are using the wrong type. That type cannot represent a moment, a specific point on the timeline. Such a type has only a date with time of day, but lacks the context of an offset.

Converting string to date 2021-12-10T00:00:00 in java

I'm tring to convert this date string "2021-12-10T00:00:00" into a Date but when i deserialize it i got this.
Thu Dec 09 19:00:00 COT 2021.
it seems I'm losing one day.
Can anyone help me?
"startDate": "2021-12-10T00:00:00", and the result is this
2021-12-09T19:00:00.000-0500
tl;dr
java.util.Date.from(
LocalDateTime
.parse( "2021-12-10T00:00:00" )
.atZone(
ZoneId.of( "America/Bogota" )
)
.toInstant()
)
Details
I am guessing that you are using the terrible legacy date-time classes such as Date and Calendar. Don’t. Use only java.time class.
Your input string complies with the ISO 8601 standard for date-time formats. The java.time classes use these standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
LocalDateTime ldt = LocalDateTime.parse( "2021-12-10T00:00:00" ) ;
You said:
I'm tring to convert this date string "2021-12-10T00:00:00" into a Date
That does not make sense.
I assume by “Date”, you meant a java.until.Date. That legacy class represents a moment, a point on the timeline as seen in UTC, that is, with an offset from UTC of zero hours-minutes-seconds.
But your input lacks an indicator of time zone or offset. For example, if that string was meant to represent a moment as seen in UTC, it should have had a Z appended.
I am guessing that you assume the input was meant to represent a moment as seen in Colombia.
ZoneId z = ZoneId.of( "America/Bogota" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
Now we have determined a moment as seen through the wall-clock time used by the people of Colombia.
Generally best to avoid java.util.Date class. But if you must, to interoperate with legacy code not yet updated to java.time, you can convert.
java.util.Date d = Date.from( zdt.toInstant() ) ;
Your start date is 2021-12-10 00:00:00 GMT+0 and your result is 2021-12-09 19:00:00 GMT-5. These times are the same. You can pass a Locale to your SimpleDataFormat constructor to be able to configure the used time zone.

Cannot convert String to Local Date

When trying to convert from String to Local Date, an error is occurred and date cant be parsed
I am trying to convert a date which is in String format (eg: 2019-11-11T19:12:59.598) to Local Date (eg: 2019-11-11) format.
String dateInString = "2019-11-11T19:12:59.598";
public LocalDateTime DateToYear(String dateInString) {
Instant instant = Instant.parse(dateInString);
System.out.println("Instant : " + instant);
//get date time only
LocalDateTime result = LocalDateTime.ofInstant(instant, ZoneId.of(ZoneOffset.UTC.getId()));
//get localdate
System.out.println("LocalDate : " + result.toLocalDate());
return result;
}
One of my test method is calling this method DateToYear(String dateInString).
ISO 8601
Your input string complies with the ISO 8601 standard for textual date-time values.
The java.time classes use the standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
LocalDateTime
Your input string lacks an indicator of time zone or offset-from-UTC.
So we must parse as a LocalDateTime.
String dateInString = "2019-11-11T19:12:59.598";
LocalDateTime ldt = LocalDateTime.parse( input ) ;
Not a moment
Your input string does not represent a moment, is not a point on the timeline. Without the context of a time zone or offset, we do not know if you meant 7 PM on November 11 this year in Tokyo Japan, or 7 PM in Tunis Tunisia, or 7 PM in Toledo Ohio. These are all different moments, happening several hours earlier/later than one another. All we know is this string meant 7 PM on that date somewhere, but we know not where — so we know not when precisely.
To simply extract the date-only portion from your LocalDateTime, call toLocalDate.
LocalDate ld = ldt.toLocalDate() ;
Because your input is not a moment, your line:
Instant instant = Instant.parse(dateInString);
…makes no sense. An Instant represents a moment in UTC, a specific point on the timeline. But your string is not necessarily intended for UTC; we simply do not know what offset/zone was intended. We cannot tell that by looking at just the string.
If you happen to know for certain that input string was meant for UTC:
Educate the people who published that data about the importance of zone/offset. If they meant UTC, they should have appended a +00:00 or the abbreviation Z (pronounced “Zulu”).
Apply the constant ZoneOffset.UTC to get a OffsetDateTime which represents a moment as seen in a particular offset-from-UTC.
Code:
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ; // Making a moment of ambiguous input. Do this only if you are *certain* of the zone/offset intended by the publisher of this data input.
Get the date for that moment as seen in that offset.
LocalDate localDate = odt.toLocalDate() ;
If you know for certain the input string was meant for a particular time zone, apply a ZoneId to get a ZonedDateTime object. Then extract a LocalDate.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
LocalDate localDate = zdt.toLocalDate() ;
Keep in mind that for any given moment the date varies around the globe by time zone. So the LocalDate here may represent a different date than seen in the input string, being a day ahead or behind the date of the input string.
It will parse if you put a Z at the end of your string. See DateTimeFormatter.ISO_INSTANT
jshell> Instant.parse("2019-11-11T19:12:59.598")
| java.time.format.DateTimeParseException thrown: Text '2019-11-11T19:12:59.598' could not be parsed at index 23
| at DateTimeFormatter.parseResolved0 (DateTimeFormatter.java:2046)
| at DateTimeFormatter.parse (DateTimeFormatter.java:1948)
| at Instant.parse (Instant.java:395)
| at (#10:1)
jshell> Instant.parse("2019-11-11T19:12:59.598Z")
==> 2019-11-11T19:12:59.598Z

converting from string to date object not displaying expected result [duplicate]

This question already has answers here:
How to Parse Date from GMT TimeZone to IST TimeZone and Vice Versa in android
(4 answers)
SimpleDateFormat returns wrong time zone during parse
(2 answers)
DateFormat parse - not return date in UTC
(1 answer)
Closed 3 years ago.
I searched for solutions but still not working ,I'm trying to convert the date object's local timezone to UTC +0 , but when i format the date object to UTC it's working . but when I want to convert the converted string to date again, the format changes and UTC goes back to GMT+8 before i store it in the fire store. what is the problem in the code?
this is the current date object that i get
Calendar time = Calendar.getInstance();
time.setTimeZone(TimeZone.getTimeZone("UTC"));
Date current_time = time.getTime();
if printed
Thu Aug 22 10:09:55 GMT+08:00 2019
then i convert it to UTC
String dismissal_time_firestore;
Log.i(TAG, "Current time when swiped from phone time.getTime() "+current_time);
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
dismissal_time_firestore = dateFormat.format(current_time);
got this
Thu, 22 Aug 2019 02:09:55 +0000
but then when i convert this string to a date object
try {
current_time = dateFormat.parse(dismissal_time_firestore);
} catch (ParseException e) {
e.printStackTrace();
}
i got this
Thu Aug 22 10:09:55 GMT+08:00 2019
You are using terrible date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310.
Your main problem is not understanding that the Date::toString method lies to you. It dynamically applies the JVM’s current time zone to the moment in UTC while generating the text. One of many reasons to never use this class.
Get current moment in UTC.
Instant instant = Instant.now() ;
View that moment as seen in the wall-clock time used by the people of a particular region (a time zone).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Generate text for display to user.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
String output = zdt.format( f ) ;
You talk about parsing formatted strings. Bad idea. Think of textual representations of date-time values only as outputs, not inputs. Collecting date-time inputs should be done by using date-time widgets, not typed text.
When storing or exchanging date-time values as text, always use ISO 8601 standard formats. The java.time classes use ISO 8601 formats by default when parsing/generating strings. So no need to specify any formatting pattern. Just call parse/toString. Example: Instant.now().toString() and Instant.parse( "2020-01-23T12:34:56.123456Z" ).
I cannot help further as you did not really say what you were trying to accomplish.
All of this has been covered many many times on Stack Overflow. So search to learn more. And search before posting.

Need to persist local date from Json input to oracle DB in a spring-boot application

I have the local date in json input in String format dd-MM-yyyy HH:mm:ss format [let it be any format no issue], have a separate field timezone in header [eg : CST , CDT etc]. In java when i try to create a date with this value and timezone it is getting created with my system [jvm running system] timezone.
I need to persist the exact date and time from input with the input timezone.
How can I do it ?
I even tried with putting date object with #DateTimeFormat in dto instead of string but that did not work.
I want a method like this to get the local date from the input date string and timezone.
public Date getLocalDate(String dateString, String localTimeZone) {
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss a");
formatter.setTimeZone(TimeZone.getTimeZone(localTimeZone));
return formatter.parse(dateString);
}
Input : dateString : "20-04-2019 20:15:00 AM" localTimeZone : "CDT" .
Expected Output : Date object with value 20-04-2019 20:15:00 AM CDT .
Actual Output : same date with IST-CDT hour difference with IST timezone
There is a misunderstanding about what a Date object really is. It is just a number of milliseconds since '01-01-1970 00:00:00 UTC'. Said differently it is always an UTC date/time and it is implicitely converted in your local time zone by the default formatter when you try to print it.
If you want to store both the instant (ie the UTC date/time) and a time zone, you will have to use a Calendar object. But anyway, if you want to store both the time and the zone in Oracle, you should directly store a string, or a date and a string (for the timezone), because AFAIK, Oracle DATE fields have no notion of a time zone.
java.time
You are using terrible date-time classes that were supplanted years ago by the java.time classes defined in JSR 310.
“CST” and such 2-4 character pseudo-zones are not time zones. They are not standardized and are not even unique! Ex: CST is Central time in North America and also China Standard Time.
True time zones are in format Continent/Region. Ex: Europe/Paris or Africa/Tunis. See list in Wikipedia.
To represent a date and time-of-day in the context of a time zone, use ZonedDateTimeclass.
To store a date-time separate from zone, use LocalDateTime and ZoneId classes.
Database
Your comments indicate a desire to store the current moment in database.
Capture the current moment in UTC.
Instant instant = Instant.now() ;
For use with JDBC 4.2, convert to an OffsetDateTime.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
Pass to a prepared statement.
myPreparedStatement.setObject( … , odt ) ;
Retrieve.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

Categories

Resources