while converting to data object, Moscow time is one hour behind - java

In my application while converting to date object i am always getting one hour behind time . this issue in happening only with moscow time zone.
below is code :
MutableDateTime mdt = new MutableDateTime(time);
mdt.setSecondOfMinute(0);
mdt.setMinuteOfDay(0);
mdt.toDate()
in above code mdt.todate() returning 5/30/2021 23:00 instead of 5/31/2021 00:00.
jdk version : "1.8.0_191"

Edit: Why does "June 6 00:00" after conversion mdt.toDate() become "May 31 23:00"?
Your surprising observation probably comes from an old Joda-Time version with an old time zone database where Europe/Moscow was at offset +04:00 rather than +03:00. It was between 31 October 2010 and 26 October 2014. If Joda-Time “believes” that this is still the case, it sets your MutableDateTime to something like 2021-06-01T00:00:00.000+04:00 with offset +04:00 instead of +03:00. This corresponds to 2021-05-31T20:00Z UTC where the correct point in time would have been 2021-05-31T21:00Z UTC. In other words, it’s an hour too early. Therefore you get a Date that is an hour too early too. Your Java 1.8 “knows” that Moscow is at offset +03:00 these days and therefore prints the time as Mon May 31 23:00:00 MSK 2021.
Solutions include:
Upgrade to a newer version of Joda-Time that has an up-to-date time zone database.
Build your Joda-Time from sources for the version that you are using only with a newer bundled time zone database. This is explained on the Joda-Time home page, see the second link below.
Original answer
Your surprising observation probably comes from an old Java version with an old time zone database where Europe/Moscow was at offset +04:00 rather than +03:00. It was between 31 October 2010 and 26 October 2014. I have reproduced your result on my Java 1.7.0_67 and verified that my Java installation “believes” that Moscow is at offset +04:00 and does not use summer time (DST), as was the case in the mentioned period.
Your Joda-Time seems to be new enough to know that Europe/Moscow is at +03:00 so correctly converts your MutableDateTime to a Date at 00:00 hours on the date in question. Only when you print this Date, Java uses its default time zone, still Europe/Moscow, but its own time zone data, and therefore incorrectly prints the time as 01:00 hours instead of 00:00.
Possible solutions include:
Upgrade to a newer Java version that has up-to-date time zone data.
Fix your current Java installation by upgrading only its time zone database. See Timezone Updater Tool in the second link below.
Setting the time to the start of the day
Edit: you added:
Here MutableDateTime time =new MutableDateTime(new Date().getTime());
To get a Date representing the start of today’s date using Joda-Time:
Date oldfashionedDateObject = LocalDate.now(DateTimeZone.getDefault()).toDate();
System.out.println(oldfashionedDateObject);
Output just now:
Mon May 31 00:00:00 MSK 2021
Original aside: As an aside, the simpler and safer way to set the time to the start of the day is:
mdt = mdt.toDateTime().withTimeAtStartOfDay().toMutableDateTime();
If you need to keep the same MutableDateTime object, instead do:
mdt.setMillis(mdt.toDateTime().withTimeAtStartOfDay().toInstant());
First of all I would be worried that your code may run in a time zone and on a day that in that time zone has a transition at 00:00 so that the first moment of the day is 01:00 or something else. In this case I b believe that your code would throw a surprising exception. Also I find setting individual fields low-level and prefer to set everything in one method call even if it requires further operations to determine the argument to pass to that method.
Links
Time Zone in Moscow, Russia (Moskva).
Joda-Time Updating the time zone data.
Timezone Updater Tool on Oracle’s web site.

Related

Joda Time not handling Day Light Saving transitions correctly

