How to adjust a Timestamp that comes from my database? - java

In the database, a time is saved as a Timestamp in the UTC time zone (that is, 0). When I get it, I need to add the Timezone from the place that I will send. I have these two pieces of information, but I can't find the time.
This is the code from which I get both information. I've tried to transform to LocalDateTime and adjust the zone, but it didn't produce any results. There is no much of code:
Timestamp timestamp = resultQueryCamerasOffline.getLastOnline();
String zoneId = resultQueryCamerasOffline.getEmpresaTimezone();
System.out.println(timestamp.toString());
System.out.println(zoneId);
2020-03-12 03:01:45.0
America/São_Paulo
In the database, last_online has value:
2020-03-12 03:01:45.0

You can and maybe have to use a LocalDateTime in order to achieve what you want, but the final product should be a ZonedDateTime.
Basically, the timestamp should be converted to a LocalDateTime and that LocalDateTime can then be converted to a ZonedDateTime by adding a specific ZoneId, like this:
Just adding a zone, leaving the datetime as is:
public static void main(String[] args) {
// get or take a timestamp
java.sql.Timestamp timestamp = Timestamp.valueOf("2020-03-12 03:01:45.0");
// transforming it into a LocalDateTime
LocalDateTime localDateTime = timestamp.toLocalDateTime();
// now create a ZonedDateTime by putting a zone
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime,
ZoneId.of("America/Sao_Paulo"));
// and print the result
System.out.println(zonedDateTime);
}
The output is
2020-03-12T03:01:45-03:00[America/Sao_Paulo]
If you are sure the client that runs this code always has the desired time zone, then you can alternatively use ZoneId.systemDefault() when the ZonedDateTime is being created.
But if you don't just want to add a zone but really convert the Instant to another zone, then you can do this:
Converting the Instant to another time zone:
public static void main(String[] args) {
// get or take a timestamp
java.sql.Timestamp timestamp = Timestamp.valueOf("2020-03-12 03:01:45.0");
// transforming it into a LocalDateTime
LocalDateTime localDateTime = timestamp.toLocalDateTime();
// now create a ZonedDateTime by putting a zone
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
localDateTime.toInstant(ZoneOffset.of("+00:00")),
ZoneId.of("America/Sao_Paulo"));
// and print the result
System.out.println(zonedDateTime);
}
This outputs
2020-03-12T00:01:45-03:00[America/Sao_Paulo]
You can have the second one shorter:
public static void main(String[] args) {
// get or take a timestamp
java.sql.Timestamp timestamp = Timestamp.valueOf("2020-03-12 03:01:45.0");
// transforming it into a LocalDateTime
ZonedDateTime utc = ZonedDateTime.of(timestamp.toLocalDateTime(), ZoneId.of("UTC"));
// now create a ZonedDateTime by putting a zone
ZonedDateTime saoPaulo = utc.withZoneSameInstant(ZoneId.of("America/Sao_Paulo"));
// and print the result
System.out.println(saoPaulo);
}
The output stays
2020-03-12T00:01:45-03:00[America/Sao_Paulo]
If you want the output formatted differently, you have to either choose one of the built-in patterns (public constants of DateTimeFormatter, like DateTimeFormatter.ISO_ZONED_DATE_TIME) or give it a custom one (by DateTimeFormatter.ofPattern(String pattern) plus an optional Locale):
public static void main(String[] args) {
// get or take a timestamp
java.sql.Timestamp timestamp = Timestamp.valueOf("2020-03-12 03:01:45.0");
// transforming it into a LocalDateTime
ZonedDateTime utc = ZonedDateTime.of(timestamp.toLocalDateTime(), ZoneId.of("UTC"));
// now create a ZonedDateTime by putting a zone
ZonedDateTime saoPaulo = utc.withZoneSameInstant(ZoneId.of("America/Sao_Paulo"));
// create a formatter for your locale and with the desired pattern
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEEE dd MMM yyyy hh:mm:ss a xxx",
Locale.forLanguageTag("pt-BR"));
// and print the result
System.out.println(saoPaulo.format(dtf));
}
This time, the output is formatted in a totally different way:
Quinta-feira 12 mar 2020 12:01:45 AM -03:00

get the millis from your timestamp and try:
LocalDateTime date = LocalDateTime
.ofInstant(Instant.ofEpochMilli(timestamp.getTime()), ZoneId.systemDefault(yourTimezone()));
or try using a ZonedDateTime

Related

Parse a String to LocaDateTime in Java

