Adding days with java.util.Calendar gives strange results

Using java.util.Calendar to add one day to the date and SimpleDateFormat to display the result, it sometimes seems to lose a day (usually in March), and sometimes skips a day (in November).

The program below, with the release, illustrates the problem. Notice that I just add one day at a time, and then skip a few months and add a few more days. You will see that 2008-03-09 is printed twice, but 2008-11-02 is skipped. The same thing happens in other years, but on different days. I had to experiment to find the days that are causing the problem.

If I do not set the time zone for UTC in SimpleDateFormat, then the problem does not occur. I ran this on a machine in the US Central Time Zone.

This certainly looks like an error in the calendar or SimpleDateFormat, but I could not find it documented anywhere. Anyone explain what is going on here?

Program:

package mab; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; public class CalendarHiccup2 { public static void main(String[] args) { addDays("2008-03-08"); addDays("2009-03-07"); addDays("2010-03-13"); } public static void addDays(String dateString) { System.out.println("Got dateString: " + dateString); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); Calendar calendar = Calendar.getInstance(); try { calendar.setTime(sdf.parse(dateString)); Date day1 = calendar.getTime(); System.out.println(" day1 = " + sdf.format(day1)); calendar.add(java.util.Calendar.DAY_OF_MONTH, 1); Date day2 = calendar.getTime(); System.out.println(" day2 = " + sdf.format(day2)); calendar.add(java.util.Calendar.DAY_OF_MONTH, 1); Date day3 = calendar.getTime(); System.out.println(" day3 = " + sdf.format(day3)); calendar.add(java.util.Calendar.DAY_OF_MONTH, 1); Date day4 = calendar.getTime(); System.out.println(" day4 = " + sdf.format(day4)); // Skipping a few days ahead: calendar.add(java.util.Calendar.DAY_OF_MONTH, 235); Date day5 = calendar.getTime(); System.out.println(" day5 = " + sdf.format(day5)); calendar.add(java.util.Calendar.DAY_OF_MONTH, 1); Date day6 = calendar.getTime(); System.out.println(" day6 = " + sdf.format(day6)); calendar.add(java.util.Calendar.DAY_OF_MONTH, 1); Date day7 = calendar.getTime(); System.out.println(" day7 = " + sdf.format(day7)); calendar.add(java.util.Calendar.DAY_OF_MONTH, 1); Date day8 = calendar.getTime(); System.out.println(" day8 = " + sdf.format(day8)); } catch (Exception e) { } } } 

Output:

 Got dateString: 2008-03-08 day1 = 2008-03-08 day2 = 2008-03-09 day3 = 2008-03-09 day4 = 2008-03-10 day5 = 2008-10-31 day6 = 2008-11-01 day7 = 2008-11-03 day8 = 2008-11-04 Got dateString: 2009-03-07 day1 = 2009-03-07 day2 = 2009-03-08 day3 = 2009-03-08 day4 = 2009-03-09 day5 = 2009-10-30 day6 = 2009-10-31 day7 = 2009-11-02 day8 = 2009-11-03 Got dateString: 2010-03-13 day1 = 2010-03-13 day2 = 2010-03-14 day3 = 2010-03-14 day4 = 2010-03-15 day5 = 2010-11-05 day6 = 2010-11-06 day7 = 2010-11-08 day8 = 2010-11-09 
+2
source share
4 answers

This is due to summer time and is completely correct.

Time (in the northern hemisphere) moves forward by one hour, usually in March, and returns in November.

+3
source

This is more like the problem of saving time per day, which changes in Mar and November. Can you try to set the time element at 00:00:00? If you do this,

 addDays("2008-03-08 00:00:00"); addDays("2009-03-07 00:00:00"); addDays("2010-03-13 00:00:00"); 

and change the format to,

 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 

you will see the difference that it makes in the elements of time.

+2
source

When you have such problems, you need to print out the Calendar and Date instances to find out what is happening.

Following:

 sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 

changes the time of your calendar depending on your local JVM time (and time zone). Calendar.getInstance(); creates a calendar in your JVM local time when you do calendar.setTime(sdf.parse(".....")) , which sets the time in UTC (considering how you created sdf!). Depending on the DoY (and the year!), Which can make you pass midnight, and when you print your date using the yyyy-MM-dd format, you see a difference of one day.

Print a complete calendar and full date, and you will understand what is happening!

0
source

Summer time

The answer of Tomash Nurkevich is correct, the problem is Daylight Saving Time (DST).

local time changes at 02:00 local standard time until 03:00 local time on the second Sunday of March and returns at 02:00 local daylight until 01:00 local standard time on the first Sunday of November.

See Wikipedia on Central Time Zone

Joda time

The Joda-Time library simplifies this work.

A DateTime in Joda-Time knows its own time zone . To use UTC / GMT (no time offset), pass the built-in constant DateTimeZone.UTC .

To print only part of a date, use DateTimeFormatter .

 // © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so. // import org.joda.time.*; // import org.joda.time.format.*; String dateString = "2008-03-08"; // withTimeAtStartOfDay() is probably superfluous in this example, but I like that it self-documents our focus on the day rather than a particular time of day. DateTime dateTime = new DateTime( dateString, DateTimeZone.UTC ).withTimeAtStartOfDay(); DateTime dateTimePlus1 = dateTime.plusDays( 1 ).withTimeAtStartOfDay(); DateTime dateTimePlus2 = dateTime.plusDays( 2 ).withTimeAtStartOfDay(); DateTime dateTimePlus3 = dateTime.plusDays( 3 ).withTimeAtStartOfDay(); 

Dump for console ...

 System.out.println("dateTime: " + dateTime ); System.out.println("dateTime (date portion): " + ISODateTimeFormat.date().withZone( DateTimeZone.UTC ).print( dateTime ) ); System.out.println("dateTimePlus1: " + dateTimePlus1 ); System.out.println("dateTimePlus2: " + dateTimePlus2 ); System.out.println("dateTimePlus3: " + dateTimePlus3 ); 

At startup ...

 dateTime: 2008-03-08T00:00:00.000Z dateTime (date portion): 2008-03-08 dateTimePlus1: 2008-03-09T00:00:00.000Z dateTimePlus2: 2008-03-10T00:00:00.000Z dateTimePlus3: 2008-03-11T00:00:00.000Z 
0
source

Source: https://habr.com/ru/post/981611/


All Articles