Java: ZonedDateTime - get the offset of a reference timestamp - java

I have a timestamp in UTC. I convert it into localtime. My timezone is CET/CEST.
2018-10-03 12:00 UTC => 14:00 CEST
2018-10-30 12:00 UTC => 13:00 CET
Because of my timezone the system automatically applies the correct offset: If I convert timestamp in summer it automatically adds 2hrs (no matter what time it is when I convert), if it is in winter it adds 1hr.
So far - so good.
Now I would like to convert a UTC timestamp based on another referenced timestamp.
If the reference is in summer it should always add 2hrs - no matter if the timestamp to convert is summer or winter - and if reference is in winter it should always add 1hr.
Ref = 01.01.2018 = CET
2018-10-03 12:00 UTC => 13:00 CET
2018-10-30 12:00 UTC => 13:00 CET
Ref = 01.10.2018 = CEST
2018-10-03 12:00 UTC => 14:00 CEST
2018-10-30 12:00 UTC => 14:00 CEST
So how can I find out what timezone (or what offset to UTC) a reference timestamp (in UTC) has if my systems runs normal CEST/CET??
I use ZonedDateTime normally.

You can get the ZoneId from the reference ZonedDateTime that you have and use it to adjust the timestamp that you have in UTC to that zone:
Set up
ZoneId cet = ZoneId.of("CET");
// The reference timestamps, these could be any ZonedDateTime
// but I specifically make one for winter and one for summer
ZonedDateTime refWinter = ZonedDateTime.of(LocalDateTime.parse("2018-01-01T12:00"), cet);
ZonedDateTime refSummer = ZonedDateTime.of(LocalDateTime.parse("2018-10-01T12:00"), cet);
// The UTC timestamp that you want to convert to the reference zone
ZonedDateTime utc = ZonedDateTime.of(LocalDateTime.parse("2018-10-03T12:00"), ZoneOffset.UTC);
Conversion
// The converted timestamps
ZonedDateTime convertedWinter = utc.withZoneSameInstant(refWinter.getOffset());
ZonedDateTime convertedSummer = utc.withZoneSameInstant(refSummer.getOffset());
System.out.println(convertedWinter); // 2018-01-03T13:00+01:00
System.out.println(convertedSummer); // 2018-10-03T14:00+02:00

You can parse your date from string to Date object if they are in UTC and then you can convert them back to the string in your local timezone. Please check below code example:
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2018-10-03 12:00");
isoFormat.setTimeZone(TimeZone.getDefault());
System.out.println("Date in my local timezone is "+isoFormat.format(date));

Related

Java convert RFC 1123 datetime to milliseconds from epoch

I'm trying to convert a date in RFC 1123 format to number of milliseconds from epoch in Java.
My usecase is that I've uploaded a file to my pCloud storage (directly from my browser) and then from java, request the REST API to retrieve the last modified datetime of this file.
The string I've received is "Fri, 08 Apr 2022 15:57:48 +0000".
But from my computer, the file last modification is at 17:57:48.
But I'm in Europe/Paris, so that I'm at timezone offset +2.
I tried to do:
String modified = "Fri, 08 Apr 2022 15:57:48 +0000";
DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
LocalDateTime localDateTime = LocalDateTime.parse(modified, formatter);
ZonedDateTime zdt = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
At this point, if I output variables:
System.out.println(localDateTime);
System.out.println(zdt);
It displayed:
2022-04-08T15:57:48
2022-04-08T15:57:48+02:00[Europe/Paris]
Now to convert to milliseconds from epoch time, I've tried:
localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
zdt.toInstant().toEpochMilli();
localDateTime.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli();
And all these give
1649426268000
And if I use the following formatter :
new SimpleDateFormat("YYYY/MM/dd HH:mm:ss").format(long milliseconds).
It display:
2022/04/08 15:57:48
So it missing my timezone offset?! (the "+02:00[Europe/Paris]").
I found this solution:
TimeZone tz = TimeZone.getTimeZone(ZoneId.systemDefault());
long milli = zdt.toInstant().toEpochMilli() + tz.getOffset(new Date().getTime())
And formmating milli as just before with the same SimpleDateFormat, I have:
2022/04/08 17:57:48
which is the correct value.
Is there a cleaner way to have the correct long millisecond to epoch from my string date in RFC 1123 format?
Especially I think in my solution I have to do something like
tz.getOffset(extact date from "modified" string)
because the offset is not the same according to DST (summer or winter), and I hope this use case must be natively managed with all the Class of Java ?
You are using a LocalDateTime, which stores only date and time components. Then you proceed to apply the local time zone. Your local time zone is not relevant to this task, so should not be used.
Instead, since your input contains a date, time, and offset, you should parse to an OffsetDateTime.
String modified = "Fri, 08 Apr 2022 15:57:48 +0000";
DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
OffsetDateTime odt = OffsetDateTime.parse(modified, formatter);
Then you can use either of the following to get milliseconds since the epoch:
odt.toInstant().toEpochMilli()
or
odt.toEpochSecond() * 1000
Either will give you the correct value of 1649433468000. See similar code run live at IdeOne.com.
(Note, there is no toEpochMilli method directly on an OffsetDateTime, so either go through an Instant first, or get seconds and multiply by 1000.)