Consider a String "2022-03-23 21:06:29.4933333 +00:00".
How do I parse the above DateTimeOffset String to LocalDateTime in Java?
I tried with the following DateTimeFormatter but the format seems to be incorrect:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss\[.nnnnnnn\] \[+|-\]hh:mm\]");
LocalDateTime dateTime = LocalDateTime.parse(timestamp, formatter)
First, start by having the JavDocs for DateTimeFormatter at hand, this is going to really help determine which specifiers you need
The first thing to do is parse the text into a ZonedDateTime, LocalDateTime won't parse a input value with a time zone (AFAIK), you "might" be able to force it, but what's the point?
String text = "2022-03-23 21:06:29.4933333 +00:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSS z");
ZonedDateTime zdt = ZonedDateTime.parse(text, formatter);
System.out.println(zdt);
This prints...
2022-03-23T21:06:29.493333300Z
Now you could use ZonedDateTime#toLocalDateTime, but this won't take into account the current time zone of the user/computer.
If you need to convert the ZonedDateTime to LocalDateTime, it's best to do so in away which will translate the time (and date if required) to best represent the time within the current time zone (okay, I was confused typing it)
For example, converting the input value into my current time zone (+11 hours) would look like this...
ZoneId currentZone = ZoneId.systemDefault();
ZonedDateTime currentZDT = zdt.withZoneSameInstant(currentZone);
System.out.println(currentZDT);
LocalDateTime ldt = currentZDT.toLocalDateTime();
System.out.println(ldt);
which will print...
2022-03-24T08:06:29.493333300+11:00[Australia/Melbourne]
2022-03-24T08:06:29.493333300
This means that at 9:06pm on the 23rd March in Grinch (GMT), it was 8:06am on the 24th March where I live.
Now you can use different ZoneIds to convert to a TimeZone which is not the current computers TimeZone, but I'll leave that up to you to experiment with (for example, I used Convert ZonedDateTime to LocalDateTime at time zone to base my example on)
You need create custom DateTimeFormatter:
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
public class Main {
public static void main(String args[]){
String dateString = "2022-03-23 21:06:29.4933333 +00:00";
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(java.time.format.DateTimeFormatter.ISO_LOCAL_TIME)
.appendLiteral(' ')
.appendOffsetId()
.toFormatter();
//In case of OffSet matter, retaining the instant
LocalDateTime localDateTimeSavePointOfTime = OffsetDateTime.parse(dateString, formatter).withOffsetSameInstant(OffsetDateTime.now().getOffset()).toLocalDateTime();
//In case OffSet does not matter we can skip it
LocalDateTime localDateTimeSkipOffSet = LocalDateTime.parse(dateString, formatter);
}
}

Best way to Change java.sql.TimeStamp to UTC format in Java

I have tried multiple ways one of them using SimpleDateFromatter and now trying
import java.sql.Timestamp;
public static String getCorrectTimeFormat(Timestamp time) {
return time.toInstant().toString();
}
But the problem is which I realized during writing unit test is, the time gets modified.
Timestamp timeStamp = Timestamp.valueOf("2020-07-22 12:26:51.599");
String res = UserUtil.getCorrectTimeFormat(timeStamp);
assertThat(res).isEqualTo("2020-07-22T12:26:51.599Z");
This never passes as the it auto converts to "2020-07-22T11:26:51.599Z"
It’s best to avoid jqva.sql.Timestamp completely. I’ll show you how.
The result you got is correct, as I think you have already discovered.
Get java.time types from your database
Since JDBC 4.2 we can directly get java.time types from a ResultSet. If your database value is a timestamp with time zone (recommended), for example:
OffsetDateTime odt = rs.getObject(
"your_timestamp_with_time_zone_column", OffsetDateTime.class);
String utcString = odt.withOffsetSameInstant(ZoneOffset.UTC).toString();
If your database value is a timestamp without time zone (not recommended), we can only get a LocalDateTime from it, which doesn’t define a point in time. To convert to Instant we need to rely on knowing which time zone the database uses. For example:
ZoneId datebaseTimeZone = ZoneId.of("Europe/Paris");
LocalDateTime ldt = rs.getObject(
"your_timestamp_column", LocalDateTime.class);
String utcString = ldt.atZone(datebaseTimeZone)
.withZoneSameInstant(ZoneOffset.UTC)
.toString();
If your database uses UTC, which counts as an offset, it’s better to use ZoneOffset than ZoneId:
ZoneOffset datebaseOffset = ZoneOffset.UTC;
LocalDateTime ldt = rs.getObject(
"your_timestamp_column", LocalDateTime.class);
String utcString = ldt.atOffset(datebaseOffset).toString();
Your observed result is correct
java.sql.Timestamp confusingly prints in the default time zone of the JVM, and Timestamp.valueOf() equally confusingly assumes that time zone. So assuming that your time zone is at offset +01:00 at this time of year (such as Great Britain, Ireland, Portugal, Morocco and Tunesia, for example), the conversion from 2020-07-22 12:26:51.599 to 2020-07-22T11:26:51.599Z is correct.
You can use java 8 time ZonedDateTime class :
//1 - default pattern
String timeStamp = "2019-03-27T10:15:30";
ZonedDateTime localTimeObj = ZonedDateTime.parse(time);
//2 - specified pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss a z");
String timeStamp1 = "2019-03-27 10:15:30 AM";
ZonedDateTime localTimeObj1 = ZonedDateTime.parse(timeStamp1, formatter);
//To get LocalDate from ZonedDateTime
LocalDate localDate = localTimeObj1.toLocalDate()
//To get timestamp from zoneddatetime with utc timezone
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());

ISO8601 Date Parsing ignoring Offset

