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.
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
I have 3 sets of start date and end dates
1st - start date (01/25/2017) and an end date (02/26/2017)
2nd - set of (01/25/2017) and an end date (02/26/2017)
3rd - set (03/25/2017) and an end date (04/26/2017)
I want to write a Java program to compare the 3 sets and give me the two sets which are equal:
((01/25/2017) - (02/26/2017))
Note that start date and end date comes from two different variables.
org.threeten.extra.LocalDateRange::equals
See the ThreeTen-Extra project for the LocalDateRange class with its equals method. This method compares one LocalDateRange with another ensuring that the pair of dates are the same.
That class depends on the java.time.LocalDate class built into Java 8 and later. That class has been covered many hundreds of times on this site. So search Stack Overflow for further info.
LocalDateRange.of(
LocalDate.of( 2017 , Month.JANUARY , 25 ) ,
LocalDate.of( 2017 , Month.FEBRUARY , 26 ) // Returns a `LocalDate` object.
) // Returns a `LocalDateRange` object.
.equals(
LocalDateRange.of(
LocalDate.of( 2017 , Month.MARCH , 25 ) ,
LocalDate.of( 2017 , Month.APRIL , 26 )
)
)
false
ChronoUnit.DAYS::between
If you meant to compare the number of days elapsed, use ChronoUnit enum.
ChronoUnit.DAYS.between(
LocalDate.of( 2017 , Month.JANUARY , 25 ) ,
LocalDate.of( 2017 , Month.FEBRUARY , 26 )
) // Returns a `long` integer primitive.
==
ChronoUnit.DAYS.between(
LocalDate.of( 2017 , Month.MARCH , 25 ) ,
LocalDate.of( 2017 , Month.APRIL , 26 )
)
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.
One way to do this is to create a custom class (MyDateSets) which holds a set of start and end dates. The class's equals method (override the Object's equals) specifies the date set equality.
The example code:
import java.time.*;
import java.time.format.*;
public class CompareDateSets {
public static void main(String [] args) {
// Parse date strings to LocalDate objects
// Make 3 set sof them - the input
DateTimeFormatter parser = DateTimeFormatter.ofPattern("MM/dd/yyyy");
LocalDate start1 = LocalDate.parse("01/25/2017", parser);
LocalDate end1 = LocalDate.parse("01/25/2017", parser);
LocalDate start2 = LocalDate.parse("01/25/2017", parser);
LocalDate end2 = LocalDate.parse("01/25/2017", parser);
LocalDate start3 = LocalDate.parse("03/25/2017", parser);
LocalDate end3 = LocalDate.parse("04/26/2017", parser);
// Create MyDateSets objects - 3 sets of input
MyDateSets set1 = new MyDateSets(start1, end1);
MyDateSets set2 = new MyDateSets(start2, end2);
MyDateSets set3 = new MyDateSets(start3, end3);
// Compare each set and print the comparison result
System.out.println(set1.equals(set2)); // true
System.out.println(set1.equals(set3)); // false
System.out.println(set2.equals(set3)); // false
}
}
/*
* Custom class has a set of the start and end dates.
* Overrides Object class's equals method to define
* the date set's equality.
*/
class MyDateSets {
private LocalDate start;
private LocalDate end;
public MyDateSets(LocalDate start, LocalDate end) {
this.start = start;
this.end = end;
}
public LocalDate getStart() {
return start;
}
public LocalDate getEnd() {
return end;
}
#Override
public boolean equals(Object o) {
MyDateSets dates = (MyDateSets) o;
if ((dates.getStart().equals(start)) &&
(dates.getEnd().equals(end))) {
return true;
}
return false;
}
}
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'd like to have a random millisecond value from an (inverse) linear distribution of values (if I get the term right).
In essence I want to have a random point-in-time t (Date in my case) between two time points early and late where a t towards early has a much greater probability then those towards late. late itself may have a probability of 0.0.
My current java code just uses uniform distribution, so I plan to modify this to a (inverse) linear distribution:
public Date getRandomDate(Date early, Date late) {
long diff = late.getTime() - early.getTime();
final int randVal = rand.nextInt((int) diff);
Calendar cal = Calendar.getInstance();
cal.setTime(early);
cal.add(Calendar.MILLISECOND, randVal);
return cal.getTime();
}
Piggy-backing off of this answer to a similar question, you could just take the minimum of two rand calls:
final int randVal = Math.min(rand.nextInt((int) diff), rand.nextInt((int) diff));
Finally, here is another more complex way that solves for x using the cumulative distribution function (x^2):
int randVal = (int) Math.floor(diff * (1.0 - Math.sqrt(rand.nextDouble())));
if(randVal >= diff) randVal = 0; // handle the edge case
To meet your specified requirements, the square root has been subtracted from 1.0 to invert the distribution, i.e. putting the greater density at the bottom of the range.
The accepted Answer by Parker seems to be correct and well-done.
Using java.time
The Question uses outmoded troublesome date-time classes that are now legacy, supplanted by the java.time classes. Here is the same kind of code, along with Parker’s solution, rewritten in java.time.
Instant
First, if you must work with java.util.Date objects, convert to/from Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). To convert, look to new methods added to the old classes.
Instant instant = myJavaUtilDate.toInstant(); // From legacy to modern class.
java.util.Date myJavaUtilDate = java.util.Date.from( instant ) ; // From modern class to legacy.
Let's rewrite the method signature but passing and returning Instant objects.
public Instant getRandomDate( Instant early , Instant late) {
Verify the early argument is indeed earlier than the later argument. Alternatively, assert that Duration seen below is not negative ( ! duration.isNegative() ).
if( early.isAfter( late) ) { … } // Assert `early` is not after `late`.
Half-Open
Calculate the delta between the earliest and latest moments. This is done in the Half-Open approach often used to define spans of time, where the beginning is inclusive and the ending is exclusive.
Duration
The Duration class represents such a span in terms of a total number of seconds plus a fractional second in nanoseconds.
Duration duration = Duration.between( early , late ) ;
To do our random math, we want a single integer. To handle nanoseconds resolution, we need a 64-bit long rather than a 32-bit int.
ThreadLocalRandom
Tip: If generating these values across threads, use the class ThreadLocalRandom. To quote the doc:
When applicable, use of ThreadLocalRandom rather than shared Random objects in concurrent programs will typically encounter much less overhead and contention.
We can specify the range in Half-Opened style with the origin being inclusive and the bound being exclusive by calling ThreadLocalRandom::nextLong( origin , bound ).
long bound = duration.toNanos() ;
long nanos1 = ThreadLocalRandom.current().nextLong( 0 , bound );
long nanos2 = ThreadLocalRandom.current().nextLong( 0 , bound );
long nanos = Math.min( nanos1 , nanos2 ); // Select the lesser number.
Instant instant = early.plusNanos( nanos );
return instant ;
}
Live example
See the code below run live at IdeOne.com.
We extract the number of date-time values generated for each date-only (LocalDate) as a casual way to survey the results to verify our desired results skewed towards earlier dates.
The test harness shows you how to assign a time zone (ZoneId) to an Instant to get a ZonedDateTime object, and from there extract a LocalDate. Use that as a guide if you wish to view the Instant objects through the lens of some particular region’s wall-clock time rather than in UTC.
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.concurrent.ThreadLocalRandom ;
import java.util.TreeMap ;
import java.time.*;
import java.time.format.*;
import java.time.temporal.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
Ideone app = new Ideone();
app.doIt();
}
public void doIt() {
ZoneId z = ZoneId.of( "America/Montreal" ) ;
int count = 10 ;
LocalDate today = LocalDate.now( z );
LocalDate laterDate = today.plusDays( count );
Instant start = today.atStartOfDay( z ).toInstant();
Instant stop = laterDate.atStartOfDay( z ).toInstant();
// Collect the frequency of each date. We want to see bias towards earlier dates.
List<LocalDate> dates = new ArrayList<>( count );
Map<LocalDate , Integer > map = new TreeMap<LocalDate , Integer >();
for( int i = 0 ; i <= count ; i ++ ) {
LocalDate localDate = today.plusDays( i ) ;
dates.add( localDate ); // Increment to next date and remember.
map.put( localDate , new Integer( 0 ) ); // Prepopulate the map with all dates.
}
for( int i = 1 ; i <= 10_000 ; i ++ ) {
Instant instant = this.getRandomInstantBetween( start , stop );
LocalDate localDate = instant.atZone( z ).toLocalDate();
Integer integer = map.get( localDate );
map.put( localDate , integer + 1); // Increment to count each time get a hit on this date.
}
System.out.println( map );
}
public Instant getRandomInstantBetween( Instant early , Instant late) {
Duration duration = Duration.between( early , late ) ;
// Assert the duration is positive or zero: ( ! duration.isNegative() )
long bound = duration.toNanos() ;
ThreadLocalRandom random = ThreadLocalRandom.current() ;
long nanos1 = random.nextLong( 0 , bound ); // Zero means the `early` date is inclusive, while `bound` here is exclusive.
long nanos2 = random.nextLong( 0 , bound );
long nanos = Math.min( nanos1 , nanos2 ); // Select the lesser number.
Instant instant = early.plusNanos( nanos );
return instant;
}
}
Here are some sample results. These look good to me, but I'm no statistician. Use at your own risk.
{2017-02-24=1853, 2017-02-25=1697, 2017-02-26=1548, 2017-02-27=1255, 2017-02-28=1130, 2017-03-01=926, 2017-03-02=706, 2017-03-03=485, 2017-03-04=299, 2017-03-05=101, 2017-03-06=0}
{2017-02-25=930, 2017-02-26=799, 2017-02-27=760, 2017-02-28=657, 2017-03-01=589, 2017-03-02=470, 2017-03-03=342, 2017-03-04=241, 2017-03-05=163, 2017-03-06=49, 2017-03-07=0}
{2017-02-25=878, 2017-02-26=875, 2017-02-27=786, 2017-02-28=676, 2017-03-01=558, 2017-03-02=440, 2017-03-03=370, 2017-03-04=236, 2017-03-05=140, 2017-03-06=41, 2017-03-07=0}
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, andfz more.
Perhaps you could apply analogy to Date as shown in this answer.
Java: random integer with non-uniform distribution
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);
}
}
}