SCENARIO
I have two UTC timestamps that are 7 days apart:
val timestamp1: Long = 1600642800000L // GMT => Sunday, September 20, 2020 11:00:00 PM
val timestamp1: Long = 1601247600000L // GMT => Sunday, September 27, 2020 11:00:00 PM
The timezone used here is Africa/Casablanca.
val timeZone = DateTimeZone.forID("Africa/Casablanca")
Then, when I try to generate offset for both timestamps, it shows weird behavior:
timeZone.getOffset(timestamp1) // 3600000 milliseconds OR 1 hour
timeZone.getOffset(timestamp2) // 0 milliseconds
Africa/Casablanca currently has Day Light Saving enabled since May 24, 2020. It's clock was shifted on that day forward by 1 hr. So, currently it is at UTC + 1 hr. When Day Light Saving is not active, it is at UTC + 0.
QUESTION
So, how is the above behavior possible ? Shouldn't both timestamps generate the same 1 hr offset ?
Those two timestamps are only 7 days apart and no any Day Light Saving event happened between those timestamps.
I tried to reproduce similar behavior for other timezones but they always produce the same offset for those timestamps as expected.
Any insights on this behavior would be extremely helpful.
This issue was resolved when I upgraded Joda Time library to latest version 2.10.6 on my system with Java openjdk version "11.0.8". The reason this worked was that the latest version of Joda Time library had the latest timezone data with recent Day Light Saving rules. I realized that it is important to use the latest version and keep upgrading because Day Light Saving rules are political and can be changed by the governing body.
In addition, without doing any version upgrades, I also tested by writing the same code using native Java Time api. And by doing that also, this issue didn't appear.So, in the longer term, I would prefer using Java Time.

Wrong results when adding milliseconds to java.util.date object

Current time is Sat Apr 04 15:02:00 AEST 2020.
In the following snippet, I create a Date object and add 86400000L milliseconds (1 day) to it:
Date date = new Date();
date.setTime(date.getTime() + 86400000L);
System.out.println(date);
The output is Sun Apr 05 14:02:00 AEST 2020. I don't understand why the result adds only 23 hours to my current time, instead of 24 hours.
Any help would be appreciated.
The code works just fine. The AEST on your output means that the date regards Australian Eastern Standard Time. Googling for AEST dst shows that on Sunday, April 5, 3:00 am 2020 the clock will "go back" 1 hour. Thus adding 24 hours just before the DST change, will only move the time 23 hours forward.
If you run that code tomorrow, you'll not have this "problem".
Do use java.time, the modern Java date and time API, for your date and time work.
ZonedDateTime currentTime = ZonedDateTime.now(ZoneId.of("Australia/Sydney"));
System.out.println(currentTime);
ZonedDateTime tomorrowSameTime = currentTime.plusDays(1);
System.out.println(tomorrowSameTime);
Output when running just now:
2020-04-04T16:00:30.579484+11:00[Australia/Sydney]
2020-04-05T16:00:30.579484+10:00[Australia/Sydney]
Please observe: we got the same time of day tomorrow, 16:00. Because summer time (daylight saving time) ends, the UTC offset for tomorrow is different, +10:00 instead of +11:00. And importantly, while I find + 86400000L pretty close to unreadable for adding a day, .plusDays(1) conveys the intention very clearly.
Please insert a different Eastern Australian time zone if required.
What went wrong in your code? cherouvim has explained this very nicely in the other answer, no need for me to repeat. Only allow me to add that the Date class is not only poorly designed — giving rise to your confusion — it is also long outdated. I recommend you don’t use it. And as cherouvim notes in a comment, programming with dates is hard. Don’t trust that you can yourself convert 1 day to 86 400 000 milliseconds. Leave all date and time calculations to proven library methods.
Link: Oracle tutorial: Date Time explaining how to use java.time.

Java datetime inconsistent between local application and Jenkins deployment

I am receiving a date time as a string into my application. There I need to extract the hour so it can be written to a file along with some other stuff. For my unit test the string will look like this
2019-10-26T00:00:00+01:00
The code I use to extract the hour is this
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public static int extractHour(String dateInString) {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZZ");
DateTime dateTime = formatter.parseDateTime(dateInString);
return dateTime.getHourOfDay();
}
My test passes locally with expected hour 00 and actual hour 00 but when I deploy through Jenkins the actual hour is showing as 23 and my expected is 00.
When you don’t instruct Joda-Time otherwise, formatter.parseDateTime() parses into a DateTime in your default time zone.
So if for example your local time zone is set to Europe/Dublin or Europe/London, the result of parsing will be a DateTime of 2019-10-26T00:00:00.000+01:00 (because October 26 was the last day with summer time (DST) in those time zones) and the hour of day will be 0 as you expected. And if the time zone setting of your Jenkins server is UTC — that’s pretty commonplace — your string is parsed into 2019-10-25T23:00:00.000Z there. And the hour of day will be 23, obviously.
If you want the offset from your string to be retained in the DateTime, the fix is:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZZ")
.withOffsetParsed();
However, think twice. The hour of day only makes sense relative to the offset. In the night where summer time ended you could have strings of 2019-10-27T01:00:00+01:00 and an hour later when the clocks are changed, 2019-10-27T01:00:00+00:00. Both strings have hour of day of 1, but there’s an hour between them. Do you really want the same result? What if one day you get a string of 2020-02-16T00:00:00-05:00?
Edit:
What would you suggest rather than using withOffsetParsed()[?]
I first of all suggest that you decide what result you want for strings with different offsets, for example 2020-03-06T18:00:00+05:30 and 2020-04-18T04:00:00-08:00. You ought to know that better than I.
A generally recommended practice for handling time across offsets is to handle everything in UTC. This can be a special case of the solution you already found and mentioned in a comment, specifying time zone on the formatter:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZZ")
.withZoneUTC();
This guarantees a consistent result, apparently the same result that you already got on the Jenkins server. So 23 in your example.
PS If this is new code, you probably shouldn’t use Joda-Time. The Joda-Time homepage says:
Note that Joda-Time is considered to be a largely “finished” project.
No major enhancements are planned. If using Java SE 8, please migrate
to java.time (JSR-310).