Convert a GMT datetime to local timezone datetime

In Java 8 I need a way to get the local datetime (GMT+1) from a GMT datetime in ISO 8601 format.
A simple example:
Client sends me (Server) this datetime "2020-01-11T23:00:00.000Z"
Client sends me this when the user choose the 12 Jan 2020 from the datepicker. Is the 12 Jan for GMT+1 but the day before for GMT.
For the reason above then I know that for me this datetime is not the 11 Jan 2020 but 12 Jan 2020 in GMT+1.
So I need this value "2020-01-12T00:00:00.000"
To be precise I don't need to print this with simpleDateFormat but just covert "2020-01-11T23:00:00.000Z" to "2020-01-12T00:00:00.000" in a java.util.Date class field
Thanks.
The problem is that the source system took the pure date value, but added time at midnight, then converted that to UTC, but you want the pure date value in a java.util.Date, which by default prints in your local time zone, i.e. the JVM's default time zone.
So, you have to parse the string, revert the value back to the time zone of the source system, the treat that local time as a time in your own JVM's default time zone.
You can do that like this, showing all the intermediate types:
String sourceStr = "2020-01-11T23:00:00.000Z";
ZoneId sourceTimeZone = ZoneOffset.ofHours(1); // Use real zone of source, e.g. ZoneId.of("Europe/Paris");
// Parse Zulu date string as zoned date/time in source time zone
Instant sourceInstant = Instant.parse(sourceStr);
ZonedDateTime sourceZoned = sourceInstant.atZone(sourceTimeZone);
// Convert to util.Date in local time zone
ZonedDateTime localZoned = sourceZoned.withZoneSameLocal(ZoneId.systemDefault());
Instant localInstant = localZoned.toInstant();
Date localDate = Date.from(localInstant); // <== This is your desired result
// Print value in ISO 8601 format
String localStr = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").format(localDate);
System.out.println(localStr);
Output
2020-01-12T00:00:00.000
The code can of course be merged together:
String input = "2020-01-11T23:00:00.000Z";
Date date = Date.from(Instant.parse(input).atZone(ZoneOffset.ofHours(1))
.withZoneSameLocal(ZoneId.systemDefault()).toInstant());
System.out.println(date);
Output
Sun Jan 12 00:00:00 EST 2020
As you can see, the date value is correct, even though I'm in the US Eastern time zone.

Java Date.toString in Oracle's TO_DATE

The default format for Date.toString() seems to be, in an US locale, something like:
Thu Nov 24 15:20:52 CET 2016
Oracle database has a function "TO_DATE" that allows convert from string to date. First argument is the date format.
Which is the correct date format to map a Java Date.toString() string? Is it:
DAY MONTH DD HH24:MI:SS TZD YYYY
?
Thanks.
An Oracle DATE data type does not have a time zone - you need a TIMESTAMP WITH TIMEZONE data type:
SELECT TO_TIMESTAMP_TZ(
'Thu Nov 24 15:20:52 CET 2016',
'DY MON DD HH24:MI:SS TZR YYYY'
)
FROM DUAL
If you want to convert to a DATE (and the time zone region is always CET) then you can use:
SELECT TO_DATE(
'Thu Nov 24 15:20:52 CET 2016',
'DY MON DD HH24:MI:SS "CET" YYYY'
)
FROM DUAL
If you want it as a DATE data type and to respect the time zone in the original string then you will need to (1) convert it to a TIMESTAMP WITH TIMEZONE data type; (2) convert that value to a standardized time zone (UTC is often used for this); then (3) convert that to a date:
SELECT CAST(
TO_TIMESTAMP_TZ(
'Thu Nov 24 15:20:52 CET 2016',
'DY MON DD HH24:MI:SS TZR YYYY'
)
AT TIME ZONE 'UTC'
AS DATE
)
FROM DUAL;
Which will output the date 2016-11-24 14:20:52 (the UTC representation of the input date).
In Java, default Date format with toString() method is EEE MMM dd HH:mm:ss zzz yyyy. I don't know why but Oracle doesn't supports parse syntax 'EEE','MMM' and 'zzz' .
Read more : Table 9-4 Datetime Format Elements

