Timezone format, how to know the timezone - java

I got a timestamp in the following format:
2017-09-27T16:19:24+0000
How do I know which timezone that is? What's the DateTimeFormatter if I'm using Java 8?

ZonedDateTime
As you stated using Java 8, you can leverage ZonedDateTime by using
ZonedDateTime zdt = ZonedDateTime.parse("2017-09-27T16:19:24+0000", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")
Parsing rules are explained in DateTimeFormatter documentation. It is not exactly the ISO 8601 ISO_OFFSET_DATE_TIME as the offset should have been written +00:00 instead of +0000
Time zone vs time offset
Then, you can get the offset information with zdt.getZone(). However, you'll only get the Offset ID:
Z - for UTC (ISO-8601)
+hh:mm or -hh:mm - if the seconds are zero (ISO-8601)
+hh:mm:ss or -hh:mm:ss - if the seconds are non-zero (not ISO-8601)
As one comment said, be careful that time offset is not time zone: A given time zone (e.g. time in France) does not have the same offset the whole year (summer time vs winter time).

The timestamp given has a timezone offset (+0000), which represents +00 hours and +00 minutes from GMT+00.
This timezone pattern can be represented by the character Z for both SimpleDateFormat and DateTimeFormatter's ofPattern method.
The timezone you are handling can be represented by a pattern of yyyy-MM-dd'T'HH:mm:ssZ:
yyyy represents the current year
MM represents the month of the current year
dd represents the current day of the current month
'T' represents a quoted T character
HH represents the current hour of the current day
mm represents the current minute of the current hour
ss represents the current second of the current minute
Z represents the timezone offset from GMT

It looks like ISO 8601 format: dateTime±hhmm. Here hhmm is offset from UTC

The representation 2017-09-27T16:19:24+0000 gives +0000 so baseline UTC.
Timestamps themselves and LocalDateTime wrap a long count of seconds and do not contain a separate time zone info.
Java provides a class that maintains an addition time zone.
ZonedDateTime dt = LocalDateTime.now().atZone(ZoneId.of("Europe/Sofia"));
One needs to be sure that the time was stored as UTC, +0000: a recommendation only.

Related

Convert UTC time to Europe/London timezone in java

I've current datetime in UTC but I need date time of timezone (Europe/London). I tried but everytime time is not adding instead of this offset is appending in current date time.
My code -
LocalDateTime utcTime = LocalDate.now().atTime(0,1);
System.out.println("utc time " + utcTime);
ZoneId europeLondonTimeZone = ZoneId.of("Europe/London");
ZoneOffset offset = europeLondonTimeZone.getRules().getOffset(utcTime);
OffsetDateTime offsetDateTime = utcTime.atOffset(offset);
System.out.println(offsetDateTime);
It will print:
"2021-06-18T00:01+01:00"
but I want
"2021-06-17T23:01"
as +01:00 is ahead in daylight saving time.
Thanks
If you just want the current time in Great Britain, there is no need to convert from UTC. You can have that time directly.
ZoneId europeLondonTimeZone = ZoneId.of("Europe/London");
OffsetDateTime offsetDateTime = OffsetDateTime.now(europeLondonTimeZone);
System.out.println(offsetDateTime);
Output when I ran the code just now:
2021-06-18T19:18:39.599+01:00
If you do need to have the UTC time first, avoid using LocalDate or LocalDateTime for that. The local in some java.time class names means without time zone or UTC offset. Prefer OffsetDateTime, which itself keeps track of its offset, as the name says. So when it’s in UTC, it “knows” this fact itself.
// Sample UTC time
OffsetDateTime utcTime = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println("UTC time: " + utcTime);
ZoneId europeLondonTimeZone = ZoneId.of("Europe/London");
OffsetDateTime offsetDateTime = utcTime.atZoneSameInstant(europeLondonTimeZone)
.toOffsetDateTime();
System.out.println("UK time: " + offsetDateTime);
UTC time: 2021-06-18T18:18:39.669Z
UK time: 2021-06-18T19:18:39.669+01:00
The atZoneSameInstant method converts from whatever offset the OffsetDateTime was in (in this case UTC) to the time zone passed as argument, thus typically altering the clock time (sometimes even the date).
What went wrong in your code?
A LocalDate contains a date without time of day only, so LocalDate.now() only gives you which day it is in the default time zone of your JVM (so not even which day it is in UTC), not the time of day. .atTime(0,1) converts that day to a LocalDateTime representing the time of 0 hours 1 minute, that is, 00:01, on that day, still without any time zone.
Also a ZonedDateTime not only knows its time zone but can also handle its time zone rules. So there is no reason for you to deal with the offset at a particular time yourself.
Finally LocalDateTime.atOffset() converts to an OffsetDateTime but neither changes the date nor the time of day. Since the LocalDateTime did not have any time zone, the method cannot be used for converting between time zones.

Joda Time to Java Time Migration show different result while migration

Given the following code
public static void main(String[] args) {
org.joda.time.format.DateTimeFormatter _timestampFomatNYCJoda = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd HHmmss.SSS").withZone(DateTimeZone.forID("America/New_York"));
DateTimeFormatter _timestampFomatNYC = DateTimeFormatter.ofPattern("yyyyMMdd HHmmss.SSS").withZone(ZoneId.of("America/New_York"));
LocalDateTime localDateTime = LocalDateTime.now();
org.joda.time.LocalDateTime jodaLocalDateTime = new org.joda.time.LocalDateTime();
System.out.println("System Time " + new Date());
System.out.println("Java Version " + localDateTime.format(_timestampFomatNYC));
System.out.println("Joda Version " + _timestampFomatNYCJoda.print(jodaLocalDateTime.toDateTime(DateTimeZone.UTC)));
}
Why does the Java Version and Joda Version dont match ? I am running this on IST clock.
Below is the output
System Time Fri Mar 27 17:01:33 IST 2020
Java Version 20200327 170133.933
Joda Version 20200327 130133.938
I can reproduce your results. I can also explain them. Joda-Time and java.time have been designed to behave differently in this case. Let’s look at them in turn.
Joda-Time
In Joda-Time DateTimeFormatter.withZone() gives you a formatter with an override zone, that is, a zone that will always be used for formatting dates and times. In other words, any date and time will be converted to this zone for printing. The documentation says:
When printing, this zone will be used in preference to the zone from
the datetime that would otherwise be used.
When you do new org.joda.time.LocalDateTime(), you are getting a LocalDateTime representing the current date and time in your default time zone. The Local in some class names means without time zone or offset from UTC. I figure that you must have got a value equal to 2020-03-27T17:01:33.938.
Apparently what happens when you format a LocalDateTime with a formatter with an override zone, is that the formatter assumes that your LocalDateTime is in UTC (which yours isn’t) and converts it from there, in your case to America/New_York time zone. Since summer time (DST) is in effect in New York, the offset is -04:00, so 17:01 becomes 13:01.
This is the wrong result. When the time is 17:01 in your time zone, it is not 17:01 UTC, so the conversion is based on a false premise. It is also not 13:01 in New York, so the converted result is telling a lie.
java.time
With java.time setting an override zone on a formatter works similarly for formatting, but with a difference that matters here: the override zone is only used when printing a date-time object that identifies an instant (a point in time). From the docs:
When formatting, if the temporal object contains an instant, then it
will be converted to a zoned date-time using the override zone.
Whether the temporal is an instant is determined by querying the
INSTANT_SECONDS field. If the input has a chronology then it will be
retained unless overridden. If the input does not have a chronology,
such as Instant, then the ISO chronology will be used.
… In all other cases, the override zone is added to the temporal,
replacing any previous zone, but without changing the date/time.
Again LocalDateTime.now() gives you the current date and time of day (a few milliseconds earlier than the query through Joda-Time), 2020-03-27T17:01:33.933. Local still means without offset or time zone.
Because your LocalDateTIme hasn’t got offset or time zone, it cannot identify an unambigous point in time, an instant. Therefore when formatting it neither the date nor the time of day is changed. And since your format pattern contains no time zone or offset, none is printed. So you just get the date and time in your time zone (not in New York), 20200327 170133.933.
To get the date and time in New York time zone
DateTimeFormatter timestampFormat
= DateTimeFormatter.ofPattern("yyyyMMdd HHmmss.SSS");
ZonedDateTime timeInNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println(timeInNy.format(timestampFormat));
When I ran this code just now, the output was:
20200327 122359.683
Documentation links
Joda-Time DateTimeFormatter.withZone()
java.time DateTimeFormatter.withZone()

Convert Time from one time zone to another using Java 8 Time

I am trying to convert Date with GMT +5:30 to EST with java 8 ZonedDateTime.
String inputDate = "2015/04/30 13:00";
DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US);
LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);
// local : 2015-04-30T13:00
//Combining this local date-time with a time-zone to create a ZonedDateTime.
ZonedDateTime zoned = local.atZone(TimeZone.getTimeZone("GMT+5:30").toZoneId());
// zoned : 2015-04-30T13:00+05:30[GMT+05:30]
ZonedDateTime zonedUS = zoned.withZoneSameInstant(TimeZone.getTimeZone("GMT-5:00").toZoneId());
// zonedUS : 2015-04-30T02:30-05:00[GMT-05:00]
I am expecting 3:30 AM EST but what I am getting is 2:30 AM EST as 1 PM IST= 3:30AM EST. What am I missing?
It seems that whatever service you found was being over-helpful in interpreting what you meant and assumed North American Eastern Daylight Time (EDT) when you specified EST (Eastern Standard Time). Most, not all of the places using EST as standard time are using daylight saving time and hence were on EDT or offset UTC-04:00 on the date you use, April 30, 2015.
If it makes sense in your situation, you should always prefer to give time zone in the region/city format, as Asia/Kolkata and America/New_York. If you intended Eastern Time as in New York or Montréal, one may say that your “time zone” of GMT-5:00 was wrong and the cause of your unexpected result.
So your code becomes for example:
String inputDate = "2015/04/30 13:00";
DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US);
LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);
// local : 2015-04-30T13:00
//Combining this local date-time with a time-zone to create a ZonedDateTime.
ZonedDateTime zoned = local.atZone(ZoneId.of("Asia/Kolkata"));
// zoned : 2015-04-30T13:00+05:30[Asia/Kolkata]
ZonedDateTime zonedUS = zoned.withZoneSameInstant(ZoneId.of("America/Montreal"));
// zonedUS : 2015-04-30T03:30-04:00[America/Montreal]
I have made one other change: When using the modern classes from java.time, there is no point in also using the outdated TimeZone class, so I have taken that out. The code is slightly simpler, and more importantly, ZoneId.of(String) includes validation of your time zone string so you will discover any spelling error in the time zone name (like when I just happened to type a ( instead of the / in Asia/Kolkata — such happens all the time).
Most of the above has already been said in comments by Jon Skeet and others. I thought it deserved to go into an answer so it’s plain to see that the question has been answered.
Though the question is old, felt like I could add more to the accepted answer.
A ZonedDateTime is different from an OffsetDateTime.
I would prefer to use ZonedDateTime when I'm getting a time for a specific location like "Asia/Kolkata", "Asia/Shanghai", "US/Pacific" (this time zone will change depending on the day of the year because of Daylight savings).
To illustrate with an example,
var pacific = ZonedDateTime.of(2020,11,01,1,59,0,0,ZoneId.of("US/Pacific"))
var afterAnHour = pacific.plusHours(1)
This will give me a time of
2020-November-01 01:59:00.000 AM -07:00[US/Pacific]
And if i add an hour to it, it will give me a time of
2020-November-01 01:59:00.000 AM -08:00[US/Pacific]
You can see that the hour component is same even after adding an hour to the time. This is because the daylight savings time has kicked in and the time zone is shifted from -07:00 to -08:00.
Now if i use an OffsetDateTime look what happens.
var offsetNow = OffsetDateTime.of(2020,11,01,1,59,0,0,ZoneOffset.of("-07:00"))
var offsetAfterAnHour = offsetNow.plusHours(1)
The offsetNow will be,
2020-November-01 01:59:00.000 -07:00
And adding an hour to it will be,
2020-November-01 02:59:00.000 -07:00
you can see that the hour component has become 2 after adding an hour.
The key point is a ZonedDateTime uses ZoneRules to calculate important properties like Daylight savings time so that it can adjust the time zone accordingly.
While the OffsetDateTime will not change the zone offset for anything.

Joda-Time datetime daylight saving time for Europe/Berlin

How can I parse a date string with Joda-Time datetime which uses the correct timezone WITH daylight saving time?
As an example in scala I try to parse the string "2014-04-07 01:00:00.000" (without timezone information). This date is coming from MySQL and is supposed to be in tz Europe/Berlin +01:00. What I like to have is a joda date time according to 2014-04-07 00:00:00+01:00 which is the timezone Europe/Berlin currently not on DST (GMT +1).
val fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(DateTimeZone.forID("Europe/Berlin"))
val dt = fmt.parseDateTime("2014-04-07 01:00:00.000")
Unfortunately Joda-Time parses the date to 2014-04-07T01:00:00.000+02:00 which is currently the wrong offset (02:00 instead if 01:00)
Any ideas how to make Joda-Time parse the date with the correct DST offset?
Joda-Time is correct. Your assumption of +01:00 for Berlin is incorrect. You did not account for Daylight Saving Time.
According to this page at TimeZoneConverter.com for the time zone "Europe/Berlin", Daylight Saving Time (DST) began on Sun 30-Mar-2014 at 02:00:00 A.M. when local clocks were set forward 1 hour. According to the Wikipedia list of time zone names, that means Berlin shifted from being one hour ahead of UTC (+01:00) to two hours ahead (+02:00).

How to get timezone representation in GMT format

Our timezones are stored in the database as follows (e.g. America/Los_Angeles). How do I get the equivalent GMT representation from the above (e.g. GMT -08:00)
Offset from GMT in hours:
import java.util.TimeZone
double offset = TimeZone.getTimeZone("America/Los_Angeles")
.getRawOffset()/(60*60*1000.0);
// returns 8.0
However, this returns the raw offset. The offset changes depending on the timezone and the date due to Daylight Time Savings. To get the offset for a particular date use:
import java.util.TimeZone
import java.util.Calendar
Calendar cal = Calendar.getInstance();
double offset = TimeZone.getTimeZone("America/Los_Angeles")
.getOffset(cal.getTimeInMillis())/(60*60*1000.0);
// returns -7.0 for 22/sep/2010
There's a huge difference between those two:
"America/Los_Angeles" lets you determine the local time given any UTC time
"GMT -08:00" only tells you the difference between local time and UTC at one instant. It doesn't tell you about when or whether DST is applied, or how much DST is applied
In other words, "GMT -08:00" is an offset, not a time zone. Now you can get the offset at any particular instant fairly easily - I would personally use Joda Time for that - and format it appropriately. But don't think that you've actually got a reasonable representation of a time zone.

Categories