10

I want to precisely calculate the time one week from a given date, but the output I get back is one hour early.

code:

long DURATION = 7 * 24 * 60 * 60 * 1000;
System.out.println("    now: " + new Date(System.currentTimeMillis()));
System.out.println("next week: " + new Date(System.currentTimeMillis() + DURATION));

output:

now: Wed Sep 16 09:52:36 IRDT 2015
next week: Wed Sep 23 08:52:36 IRST 2015

How can I calculate this correctly?

Craig
  • 2,286
  • 3
  • 24
  • 37
Askar
  • 544
  • 1
  • 6
  • 17
  • 7
    Use Java 8's Time API, use JodaTime, use `Calendar` for the love of sanity, but DON'T try and use millisecond arithmetic – MadProgrammer Sep 16 '15 at 05:33
  • @MadProgrammer actually, if you don't use Joda Time yet, nowadays you're better off using threetenbp instead – fge Sep 16 '15 at 05:34
  • I agree with @MadProgrammer. Using `JodaTime` would make this really simple. Joda provides methods like `plusWeek()` where you can add weeks to a given date – TheLostMind Sep 16 '15 at 05:35
  • @fge I'd say that's a matter of needs and requirements, I can see where the value might be in using 3-10bp to make the code more "compatible", but it still lacks some of the nice functionality in JodaTime, which might make appearances in later releases – MadProgrammer Sep 16 '15 at 05:40
  • @MadProgrammer, i want to use the code in GWT, and can't use Java 8 or other third parties, please suggest me another workaround – Askar Sep 16 '15 at 06:24
  • `Calendar`? It's part of the core API since 1.1 – MadProgrammer Sep 16 '15 at 06:26
  • @MadProgrammer, Class 'java.util.Calendar' is not present in JRE Emulation Library so it cannot be used in client code of GWT. – Askar Sep 16 '15 at 06:43
  • 1
    Not sure if will help [CalendarUtil](http://www.gwtproject.org/javadoc/latest/com/google/gwt/user/datepicker/client/CalendarUtil.html) or maybe [Date time library for gwt](http://stackoverflow.com/questions/10311754/date-time-library-for-gwt) – MadProgrammer Sep 16 '15 at 06:47
  • @MadProgrammer, Thanks, i use Date now = new Date(); CalendarUtil.addDaysToDate(now, 7); and worked precisely. – Askar Sep 16 '15 at 06:55
  • 7
    Your original program works correctly. The difference between "Wed Sep 16 09:52:36 IRDT 2015" and "Wed Sep 23 08:52:36 IRST 2015" is exactly one week. If the second date would be "Wed Sep 23 09:52:36 IRST 2015" the difference would be one week and one hour, which does not match your requirement "precisely calculate the time one week". Or did you mean "the same time on the same weekday in approximately one week"? – simon Sep 16 '15 at 09:05
  • 1
    Duh duh du-daaaah, [Rule #9](http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time) – Tobia Tesan Sep 16 '15 at 13:03
  • ...*and* [Rule #37](http://infiniteundo.com/post/25509354022/more-falsehoods-programmers-believe-about-time) – Tobia Tesan Sep 16 '15 at 13:09
  • @simon You are right, i will use my code, thanks for your comments – Askar Sep 17 '15 at 05:38

4 Answers4

14

Never, ever rely on millisecond arithmetic, there are too many rules and gotchas to make it of any worth (even over a small span of time), instead use a dedicated library, like Java 8's Time API, JodaTime or even Calendar

Java 8

LocalDateTime now = LocalDateTime.now();
LocalDateTime then = now.plusDays(7);

System.out.println(now);
System.out.println(then);

Which outputs

2015-09-16T15:34:14.771
2015-09-23T15:34:14.771

JodaTime

LocalDateTime now = LocalDateTime.now();
LocalDateTime then = now.plusDays(7);

System.out.println(now);
System.out.println(then);

Which outputs

2015-09-16T15:35:19.954
2015-09-23T15:35:19.954

Calendar

When you can't use Java 8 or JodaTime

Calendar cal = Calendar.getInstance();
Date now = cal.getTime();
cal.add(Calendar.DATE, 7);
Date then = cal.getTime();

System.out.println(now);
System.out.println(then);

Which outputs

Wed Sep 16 15:36:39 EST 2015
Wed Sep 23 15:36:39 EST 2015

nb: The "problem" you seem to be having, isn't a problem at all, but simply the fact that over the period, your time zone seems to have entered/exited day light savings, so Date is displaying the time, with it's correct offset

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • This code works only if the user happens to be in a time zone, where there is no time zone change between the two dates. For example, adding the line - cal.setTimeZone(TimeZone.getTimeZone("Iran")); - in your "Calendar" example would produce a differnet output. And consequently, the examples would not work for users (e.g. the original poster) who have Iran as their default time zone. – simon Sep 16 '15 at 09:01
  • Taking a given Date and adding 7 days to it should have little effect on the underlying representation of the Date, how the format of the date is represented would come down to local specific requirements, but the underlying millisecond representation would remain the same, because it's base on a single point of time. Besides, my argument isn't about how the formatting of the date value my change, but what are better mechanisms for dat arithmetic – MadProgrammer Sep 16 '15 at 09:23
  • I agree. However, the result is not any different than just adding the milliseconds as in the OP's example. The problem OP experiences comes from the different time zone representation of the two dates, and cannot be solved by adding the 7 days in a different manner. – simon Sep 16 '15 at 09:27
  • 1
    Then their isn't actual a problem (other then the fact they are using a bad approach to achieve it), the fact that there has been a change in daylight savings doesn't change the fact the result is still +7 days in the future, with offset – MadProgrammer Sep 16 '15 at 09:30
1

Try this

Calendar cal = Calendar.getInstance();

System.out.println(cal.getTime());

cal.add(Calendar.DAY_OF_MONTH, 7);

System.out.println(cal.getTime());
Siva Kumar
  • 1,983
  • 3
  • 14
  • 26
1

The difference is because of the different timezone. IRDT is +0430 and IRST is +0330

To overcome this issue you can use the JodaTime.

LocalDateTime now = LocalDateTime.now();
LocalDateTime nextweek = now.plusDays(7);
System.out.println(now);
System.out.println(nextweek);
Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
1

As other said. It would be better to use Calendar or JodaTime library. But the question is why you were not getting the desired result. It was because currentTimeMillis() calculates time between "computer time" and coordinated universal time (UTC). Now consider following case.

long DURATION = 7 * 24 * 60 * 60 * 1000;
Date now = new Date();
Date nextWeek = new Date(now.getTime() + DURATION);
System.out.println("      now: " + now);
System.out.println("next week: " + nextWeek);

here Date.getTime() calculate time from 00:00:00 GMT every time and then when converted to string will give time for your local time zone.

Edit : I was wrong. The reason is as simon said.

The actual "why" is that IRDT (Iran Daylight Time) ends on September 22nd. That's why the first date (September 16th) in the OP's post is displayed as IRDT and the second date (September 23rd) is displayed as IRST. Because IRST (Iran Standard Time) is one hour earlier than IRDT the time displayed is 08:52:36 instead of 09:52:36.

Community
  • 1
  • 1
afzalex
  • 8,598
  • 2
  • 34
  • 61
  • @Alen could you tell me your TImeZone and locale? – afzalex Sep 16 '15 at 06:05
  • 4
    The actual "why" is that IRDT (Iran Daylight Time) ends on September 22nd. That's why the first date (September 16th) in the OP's post is displayed as IRDT and the second date (September 23rd) is displayed as IRST. Because IRST (Iran Standard Time) is one hour earlier than IRDT the time displayed is 08:52:36 instead of 09:52:36. – simon Sep 16 '15 at 08:53