I'm trying to parse 2009-07-30T16:10:36+06:00 to a date using yyyy-MM-dd'T'HH:mm:ssXXXXX.
However the output I get appears to have not factored in the offset, as I get yyyy-MM-dd'T'HH:mm:ssXXXXX.
Any ideas what I'm missing?
final DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXXXX");
final ZonedDateTime zonedDateTime = ZonedDateTime.parse("2009-07-30T16:10:36+06:00", iso8601Formatter);
final String formatted = zonedDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
System.out.println(formatted);
If my understanding is correct you should set the zone similar to withZoneSameInstant(ZoneId.of("UTC"))
final ZonedDateTime zonedDateTime = ZonedDateTime.parse("2009-07-30T16:10:36+06:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME);
System.out.println("Without ZoneId: " + zonedDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")));
System.out.println("With ZoneId: " + zonedDateTime.withZoneSameInstant(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")));
Result
Without ZoneId: 30/07/2009 16:10:36
With ZoneId: 30/07/2009 10:10:36
OffsetDateTime odt = OffsetDateTime.parse("2009-07-30T16:10:36+06:00");
ZonedDateTime zdt = ZonedDateTime.ofInstant(odt.toInstant(), ZoneOffset.UTC);
// 2009-07-30T10:10:36Z
First you have no zoned date time, which would also depend on the country.
Then actually you want the Greenwich time, the UTC.
If you want the time in UTC (which is not clear from the question), then the other answers give you the correct result. Since there is no time zone (such as Europe/London Pacific/Rarotonga) in your data, there is no point in using a ZonedDateTime. OffsetDateTime is a better fit:
final OffsetDateTime dateTime = OffsetDateTime.parse("2009-07-30T16:10:36+06:00");
final OffsetDateTime utcDateTime = dateTime.withOffsetSameInstant(ZoneOffset.UTC);
final String formatted = utcDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
System.out.println(formatted);
30/07/2009 10:10:36

Specify timezone of ZonedDateTime without changing the actual date

I have a Date object which holds a date (not current date) and I need to somehow specify that this date is UTC and then convert it to "Europe/Paris" which is +1 hours.
public static LocalDateTime toLocalDateTime(Date date){
return ZonedDateTime.of(LocalDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC), ZoneId.of("Europe/Paris")).toLocalDateTime();
}
Given a date of "2018-11-08 15:00:00" this converts the date into "2018-11-08 14:00:00". I need it to convert from UTC to Europe/Paris - not the other way around.
You could use ZonedDateTime.withZoneSameInstant() method to move from UTC to Paris time:
Date date = new Date();
ZonedDateTime utc = date.toInstant().atZone(ZoneOffset.UTC);
ZonedDateTime paris = utc.withZoneSameInstant(ZoneId.of("Europe/Paris"));
System.out.println(utc);
System.out.println(paris);
System.out.println(paris.toLocalDateTime());
which prints:
2018-11-08T10:25:18.223Z
2018-11-08T11:25:18.223+01:00[Europe/Paris]
2018-11-08T11:25:18.223
Since an old-fashioned Date object doesn’t have any time zone, you can ignore UTC completely and just convert to Europe/Paris directly:
private static final ZoneId TARGET_ZONE = ZoneId.of("Europe/Paris");
public static LocalDateTime toLocalDateTime(Date date){
return date.toInstant().atZone(TARGET_ZONE).toLocalDateTime();
}
I’m not sure why you want to return a LocalDateTime, though. That is throwing away information. For most purposes I’d leave out .toLocalDateTime() and just return the ZonedDateTime from atZone.
ZonedId zoneId = ZoneId.of("Europe/Paris");
return ZonedDateTime.of(LocalDateTime.ofInstant(date.toInstant(),zonedId);
Try to define ZoneId that is Europe/Paris

Java: ZonedDateTime - parse timestring without timezone

I have a datetime-string WITHOUT a specified timezone.
But I want to parse it with ZonedDateTime to give it a timezone-meaning in the act of parsing.
This code is working but uses LocalDateTime for parsing - and then convert it to ZonedDateTime with giving it a timezone-meaning.
DateTimeFormatter dtf = DateTimeFormatter.ofPattern ("yyyyMMddHHmm");
String tmstr = "201810110907";
LocalDateTime tmp = LocalDateTime.parse (tnstr,dtf);
ZonedDateTime mytime = ZonedDateTime.of (tmp, ZoneId.of ("UTC"));
Is there a way I can parse it directly with ZonedDateTime?
I have tried this, but it was not working.
mytime = mytime.withZoneSameInstant(ZoneId.of("UTC")).parse(str,dtf);
You may specify a default time zone on the formatter:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmm")
.withZone(ZoneId.of("UTC"));
String tmstr = "201810110907";
ZonedDateTime mytime = ZonedDateTime.parse(tmstr, dtf);
System.out.println(mytime);
Output:
2018-10-11T09:07Z[UTC]
Bonus tip: Rather than ZoneId.of("UTC") it’s usually nicer to use ZoneOffset.UTC. If you accept the output being printed as 2018-10-11T09:07Z instead (Z meaning UTC).

Categories

Resources