I'm a complete beginner with Java, and I've been making simple test-programs to review some of the material I read. The following block of code works incorrectly. It's supposed to accept a Year, Month, and Date from the user, and then create a GregorianCalendar object initialized with the year, month and date. However, when I try to return the GregorianCalendar variable's month, it always gives back the month I initialized the month variable with. I'm not sure why.
import java.util.*;
public class Prac {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.print("Enter Year: ");
int YEAR = input.nextInt();
System.out.print("Enter Month: ");
String MONTH_STRING = input.next();
System.out.print("Enter Date: ");
int DATE = input.nextInt();
int MONTH = 10;
String mon = MONTH_STRING.toLowerCase();
if (mon == "january") {
MONTH = 0;
} else if (mon == "february") {
MONTH = 1;
} else if (mon == "march") {
MONTH = 2;
} else if (mon == "april") {
MONTH =3;
} else if (mon == "may"){
MONTH =4;
} else if (mon == "june"){
MONTH =5;
} else if (mon == "july"){
MONTH =6;
} else if (mon == "august"){
MONTH=7;
} else if (mon == "september"){
MONTH=8;
} else if (mon == "october"){
MONTH=9;
} else if (mon == "november"){
MONTH=10;
} else if (mon == "december"){
MONTH =11;
}
GregorianCalendar entDate = new GregorianCalendar(YEAR,MONTH,DATE);
System.out.println(entDate.get(Calendar.MONTH));
}
}
Also, I'm aware I could have used a switch block, but it gave me strange errors somehow.
String.equals
You're comparing Strings incorrectly.
The == operator checks to see if the Objects are the same -- meaning same memory location and everything.
What you want to do is the String::equals method.
if(mon.equals("january") {
...
} else if(mon.equals("feburary") {
...
} ...
This will check only to see if the value of the string is equal.
Also, unless you're using java 1.7+ you wouldn't be able to use a switch case for Strings. Not really a part of the question, but still good to know.
The Answer by Shaded is correct and should be accepted. You should generally avoid using == comparison with objects, and instead call a method such as equals or isEqual.
Furthermore, you could call String::equalsIgnoreCase method rather than changing the string to be lowercase.
boolean sameIgnoringCase = thisString.equalsIgnoreCase( thatString ) ;
java.time
The modern approach uses the modern java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Compare months by using the Month enum rather than mere numbers or text. That class offers a dozen instances, one for each month of the year.
Month month = ld.getMonth() ; // Get `Month` enum object.
You can switch on an enum.
switch( month ) {
case JANUARY:
…
case FEBRUARY:
…
default:
…
}
Note that a quirk in Java means you cannot prefix the JANUARY with Month (that is, Month.JANUARY) inside a switch. As a habit, I routinely use the enum class name with the object name, except in a switch where it is forbidden.
Also, you may find the EnumSet and EnumMap handy.
Set< Month > winter = EnumSet.of( Month.DECEMBER , Month.JANUARY , Month.FEBRUARY ) ;
boolean isWinter = winter.contains( myLocalDate.getMonth() ) ;
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Related
I'm trying to get Months from a certain quarter. Using the code below, I successfully get the names of the months in the current quarter from the LocalDate.now() instance.
How would I get a quarter's months from just a quarter String (e.g. "Q1")?
int monthInt = Month.from(LocalDate.now()).firstMonthOfQuarter().getValue();
for (int j = 1; j <= 3; j++) { //for each month in quarter
System.out.println(Month.of(monthInt).name()); //January, February, March
monthInt++;
}
We can find out how the JDK calculates the quarter by looking at the declaration of getFrom of IsoFields.QUARTER_OF_YEAR:
public long getFrom(TemporalAccessor temporal) {
if (isSupportedBy(temporal) == false) {
throw new UnsupportedTemporalTypeException("Unsupported field: QuarterOfYear");
}
long moy = temporal.getLong(MONTH_OF_YEAR);
return ((moy + 2) / 3);
}
Notice how it uses the formula quarter = (moy + 2) / 3. Therefore, to find the starting month of a quarter, we just need to rearrange it in terms of moy - moy = quarter * 3 - 2.
You can write a method like this:
private static List<String> monthNamesFromQuarter(int quarter) {
// you can do the validation of quarter yourself
int start = quarter * 3 - 2;
return IntStream.range(start, start + 3)
.mapToObj(Month::of)
.map(Month::name)
.collect(Collectors.toList());
}
tl;dr
Use org.threeten.extra.YearQuarter class, along with Quarter, ZoneId, LocalDate, and Month.
YearQuarter // Represent an entire quarter of a specific year.
.now( ZoneId.of( "Asia/Tokyo" ) ) // Determine the current quarter as seen via the wall-clock time used by the people of a particular region (a time zone).
.with( // Move to another quarter.
Quarter.valueOf( "Q1" ) // Or, `Quarter.of( 1 )` if starting with an integer number rather than a `String` object.
) // Returns another `YearQuarter` object, rather than modifying the original.
.atDay( 1 ) // Returns a `LocalDate` object.
.getMonth() // Returns a `Month` enum object.
.getDisplayName( // Automatically localize the name of the month.
TextStyle.FULL , // How long or abbreviated do you want the translation.
Locale.US // Or Locale.CANADA_FRENCH and so on.
) // Returns a `String` object.
January
YearQuarter in ThreeTen-Extra
The ThreeTen-Extra library has a class you might find useful for this work: YearQuarter.
Get the current quarter. We need a time zone to determine the current date, and therefore the current quarter. For any given moment, the date varies around the globe by time zone.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
YearQuarter currentYearQuarter = YearQuarter.now( z ) ;
But you want to determine a quarter by parsing a string.
If you have a string styled similar to ISO 8601 (the standard does not actually specify quarters) YYYY-Qq then YearQuarter can directly parse.
String input = "2020-Q1" ;
YearQuarter yearQuarter = YearQuarter.parse( input ) ;
If you have only the quarter part without the year, use Quarter enum. If your input string is Q1 and such, use valueOf to retrieve the matching enum object.
String input = "Q1" ;
Quarter quarter = Quarter.valueOf( input ) ;
If you have a number instead of a string, that is, 1 or 2 or 3 or 4, then use static method Quarter.of. By the way, in your own code you should be passing around these Quarter objects rather than a mere integer or string, to make your code more self-documenting, to provide type-safety, and to ensure valid values.
int input = 1 ; // Domain: 1, 2, 3, 4.
Quarter quarter = Quarter.of( input ) ;
Apply that Quarter instance to our current YearQuarter instance to get another YearQuarter instance. These classes use the immutable objects pattern, so we are not modifying existing instance, we are generating new instances.
YearQuarter yearQuarter = currentYearQuarter.with( quarter ) ;
yearQuarter.toString(): 2019-Q1
Get first date (LocalDate), and year-month (YearMonth), and Month enum object, from that year-quarter.
LocalDate firstDate = yearQuarter.atDay( 1 ) ;
YearMonth yearMonth1 = YearMonth.from( firstDate ) ;
YearMonth yearMonth2 = yearMonth1.plusMonths( 1 ) ;
YearMonth yearMonth3 = yearMonth1.plusMonths( 2 ) ;
Generate a string containing the automatically localized name of month.
Locale locale = Locale.US ; // Or Locale.CANADA_FRENCH and so on.
String output1 = yearMonth1.getMonth().getDisplayName( TextStyle.FULL , locale ) ;
January
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.
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 adds 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 bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I suggest we build a map of the months contained in each quarter and make a simple map lookup whenever we need the months for some quarter string. A stream pipeline and an adequate DateTimeFormatter will build such a map in just a few lines:
static Map<String, List<Month>> monthsPerQuarter = Arrays.stream(Month.values())
.collect(Collectors.groupingBy(
DateTimeFormatter.ofPattern("QQQ", Locale.ENGLISH)::format));
IMO the great advantage here is that we need to do no math ourselves. While math converting from quarter number to month number may seem simple for the person writing it, it is not only error-prone, it will also be unclear and hard to decipher for many readers.
Now we can lookup for example like this:
System.out.println(monthsPerQuarter.get("Q3"));
Output is:
[JULY, AUGUST, SEPTEMBER]
If you need the months individually:
monthsPerQuarter.get("Q4").forEach(System.out::println);
OCTOBER
NOVEMBER
DECEMBER
If your quarter was originally a number in the range from 1 through 4, you may use this map instead:
static Map<Integer, List<Month>> monthsPerQuarter = Arrays.stream(Month.values())
.collect(Collectors.groupingBy(m -> m.get(IsoFields.QUARTER_OF_YEAR)));
A reason why I recommend the map approach is: it’s easy to convert from Month to quarter string, but java.time offers no easy way to convert from quarter string to month. Just for the demonstration and not the way I recommend, one might do:
DateTimeFormatter quarterFormatter = new DateTimeFormatterBuilder()
.appendPattern("QQQ")
// Any year will do since all years have the same 4 quarters # the same 3 months
.parseDefaulting(ChronoField.YEAR, 2000)
.parseDefaulting(IsoFields.DAY_OF_QUARTER, 1)
.toFormatter(Locale.ENGLISH);
String qString = "Q1";
Month firstMonthOfQuarter = Month.from(quarterFormatter.parse(qString));
IntStream.range(0, 3)
.mapToObj(firstMonthOfQuarter::plus)
.forEach(System.out::println);
JANUARY
FEBRUARY
MARCH
It’s 11 code lines instead of 4 with no gain that I can see.
For quarter > firstmonth the rule is
Q1 -> 1
Q2 -> 4
Q3 -> 7
Q4 -> 10
With math : quarterValue *3 -2
So applying this in Java :
String quarter = "Q1";
int monthInt = Integer.parseInt(quarter.replaceAll("\\D", "")) * 3 - 2;
for (int j = 0; j < 3; j++) {
System.out.println(Month.of(monthInt + j).name());
}
List<String> quarters = Arrays.asList("Q1", "Q2", "Q3", "Q4");
for (String quarter : quarters) {
System.out.print(quarter);
int monthInt = Integer.parseInt(quarter.replaceAll("\\D", "")) * 3 - 2;
for (int j = 0; j < 3; j++) {
System.out.print(" " + Month.of(monthInt + j).name());
}
System.out.println();
}
Q1 JANUARY FEBRUARY MARCH
Q2 APRIL MAY JUNE
Q3 JULY AUGUST SEPTEMBER
Q4 OCTOBER NOVEMBER DECEMBER
Is there a better way to write this instead of writing multiple if statements?
I'm parsing through a document to find the instances of date and incrementing the int if an instance occurs.
public class OrganisingData {
static int jan16=0;
static int feb16=0;
static int mar16=0;//... static int dec18
public static void Months(String dates) {
if (dates.substring(2, 4).equals("16") &&
dates.substring(5,7).equals("01")) {
jan16++;
}
if (dates.substring(2, 4).equals("16") &&
dates.substring(5,7).equals("02")) {
feb16++;...
}
if (dates.substring(2, 4).equals("18") &&
dates.substring(5,7).equals("12")) {
dec18++;
}
}
}
I am trying to build a bar chart and jan16 feb16 etc represent the month and the year and each time i find an insistence of that date (eg. 2016-01-15) i would increment jan16. so instead of writing multiple if statements for each month + year (total of 32 if statements)is there a better way to write this?
Basically a mix of what #John T and #Zachary said, but with proper syntax and type conversion.
// [Years] and [Months], where [0][0] is jan 2000. May need to adjust for previous years.
int[][] days = new int[30][12];
void month(String dates) {
int year = Integer.parseInt(dates.substring(2, 4));
int month = Integer.parseInt(dates.substring(5,7)) - 1;
days[year][month]++;
}
You could use a switch statement to reduce the clunky logic, though this wouldn't necessarily condense greatly. You will either need to use Strings with the Switch or convert the day/month values to an integer.
String day = dates.substring(2, 4);
String month = dates.substring(5, 7);
switch (month) {
case "01" : {
if (day.equals("16"))
jan16++;
break;
}
}
If there is some pattern behind what you are wanting to do, there may be a better solution. For example, the following would count 16th of each month
int count[] = new int[12];
...
int day = Integer.parseInt(dates.substring(2, 4));
int month = Integer.parseInt(dates.substring(5, 7));
if (day == 16)
count[month - 1]++;
YearMonth
Apparently you want to track year-month values. There's a class for that, named, well, YearMonth. Find this class in the java.time package that supplants the terribly troublesome old date-time classes bundled with the earliest versions of Java.
MonthDay
Or maybe you are shooting for month-day values; your Question is convoluted so I am not sure of your goal. But if this is your goal, again, there’s a class for that: MonthDay.
Month
Or maybe you want just the month regardless of year or day-of-month, in which case you can use the Month class.
LocalDate
If your inputs strings represent a year and month and day-of-month, parse as a LocalDate. This class has no time-of-day and no time zone.
LocalDate ld = LocalDate.parse( "2016-01-15" ) ;
Extract a YearMonth, MonthDay, or Month.
YearMonth ym = YearMonth.from( ld ) ;
Create a collection. Perhaps you want to keep all a distinct set of the LocalDate objects in a particular year-month. If so, make a Map where each YearMonth object owns a Set of LocalDate objects.
Map < YearMonth, Set < LocalDate > > map = new HashMap <>();
As you process each input date, check to see if the map has a Set yet created for the particular YearMonth of the input. If not, instantiate a TreeSet. The TreeSet class is a SortedSet, meaning it maintains a sorted order as you add values.
Set < LocalDate > set = map.get( ym );
if ( null == set ) {
set = new TreeSet <>(); // A `TreeSet` is a `SortedSet`, maintains a sorted order. You may or may not need this behavior.
map.put( ym , set );
}
With a Set in hand, add your LocalDate.
set.add( ld );
After processing, you can get a collection of the YearMonth keys from your Map. And for each of those, you can retrieve the Set it owns, and get a count of the elements contained.
Lamba & Streams
For shorter code, you might be able to use Lambda syntax & Streams with Map::computeIfAbsent. I've seen this kind of code but have not yet tried it.
map.computeIfAbsent( key , k -> new TreeSet< LocalDate >() ).add( ld ) ;
Count only
If you want only the count, and don't care about the LocalDate values, replace Set as the “value” or you Map with a Integer object. Instead of retrieving the Set and adding to it, retrieve the Integer and increment it by adding one. Personally, in this kind of situation I find it best to collect the LocalDate values to be examined for debugging/testing and/or for further use in other business logic.
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Using appropriate data structures, you can greatly reduce this code.
The idea is to have a data structure that for each year you're interested in, holds an array of ints: one for each month.
Then, converting the substrings from the dates String to numbers, you can use those numbers to index the data structure.
import java.util.Map;
import java.util.HashMap;
private static Map<Integer, int[]> years = new HashMap<>();
private static String[] monthNames = new String[] {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static {
for(int year = 16; year <= 18; year++) {
years.put(year, new int[12]);
}
}
public static void months(String dates) { // method names should start with lower case
int year = Integer.parseInt(dates.substring(2, 4));
int month = Integer.parseInt(dates.substring(5, 7)) - 1; // date String is one-based, array-index is zero-based
years.get(year)[month]++;
}
public static void print() {
for(int year = 16; year <= 18; year++) {
int[] monthCounts = years.get(year);
for(int month = 0; month < 12; month++) {
System.out.println(monthNames[month] + " " + year + ": " + monthCounts[month]);
}
}
}
You can see the code in action here.
Loop through your document with this:
// 18 years(more needed?), 12 months
String[][] yearsAndMonths = new String[18][12];
yearsAndMonths[dates.substring(5,7)][dates.substring(2, 4)]++;
Then print the results.
I'm not a java expert. Code just provided to give you the logic.
I'm trying to create a function in Java that generates a quarterly date sequence, given a start and end date.
In R, for example, I can do this as follows:
generateQuarterlySequence = function(startDate, endDate)
{
require(zoo)
# Generate date sequence
dateSequence = seq.Date(from = as.Date(startDate),
to = as.Date(endDate),
by = "quarter")
# Convert to quarters
dateSequence = as.yearqtr(dateSequence, format = "%Y-%m-%d")
# Get rid of extra white space
dateSequence = gsub(" ", "", dateSequence)
return(dateSequence)
}
generateQuarterlySequence(startDate = "2017-06-30", endDate = "2017-12-31")
[1] "2017Q2" "2017Q3" "2017Q4"
Any rock stars care to show how this is done in Java? You'd be making this Java beginner very happy!
Cheers,
Joe
I know that in a comment I suggested ThreeTen-Extra. However, here’s a solution using pure java.time as built-in in Java 8 and later and available in Java 6 and 7 through ThreeTen Backport.
public static List<String> generateQuarterlySequence(LocalDate startDate, LocalDate endDate) {
// first truncate startDate to first day of quarter
int startMonth = startDate.getMonthValue();
startMonth-= (startMonth - 1) % 3;
startDate = startDate.withMonth(startMonth).withDayOfMonth(1);
DateTimeFormatter quarterFormatter
= DateTimeFormatter.ofPattern("uuuuQQQ", Locale.ENGLISH);
List<String> quarterSequence = new ArrayList<>();
// iterate thorough quarters
LocalDate currentQuarterStart = startDate;
while (! currentQuarterStart.isAfter(endDate)) {
quarterSequence.add(currentQuarterStart.format(quarterFormatter));
currentQuarterStart = currentQuarterStart.plusMonths(3);
}
return quarterSequence;
}
Trying it with your example arguments:
System.out.println(generateQuarterlySequence(LocalDate.of(2017, Month.JUNE, 30),
LocalDate.of(2017, Month.DECEMBER, 31)));
prints
[2017Q2, 2017Q3, 2017Q4]
tl;dr
YearQuarter.from( LocalDate.parse( "2017-06-30" ) )
.plusQuarters( 1 )
org.threeten.extra.YearQuarter
The other Answer by Ole V.V. using java.time is good. Alternatively, here is code using the YearQuarter class from the ThreeTen-Extra project that extends java.time with additional functionality. If you are doing much work with quarters, you will find it well worth the bother to add the ThreeTen-Extra library to your project.
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate start = LocalDate.parse( "2017-06-30" );
LocalDate stop = LocalDate.parse( "2017-12-31" );
From those, determine the year-quarter in the ISO 8601 calendar system, meaning Q1 is January to March, Q2 is April to June, Q3 is July to September and Q4 is October to December.
YearQuarter yqStart = YearQuarter.from( start );
YearQuarter yqStop = YearQuarter.from( stop );
Collect the series of quarters as a List.
int initialCapacity = ( int ) ( ChronoUnit.YEARS.between( start , stop ) + 1 ) * 4;
List < YearQuarter > quarters = new ArrayList <>( initialCapacity );
Loop each quarter, incrementing by calling plusQuarters, and collect into the list.
YearQuarter yq = yqStart;
while ( ! yq.isAfter( yqStop ) )
{
quarters.add( yq );
// Setup next loop.
yq = yq.plusQuarters( 1 );
}
Dump to console.
System.out.println( start + "/" + stop + " = " + quarters );
2017-06-30/2017-12-31 = [2017-Q2, 2017-Q3, 2017-Q4]
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
My library Time4J enables following very simple solution using the streaming-API of Java-8:
DateInterval range =
DateInterval.between(
PlainDate.of(2017, 6, 30),
PlainDate.of(2017, 12, 31)
);
range.stream(Duration.of(1, CalendarUnit.QUARTERS))
.map(CalendarQuarter::from)
.forEach(System.out::println);
// 2017-Q2
// 2017-Q3
// 2017-Q4
The code first constructs a date interval which is streamable. You can define a stream by iteratively adding a quarter year to the start date of the interval. The map-operation maps the generated (gregorian) dates in the stream to the desired year-quarter, called CalendarQuarter in Time4J and finally calls its toString()-method to produce the output.
If you prefer to eliminate the hyphen in the output then you can either apply a simple string-replace-method in another map-method or use a suitable formatter (which should best be stored in a static constant since it is immutable):
ChronoFormatter<CalendarQuarter> f =
ChronoFormatter.ofPattern(
"uuuuQQQ", PatternType.CLDR, Locale.ROOT, CalendarQuarter.chronology());
range.stream(Duration.of(1, CalendarUnit.QUARTERS))
.map(CalendarQuarter::from)
.map(cq -> f.format(cq))
.forEach(System.out::println);
// 2017Q2
// 2017Q3
// 2017Q4
The last piece of code could even be simplified by leaving out the intermediate type CalendarQuarter because a gregorian date (here: PlainDate) can also be formatted as quarterly date in the same way (one map-operation less).
Here is solution using plain Java 8 streams and java.time api:
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2000, 12, 25);
LocalDate endDate = LocalDate.of(2002, 4, 1);
Stream<LocalDate> quarterBounds = Stream.iterate(
startDate.with(IsoFields.DAY_OF_QUARTER, 1), date -> date.plus(3, MONTHS));
DateTimeFormatter quarterFormatter =
DateTimeFormatter.ofPattern("uuuuQQQ", Locale.ENGLISH);
quarterBounds
.filter(d -> !endDate.isBefore(d))
.peek(System.out::println)
.map(quarterFormatter::format)
.forEach(System.out::println);
}
Sample output:
2000-10-01
2000Q4
2001-01-01
2001Q1
2001-04-01
2001Q2
2001-07-01
2001Q3
2001-10-01
2001Q4
2002-01-01
2002Q1
2002-04-01
2002Q2
Via How to get the first date and last date of current quarter in java.util.Date.
How can I get (java.util.Date) date list from specific year and month
Example : I have a year like as '2017' and month name like as 'February' I want to get date list of February or any other months.
such as
2017-02-01,
2017-02-02,
2017-02-03,
2017-02-04,
2017-02-05,
2017-02-06,
2017-02-07
....
2017-02-28.
Please help me sample code, Thanks
java.time
The java.util Date-Time API 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*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
List<LocalDate> getDateList(int year, String monthname) {
int month = Month.valueOf(monthname.toUpperCase()).getValue();
return IntStream
.rangeClosed(1, YearMonth.of(year, month).lengthOfMonth())
.mapToObj(i -> LocalDate.of(year, month, i))
.collect(Collectors.toList());
}
Demo:
import java.time.LocalDate;
import java.time.Month;
import java.time.YearMonth;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
// Test
getDateList(2017, "February").forEach(System.out::println);
System.out.println("=*==*==*=*=");
getDateList(2016, "February").forEach(System.out::println);
}
static List<LocalDate> getDateList(int year, String monthname) {
int month = Month.valueOf(monthname.toUpperCase()).getValue();
return IntStream
.rangeClosed(1, YearMonth.of(year, month).lengthOfMonth())
.mapToObj(i -> LocalDate.of(year, month, i))
.collect(Collectors.toList());
}
}
Output:
2017-02-01
2017-02-02
...
...
...
2017-02-27
2017-02-28
=*==*==*=*=
2016-02-01
2016-02-02
...
...
...
2016-02-28
2016-02-29
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* 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.
java.time
Use the modern date-time classes, in the java.time package.
String input = "2017 February" ;
Parse as a YearMonth object. Define a formatting pattern to match your input.
String input = "2017 February";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "uuuu MMMM" , Locale.US );
YearMonth ym = YearMonth.parse ( input , f );
Loop for the number of days in that month. For each day-of-month, get a LocalDate object.
System.out.println ( "===== Days of " + ym + " =====" );
for ( int i = 1 ; i <= ym.lengthOfMonth () ; i ++ ) {
LocalDate localDate = ym.atDay ( i );
System.out.println ( localDate ); // Uses standard ISO 8601 format by default when generating a string.
}
System.out.println ( "=================" );
===== Days of 2017-02 =====
2017-02-01
2017-02-02
2017-02-03
…
You can see that code run live at IdeOne.com.
If you want to see this kind of code written using Java Streams, see my Question: Use Java streams to collect objects generated in a for loop
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
First, you need to find the number of days you can get for a specific month, this is easy with Calendar.getActualMaximum(int field)
Returns the maximum value that the specified calendar field could have, given the time value of this Calendar. For example, the actual maximum value of the MONTH field is 12 in some years, and 13 in other years in the Hebrew calendar system.
From this, just use a loop to create every value (or might be easier with Stream API, but I am not good with it...).
Here is a simple example of the usage of this method (not the answer at all):
Calendar c = Calendar.getInstance();
for(int i = 0; i <= c.getActualMaximum(Calendar.MONTH); ++i){
c.set(Calendar.MONTH, i);
System.out.format("There is %d days in %d\n", c.getActualMaximum(Calendar.DAY_OF_MONTH), c.get(Calendar.MONTH));
}
Output :
There is 31 days in 0
There is 28 days in 1
There is 31 days in 2
There is 30 days in 3
There is 31 days in 4
There is 30 days in 5
There is 31 days in 6
There is 31 days in 7
There is 30 days in 8
There is 31 days in 9
There is 30 days in 10
There is 31 days in 11
You can use this :
First you should to get the first day from date from your input year and month 2017/February
Second you should to get the number of days of this month
Third you should to loop until the number to your days in your case from 1 to 28 and add a day to your date
public static void main(String[] args) throws ParseException {
int year = 2017;
String month = "February";
SimpleDateFormat format = new SimpleDateFormat("yyyy/MMMM", Locale.US);
Date utilDate = format.parse(year + "/" + month);
//get first day of your month
System.out.println(new SimpleDateFormat("yyyy/MM/dd").format(utilDate));
//get days of months
Calendar cal = Calendar.getInstance();
cal.setTime(utilDate);
int monthMaxDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
//loop and add a day to your date
for (int i = 0; i < monthMaxDays - 1; i++) {
cal.add(Calendar.DATE, 1);
System.out.println(new SimpleDateFormat("yyyy/MM/dd").format(cal.getTime()));
}
}
See this code run live at IdeOne.com.
Good luck
As part of solution I created this high order property to get an array of dates from current month. This was for Android below API level 26.
val daysOfMonth: List<Date>
get() {
val cal = Calendar.getInstance()
val start = cal.getActualMinimum(Calendar.DAY_OF_MONTH)
val ends = cal.getActualMaximum(Calendar.DAY_OF_MONTH)
val days = mutableListOf<Date>()
for (i in start..ends) {
cal.set(Calendar.DAY_OF_MONTH, i)
days.add(cal.time)
}
return days
}
I have used JODA-data time to make my life easier and here is the solution:
package com.github.dibyaranjan.service;
import org.joda.time.DateTime;
public class Test {
public static void main(String[] args) {
DateTime dateTime = new DateTime();
dateTime = dateTime.withDate(2017, 02, 01); // Used the date and time mentioned in your question
int currentMonth = dateTime.getMonthOfYear();
boolean isCurrentMonth = true;
while (isCurrentMonth) {
isCurrentMonth = (dateTime.getMonthOfYear() == currentMonth);
if (isCurrentMonth) {
String dateTimeFormatter = "yyyy-MM-dd";
System.out.println(dateTime.toString(dateTimeFormatter));
}
dateTime = dateTime.plusDays(1);
}
}
}
Suppose the following code is executed on the 22nd of August 2009 (a Saturday)
Calendar c = Calendar.getInstance();
c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
c.get(Calendar.DAY_OF_MONTH) will return 23. I'm interested in the conditions is would return 14 (last Sunday, rather than the next Sunday).
Are there any rules associated with the direction Calendar will roll the DAY_OF_MONTH/YEAR when DAY_OF_WEEK is set? If so what are they?
It should always keep the same WEEK_OF_MONTH (http://java.sun.com/j2se/1.4.2/docs/api/java/util/Calendar.html#WEEK_OF_MONTH). From the documentation:
When setting or getting the
WEEK_OF_MONTH or WEEK_OF_YEAR fields,
Calendar must determine the first week
of the month or year as a reference
point. The first week of a month or
year is defined as the earliest seven
day period beginning on
getFirstDayOfWeek() and containing at
least getMinimalDaysInFirstWeek() days
of that month or year. Weeks numbered
..., -1, 0 precede the first week;
weeks numbered 2, 3,... follow it.
Note that the normalized numbering
returned by get() may be different.
For example, a specific Calendar
subclass may designate the week before
week 1 of a year as week n of the
previous year.
the following formula returns "current" day in a week in range of [0;6]
(d + numberOfDaysInAWeek - firstDayOfWeek) % numberOfDaysInAWeek
or add 1 if you would like range [1;7]
(d + numberOfDaysInAWeek - firstDayOfWeek) % numberOfDaysInAWeek + 1
d is what Calendar.get(Calendar.DAY_OF_WEEK) returns
to get first day of a week, subtract formula's result from current date. The following code does it:
final int currentDayOfWeek = (calendar.get(Calendar.DAY_OF_WEEK) + 7 - cal.getFirstDayOfWeek()) % 7;
cal.add(Calendar.DAY_OF_YEAR, -currentDayOfWeek);
Using java.time
The modern approach is with the java.time classes that supplant the troublesome old legacy date-time classes.
The java.time classes are much easier to work with. In particular, they remove the ambiguity raised in the Question. You can explicitly ask either for the earlier Sunday or for the later Sunday.
The LocalDate class represents a date-only value without time-of-day and without time zone.
The Month enum provides a dozen pre-defined objects, one for each month of the year. These enum objects are safer to use, but you can instead use a plain number for the month. Unlike the legacy classes, these months have sane numbering, 1-12 for January-December.
LocalDate localDate = LocalDate.of( 2009 , Month.AUGUST, 22 );
The TemporalAdjuster interface provides for manipulation of date-time values. The TemporalAdjusters class (note the plural s) provides several handy implementations.
The previous & next adjusters exclude the date itself from consideration. The previousOrSame & nextOrSame methods return the date in question if it is indeed the desired day-of-week.
The DayOfWeek enum provides seven pre-defined objects, one for each day of the week.
LocalDate previousSunday = localDate.with( TemporalAdjusters.previous ( DayOfWeek.SUNDAY ));
LocalDate previousOrSameSunday = localDate.with( TemporalAdjusters.previousOrSame ( DayOfWeek.SUNDAY ));
LocalDate nextSunday = localDate.with( TemporalAdjusters.next ( DayOfWeek.SUNDAY ));
LocalDate nextOrSameSunday = localDate.with( TemporalAdjusters.nextOrSame ( DayOfWeek.SUNDAY ));
Dump to console.
System.out.println ("localDate: " + localDate + " ( " + localDate.getDayOfWeek ().getDisplayName ( TextStyle.FULL, Locale.US ) + " )");
System.out.println ("previousSunday: " + previousSunday );
System.out.println ("nextSunday: " + nextSunday );
localDate: 2009-08-22 ( Saturday )
previousSunday: 2009-08-16
nextSunday: 2009-08-23
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
It depends, actually. Consider the following Java code. It is actually quite simple and I expect it to print the monday preceding 2011-09-18, that is 2011-09-12:
Calendar calendar = Calendar.getInstance(Locale.GERMANY);
System.out.printf("First day of week: %d%n%n", calendar.getFirstDayOfWeek());
calendar.set(2011, Calendar.SEPTEMBER, 18);
System.out.printf("Starting day: %tF%n", calendar);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.printf("Last monday: %tF%n%n", calendar);
calendar.set(2011, Calendar.SEPTEMBER, 18);
System.out.printf("Starting day: %tF (week %d)%n",
calendar, calendar.get(Calendar.WEEK_OF_YEAR));
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.printf("Last monday: %tF (week %d)%n", calendar,
calendar.get(Calendar.WEEK_OF_YEAR));
But in fact the result is a bit different:
First day of week: 2
Starting day: 2011-09-18
Last monday: 2011-09-19
Starting day: 2011-09-18 (week 37)
Last monday: 2011-09-12 (week 37)
In other words, the result depends on whether my calendar knows that I might be interested in the week. The result actually changes if I query WEEK_OF_YEAR!
From the Javadoc:
If there is any conflict in calendar field values, Calendar gives priorities to calendar fields that have been set more recently. The following are the default combinations of the calendar fields. The most recent combination, as determined by the most recently set single field, will be used.
For the date fields:
YEAR + MONTH + DAY_OF_MONTH
YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
YEAR + DAY_OF_YEAR
YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
I interpret this to mean that given that you're setting day of week, it will end up being combined with week of month or week of year in order to produce the actual date and time.
You should also check what is the first day in a week.
I also thought it is always Sunday, but this depend on local settings, and in my case
Monday is the first day in week. Setting Sunday as first day of the week fixed my problem.
Depends on the first day of the week:
/**
* Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
* <code>MONDAY</code> in France.
*
* #return the first day of the week.
* #see #setFirstDayOfWeek(int)
* #see #getMinimalDaysInFirstWeek()
*/
public int getFirstDayOfWeek()
{
return firstDayOfWeek;
}
You can use like this method.
public Integer whichDayOfWeek(Calendar calendar) {
if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
return 1;
} else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY) {
return 2;
} else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.WEDNESDAY) {
return 3;
} else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) {
return 4;
} else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) {
return 5;
} else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
return 6;
} else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
return 7;
} else {
return null;
}
}