Calendar.getTime() not returning UTC date if TimeZone is defined

I have done this for my Calendar instance to return Date in UTC timezone:
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:SS Z");
TimeZone tz = TimeZoneUtil.getTimeZone(StringPool.UTC);
formatter.setTimeZone(tz);
Date dtStart = null;
Date dtEnd = null;
try{
dtStart = formatter.parse(formatter.format(startDate.getTime()));
dtEnd = formatter.parse(formatter.format(endDate.getTime()));
}catch (Exception e) {
e.getStackTrace();
}
It works fine till I format calendar timestamp to return a string date with required timezone but when I parse that string date to Date date, it again picks up local timezone?
I need to store Date object in UTC timezone.
Any help will be highly appreciated!
You can use this:
Date localTime = new Date();
//creating DateFormat for converting time from local timezone to GMT
DateFormat converter = new SimpleDateFormat("dd/MM/yyyy:HH:mm:ss");
//getting GMT timezone, you can get any timezone e.g. UTC
converter.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("local time : " + localTime);;
System.out.println("time in GMT : " + converter.format(localTime));
It will give:
local time: Fri Jun 21 11:55:00 UTC 2013
time in GMT : 21/06/2013:11:55:00
I hope it will help.
Cheers.
Date object in java will always store the values in the host machine (your system) time zone information.
This is from javadoc :
Although the Date class is intended to reflect coordinated universal time (UTC), it may not do so exactly, depending on the host environment of the Java Virtual Machine.
You should trying using Joda Time which is much advanced.
Instead of setting TimeZone in multiple places, it is a good idea to set timezone using -Duser.timezone=GMT or PST.
And, you can easily test how Java deals with timezone and getTime() ignores timezone with an actual example:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); // print with timezone
TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("GMT"));
TimeZone.setDefault(timeZone); // set system timezone as GMT
sdf.setTimeZone(timeZone); // formatter also has a timezone
Date date = new Date();
System.out.println(date); // system says GMT date
System.out.println(date.getTime()); // only prints time in milliseconds after January 1, 1970 00:00:00 GMT
System.out.println(sdf.format(date));
timeZone = TimeZone.getTimeZone(ZoneId.of("America/Los_Angeles"));
TimeZone.setDefault(timeZone); // set system timezone as GMT
sdf.setTimeZone(timeZone); // formatter also has a timezone
date = new Date();
System.out.println(date);
System.out.println(date.getTime()); // prints the same value as above, "not including timezone offset"
System.out.println(sdf.format(date));
// GMT and PDT times are same as getTime() only returns time in ms since UTC for the day ignoring timezone which is mostly used for formatting
Wed Mar 14 22:43:43 GMT 2018
1521067423108
2018-03-14T22:43:43+0000
Wed Mar 14 15:43:43 PDT 2018
1521067423125 // not includes timezone in getTime()
2018-03-14T15:43:43-0700 // formatting looks fine
The good explanation of why Date object taking Current time zone value ,
please refer this SO answer
EDIT.
here I am gonna add some important part of that answers.
java.util.Date is has no specific time zone, although its value is most commonly thought of in relation to UTC. What makes you think it's in local time?
To be precise: the value within a java.util.Date is the number of milliseconds since the Unix epoch, which occurred at midnight January 1st 1970, UTC. The same epoch could also be described in other time zones, but the traditional description is in terms of 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.

Date timezone issue

I have a UI where user can enter date. Now this date is converted to UTC format in my code which is inside an EJB.
My Query is if the browser in IST and my code is deployed in an server which in EST.
Now to convert to UTC from which timezone I need to convert the date from IST or ETC.
My code is like:
User enters a date in DatePicker. The value of DatePicker is assigned to plain Java Date Object.
You need to do IST to UTC
Your user is selecting date assuming it is IST. So in your server code you need to consider the user time zone before creating a Date object which will be in server time zone. Since server is in EST you need to convert it again to UTC before storing.
Most of the servers have time configured at UTC time zone, so only one conversion is all that is needed in that case.
When you get a Date its in the local time zone.
private static final DateFormat FULL_RFC822_DATETIME_FORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss", Locale.US);
public static void date2() throws Exception {
FULL_RFC822_DATETIME_FORMAT.setTimeZone(new SimpleTimeZone(0, "GMT")); //frozen
Date d = new Date(); // in local time zone
System.out.println(d);
System.out.println(FULL_RFC822_DATETIME_FORMAT.format(d) + " GMT");
}
I get
Fri Dec 07 11:15:58 CET 2012
Fri, 7 Dec 2012 10:15:58 GMT
GMT + UTC are the same.

Categories