问题
I need to iterate through a range of dates. Not sure on how to take next day in for loop.
I am using java.util.Date
. So plusDays(1)
cannot be used in the for loop for taking next date.
Used date1 = new Date(date1.getTime() + (1000 * 60 * 60 * 24))
in for loop. But I don't think its a good idea to create objects by calling new each time in for loop.
Please suggest a better way for taking next day in for loop.
回答1:
tl;dr
LocalDate.now().plusDays( 1 ) // Get tomorrow's date.
Avoid legacy date-time classes.
Never use java.util.Date
.
That terrible class was supplanted years ago by the modern java.time classes defined in JSR 310. Ditto for Calendar
, GregorianCalendar
, and SimpleDateFormat
.
LocalDate
For a date-only value, without time-of-day and without time zone, use LocalDate
class.
Call LocalDate.now
to get the current date.
For any particular moment, the date varies around the globe by time zone. So, specify the time zone by which you want to view the date. If omitted, you get the JVM’s current default time zone implicitly applied.
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ; // Capture the current date as seen in a particular time zone.
for ( int i = 0 ; i < 7 ; i++ )
{
LocalDate localDate = today.plusDays( i );
System.out.println( "localDate = " + localDate );
}
When run.
localDate = 2020-12-17
localDate = 2020-12-18
localDate = 2020-12-19
localDate = 2020-12-20
localDate = 2020-12-21
localDate = 2020-12-22
localDate = 2020-12-23
If you are comfortable with Java streams, use LocalDate::datesUntil
.
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ); // Capture the current date as seen in a particular time zone.
today.datesUntil( today.plusWeeks( 1 ) ).forEach( System.out :: println );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 brought some minor features and fixes.
- Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android (26+) bundle implementations of the java.time classes.
- For earlier Android (<26), a process known as API desugaring brings a subset of the java.time functionality not originally built into Android.
- If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
回答2:
You can use plusDays()
by converting your Date into LocalDate:
import java.util.*;
import java.time.*;
public class MyClass {
public static void main(String args[]) {
Date date = new Date();
LocalDate dateCopy = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
System.out.println("Date: " + dateCopy);
for(int counter = 1; counter <= 5; counter++){
dateCopy = dateCopy.plusDays(1);
System.out.println("Date: " + dateCopy);
}
}
}
Notice that I use the same dateCopy
variable, since plusDays() return a copy of LocalDate
and I don't want to create new variables.
Codes above will produce the following console logs:
Date: 2020-12-17
Date: 2020-12-18
Date: 2020-12-19
Date: 2020-12-20
Date: 2020-12-21
Date: 2020-12-22
回答3:
All the existing answers are great. This answer provides some additional information which can also solve your problem or at least lead you in the right direction.
Using the modern API:
import java.time.LocalDate;
class Main {
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2020, 12, 5);// 5th Dec 2020
LocalDate endDate = LocalDate.of(2020, 12, 15);// 15th Dec 2020
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
System.out.println(date);
}
}
}
Output:
2020-12-05
2020-12-06
2020-12-07
2020-12-08
2020-12-09
2020-12-10
If you have dates as string objects:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("d/M/uuuu");
LocalDate startDate = LocalDate.parse("5/12/2020", dtf);// 5th Dec 2020
LocalDate endDate = LocalDate.parse("10/12/2020", dtf);// 10th Dec 2020
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
System.out.println(date);
}
}
}
Output:
2020-12-05
2020-12-06
2020-12-07
2020-12-08
2020-12-09
2020-12-10
Using the legacy API:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.set(2020, 11, 5);// 5th Dec 2020
Date startDate = calendar.getTime();
calendar.set(2020, 11, 10);// 10th Dec 2020
Date endDate = calendar.getTime();
SimpleDateFormat sdfForOutput = new SimpleDateFormat("yyyy-MM-dd");
Date date = startDate;
for (calendar.setTime(startDate); !date.after(endDate); calendar.add(Calendar.DAY_OF_YEAR,
1), date = calendar.getTime()) {
System.out.println(sdfForOutput.format(date));
}
}
}
Output:
2020-12-05
2020-12-06
2020-12-07
2020-12-08
2020-12-09
2020-12-10
If you have dates as string objects:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdfForParsing = new SimpleDateFormat("d/M/yyyy");
Date startDate = sdfForParsing.parse("5/12/2020");// 5th Dec 2020
Date endDate = sdfForParsing.parse("10/12/2020");// 10th Dec 2020
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sdfForOutput = new SimpleDateFormat("yyyy-MM-dd");
Date date = startDate;
for (calendar.setTime(startDate); !date.after(endDate); calendar.add(Calendar.DAY_OF_YEAR,
1), date = calendar.getTime()) {
System.out.println(sdfForOutput.format(date));
}
}
}
Output:
2020-12-05
2020-12-06
2020-12-07
2020-12-08
2020-12-09
2020-12-10
Note that the date-time API of java.util
and their formatting API, SimpleDateFormat
are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API. Learn more about the modern date-time API at Trail: Date Time.
Note: For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
回答4:
As the others said, avoid using java.util.Date
if there’s any way you can. Prefer the good answer by Basil Bourque.
Sometimes we need to interoperate with legacy code that uses the legacy date-time classes as Date
and that we cannot afford to upgrade to java.time right away.
If you get a
Date
form a legacy API, use the answer by ariefbayu.If the other way around for each date iterated you need an old-fashioned
Date
object for a legacy API, I will show you how.LocalDate startDateInclusive = LocalDate.of(2021, Month.MARCH, 12); LocalDate endDateExlusive = LocalDate.of(2021, Month.MARCH, 17); startDateInclusive.datesUntil(endDateExlusive) .map(d -> d.atStartOfDay(ZoneId.systemDefault())) .map(ZonedDateTime::toInstant) .map(Date::from) .forEach(System.out::println);
I ran this snippet in America/Cambridge_Bay
time zone and got this output:
Fri Mar 12 00:00:00 MST 2021 Sat Mar 13 00:00:00 MST 2021 Sun Mar 14 00:00:00 MST 2021 Mon Mar 15 00:00:00 MDT 2021 Tue Mar 16 00:00:00 MDT 2021
LocalDate.datesUnitil()
gives us a stream of LocalDate
s. Through a series of map
operations I convert each LocalDate
to a Date
, which I finally print. Instead of printing you will want to call one or more legacy methods, for example:
.forEach(jud -> {
someLegayMethod(jud);
someOtherLegacyMethod(jud, "some other argument");
});
In the output above you will notice that Java knows that summer time (DST) is introduced on March 14, so from March 15 the time zone abbreviation is MDT
for Mountain Daylight Time rather than MST
for Mountain Standard Time. There are really only 23 hours between those two Date
objects when they both fall at 00:00.
Used
date1 = new Date(date1.getTime() + (1000 * 60 * 60 * 24))
in for loop. But I don't think its a good idea to create objects by calling new each time in for loop.
Creating a new object each time is no problem (except in very special situations). There are a couple of other reasons why your code is not good:
It’s a bad habit to do our own time math. We should rely on the library classes because
a. it gives code that is clearer to read
b. date and time math is most often more complicated than we think and therefore easy to get wrong; specifically we may miss a lot of corner cases, which often goes unnoticed in test.
Your code assumes that a day is always 24 hours. As I said above, this is not the case.
Link
Oracle tutorial: Date Time explaining how to use java.time.
来源:https://stackoverflow.com/questions/65335253/iterate-over-dates-in-java