Java Date set the minutes and seconds to 0

I want to set the minutes and seconds of a date to 0,
but I see that those methods are deprecated
Date yesterday = Date.from(Instant.now().minus(24, ChronoUnit.HOURS));
yesterday.setMinutes(0);
yesterday.setSeconds(0);
TL;DR
ZonedDateTime yesterday = ZonedDateTime.now(ZoneId.of("Europe/Madrid"))
.minusDays(1)
.truncatedTo(ChronoUnit.HOURS);
System.out.println("Yesterday with minutes and seconds set to 0: " + yesterday);
Running just now gave
Yesterday with minutes and seconds set to 0: 2019-03-17T23:00+01:00[Europe/Madrid]
Define yesterday
If you intended “yesterday at the same time”, that’s not always 24 hours ago. Due to summer time (DST) and other anomalies, a day may be for example 23, 23,5 or 25 hours.
java.time
The ZonedDateTime class of java.time, the modern Java date and time API, takes the time anomalies in your time zone into account. So when you subtract a day, you do get the same time yesterday, if that time exists at all.
.truncatedTo(ChronoUnit.HOURS) sets minutes, seconds and fraction of second to 0 in the time zone in question.
You were trying to use the Date class, but in Java 8 you should not do that. It’s poorly designed and long outdated. I find java.time so much nicer to work with.
If you indispensably need an old-fashioned Date
You may need a Date for a legacy API that you cannot change or cannot afford to change just now. In that case convert only in the last moment:
Instant yesterdayInstant = yesterday.toInstant();
Date yesterdayDate = Date.from(yesterdayInstant);
System.out.println("As old-fashoined Date: " + yesterdayDate);
In my time zone (Europe/Copenhagen, currently agrees with Europe/Madrid) I got
As old-fashoined Date: Sun Mar 17 23:00:00 CET 2019
Link
Oracle Tutorial: Date Time explaining how to use java.time.

Joda-time DateTime.withTimeAtStartOfDay() wrong result in date (2036,3,21) with Asia/Tehran time zone

In Joda-Time version 2.9.9 I want to remove time part of DateTime variable.
Only for time zone Asia/Tehran and some dates like (2036-03-21, 2037-03-21, ...) it returns 1:00:00 in time part of result.
I also checked the Joda-Time source code but I couldn't find any problem.
The code is:
DateTime dt = new DateTime(2036, 03, 21, 10, 0, DateTimeZone.forID(Asia/Tehran));
dt = dt.withTimeAtStartOfday();
Actual result:
2036-03-21T01:00:00.000+04:30
Expected result:
2036-03-21T00:00:00.000+04:30
Time is not zero. This only happens for zone Asia/Tehran.
My system config:
Java version: 1.7.0_72 - I have to use Java 7
Joda-Time: 2.9.9
I solved this problem by converting DateTime to LocalDate, but I want to know why this problem happens?
This is because Iran switches from Standard time to Daylight Savings time at 00:00 on the 21st or 22nd of March (whichever day contains the astronomical equinox).
In 2036 this happens on the 21st. In 2018 it happens to fall on the 22nd.
In short, the time jumps from 2036/03/20 24:00 to 2036/03/21 01:00. The hour from midnight to 1 AM does not exist on that specific day.
When writing code that deals with time, ALWAYS keep in mind that unexpected small offsets from expected results are almost surely due to administrative time changes. This is even more true for historical dates, where offsets could be any number of minutes and seconds, not just whole or half-hours.

Categories

Resources