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
Related
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 am searching for a method to find the last date of a input day of week from now on? For example: If today is Monday, the 5th march 2018 the results should look like this:
Input Output
Monday 05.03.2018
Tuesday 27.02.2018
Wednesday 28.02.2018
Thursday 01.03.2018
Friday 02.03.2018
Saturday 03.03.2018
Sunday 04.03.2018
I hope you get the idee. I couldn't really find a post with something similar, so any help would be much appreciated
As posted in comments, this is the code I have atm:
private String getLastDateOfDayOfWeek(String day, String returnDateFormat) throws ParseException {
int dayOfWeek = parseDayOfWeek(day, Locale.ENGLISH);
Calendar cal = Calendar.getInstance(); // Today, now
if (cal.get(Calendar.DAY_OF_WEEK) != dayOfWeek) {
// ...
}
return new SimpleDateFormat(returnDateFormat).format(cal.getTime());
}
private static int parseDayOfWeek(String day, Locale locale)
throws ParseException {
SimpleDateFormat dayFormat = new SimpleDateFormat("EEEE", locale);
Date date = dayFormat.parse(day);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
return dayOfWeek;
}
Atm I have two functions: one that can convert a string to a Calender dayOfWeek number and another one, which is the method i am searching for. Currently it only handles todays day of week correct, the part that should do the work for every other day of the week is missing(comment with ...)
tl;dr
LocalDate.now().with( // Get today’s date, then move to another date.
TemporalAdjusters.previousOrSame( // An implementation of `TemporalAdjuster` interface, used for algorithms to move to another date.
DayOfWeek.valueOf( “Monday”.toUpperCase() ) // Get the enum Object with te corresponding hard-coded name in English such as `DayOfWeek.MONDAY`.
)
)
DayOfWeek
The DayOfWeek enum holds seven objects, one for each day of the week.
English
The names of these seven objects are in English, all uppercase. So you can get the Object from the English word.
String input = “Monday”.toUpperCase() ;
DayOfWeek dow = DayOfWeek.valueOf( input ) ;
Other languages
For languages other than English, define a List populated with the name of each day-of-week. Use the name generated from DayOfWeek::getDisplayName, a method that automatically localizes. Start the list with Monday, per the ISO 8601 standard. Search that list to find a match with your input. Get the ordinal number of your match, 1-7 (not the index number 0-6). Pass that number to DayOfWeek.valueOf to get a DayOfWeek object. In some languages you’ll need a pair of such lists to be searched, as an alternate spelling may be invoked for a “standalone” use of the day-of-week without the context of a date.
Here is an example of such a class. Beware: I just whipped up this class without much thought and without any serious testing. Use at your own risk. Usage: DayOfWeekDelocalizer.of( Locale.CANADA_FRENCH ).parse( "lundi" ) → DayOfWeek.MONDAY
package com.basilbourque.example;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.DayOfWeek;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
// For a given name of day-of-week in some language, determine the matching `java.time.DayOfWeek` enum object.
// This class is the opposite of `DayOfWeek.getDisplayName` which generates a localized string for a given `DayOfWeek` object.
// Usage… DayOfWeekDelocalizer.of( Locale.CANADA_FRENCH ).parse( "lundi" ) → DayOfWeek.MONDAY
// Assumes `FormatStyle.FULL`, for day-of-week names without abbreviation.
// USE AT YOUR OWN RISK. Rough draft, quickly written. No serious testing.
public class DayOfWeekDelocalizer
{
#NotNull
private Locale locale;
#NotNull
private List < String > dayOfWeekNames, dayOfWeekNamesStandalone; // Some languages use an alternate spelling for a “standalone” day-of-week used without the context of a date.
// Constructor. Private, for static factory method.
private DayOfWeekDelocalizer ( #NotNull Locale locale )
{
this.locale = locale;
// Populate the pair of arrays, each having the translated day-of-week names.
int daysInWeek = 7; // Seven days in the week.
this.dayOfWeekNames = new ArrayList <>( daysInWeek );
this.dayOfWeekNamesStandalone = new ArrayList <>( daysInWeek );
for ( int i = 1 ; i <= daysInWeek ; i++ )
{
this.dayOfWeekNames.add( DayOfWeek.of( i ).getDisplayName( TextStyle.FULL , this.locale ) );
this.dayOfWeekNamesStandalone.add( DayOfWeek.of( i ).getDisplayName( TextStyle.FULL_STANDALONE , this.locale ) );
}
// System.out.println( this.dayOfWeekNames );
// System.out.println( this.dayOfWeekNamesStandalone );
}
// Constructor. Private, for static factory method.
// Personally, I think it unwise to default implicitly to a `Locale`. But I included this in case you disagree with me, and to follow the lead of the *java.time* classes. --Basil Bourque
private DayOfWeekDelocalizer ( )
{
this( Locale.getDefault() );
}
// static factory method, instead of constructors.
// See article by Dr. Joshua Bloch. http://www.informit.com/articles/article.aspx?p=1216151
// The `Locale` argument determines the human language and cultural norms used in de-localizing input strings.
synchronized static public DayOfWeekDelocalizer of ( #NotNull Locale localeArg )
{
DayOfWeekDelocalizer x = new DayOfWeekDelocalizer( localeArg ); // This class could be optimized by caching this object.
return x;
}
// Attempt to translate the name of a day-of-week to look-up a matching `DayOfWeek` enum object.
// Returns NULL if the passed String value is not found to be a valid name of day-of-week for the human language and cultural norms of the `Locale` specified when constructing this parent object, `DayOfWeekDelocalizer`.
#Nullable
public DayOfWeek parse ( #NotNull String input )
{
int index = this.dayOfWeekNames.indexOf( input );
if ( - 1 == index )
{ // If no hit in the contextual names, try the standalone names.
index = this.dayOfWeekNamesStandalone.indexOf( input );
}
int ordinal = ( index + 1 );
DayOfWeek dow = ( ordinal > 0 ) ? DayOfWeek.of( ordinal ) : null; // If we have a hit, determine the DayOfWeek. Else return null.
return dow;
}
// `Object` overrides.
#Override
public boolean equals ( Object o )
{
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
DayOfWeekDelocalizer that = ( DayOfWeekDelocalizer ) o;
return locale.equals( that.locale );
}
#Override
public int hashCode ( )
{
return locale.hashCode();
}
public static void main ( String[] args )
{
// Quick testing.
// DayOfWeekDelocalizer x = DayOfWeekDelocalizer.of( Locale.JAPAN );
if ( DayOfWeekDelocalizer.of( Locale.CANADA_FRENCH ).parse( "lundi" ).equals( DayOfWeek.MONDAY ) )
{
System.out.println( "GOOD - Canada French 'lundi' is parsing to DayOfWeek.MONDAY." );
} else
{
System.out.println( "BAD - Canada French 'lundi' is NOT parsing to DayOfWeek.MONDAY." );
}
}
}
Tip: Using a String to represent a DayOfWeek is clumsy. Your code should instead be passing around a DayOfWeek enum object.
LocalDate
Next we need the current date.
LocalDate today = LocalDate.now() ;
Better to explicitly state your desired/expected time zone than rely implicitly on the JVM’s current default time zone.
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
LocalDate today = LocalDate.now( z ) ;
TemporalAdjuster
Move to another date by applying a TemporalAdjuster. The TemporalAdjusters class offers the implementation we need.
TemporalAdjuster ta = TemporalAdjusters.previousOrSame( dow ) ;
LocalDate ld = today.with( ta ) ;
Note that java.time uses Immutable Objects. So rather than modify an object, methods produce a new distinct object with altered values based on the original.
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, 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.
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.
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);
}
}
}