How to get right number of months and day between several dates?Java 8 calculate months between two datesGet Last Day of the Month in PythonHow to return only the Date from a SQL Server DateTime datatypeHow do you get a timestamp in JavaScript?Add days to JavaScript DateHow do I get the current date in JavaScript?Calculate difference between two dates (number of days)?How do servlets work? Instantiation, sessions, shared variables and multithreadingHow to format a JavaScript dateDifference in months between two datesGet current time and date on Android
Which is the best password hashing algorithm in .NET Core?
co-son-in-law or co-brother
How do I make my fill-in-the-blank exercise more obvious?
Tiny image scraper for xkcd.com
Count rook moves 1D
What's the difference between a share and a stock?
Does the Scrying spell require you to have a clear path to the target in order to work?
How will the UK Commons debate tonight despite the prorogation?
Is mathematics truth?
What exactly is a softlock?
Time to call the bluff
What is the most likely cause of short, quick, and useless reviews?
Is torque as fundamental a concept as force?
How to describe hit point damage without talking about wounds
Is the Levitate spell supposed to basically disable a melee-based enemy?
'This one' as a pronoun
Splitting polygons at narrowest part using R?
Is it possible to observe space debris with Binoculars?
What does "se jouer" mean here?
What is this red bug infesting some trees in southern Germany?
How to find better food in airports
Everyone for non livings
Can I sleep overnight at Stansted Airport
Why do old games use flashing as means of showing damage?
How to get right number of months and day between several dates?
Java 8 calculate months between two datesGet Last Day of the Month in PythonHow to return only the Date from a SQL Server DateTime datatypeHow do you get a timestamp in JavaScript?Add days to JavaScript DateHow do I get the current date in JavaScript?Calculate difference between two dates (number of days)?How do servlets work? Instantiation, sessions, shared variables and multithreadingHow to format a JavaScript dateDifference in months between two datesGet current time and date on Android
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I need to compute the proper number of months and days between a list of intervals:
31/03/2017 30/09/2017
01/10/2017 31/03/2018
01/04/2018 30/09/2018
01/10/2018 31/12/2019
If I compute all days between these intervals and then divide by 30, I got
MONTHS: 33 DAYS: 12
but what I want is:
MONTHS: 33 DAYS: 1 (the only day to compute is the first day of first interval)
java date
|
show 6 more comments
I need to compute the proper number of months and days between a list of intervals:
31/03/2017 30/09/2017
01/10/2017 31/03/2018
01/04/2018 30/09/2018
01/10/2018 31/12/2019
If I compute all days between these intervals and then divide by 30, I got
MONTHS: 33 DAYS: 12
but what I want is:
MONTHS: 33 DAYS: 1 (the only day to compute is the first day of first interval)
java date
1
can you show us some code please
– YCF_L
Mar 27 at 18:06
1
I don't think it is a right approach to divide the days by 30 as some months can be 30 or 31 or 28/29. It doesn't provide the accurate result. You may need to define the requirement correctly as the above example showing the end and start date of the month.
– notionquest
Mar 27 at 18:07
1
Use the the java time package probably
– JustAFellowCoder
Mar 27 at 18:09
2
@MichaelMurray Or on Java 6 or 7 even better, use the backport of java.time: ThreeTen Backport.
– Ole V.V.
Mar 27 at 18:28
1
@OleV.V. if someone is dealing with time and is below java 8, it is recommended to update to 8 or above because below 8 is just a mess when it comes to time. Additionally, it is much slower.
– JustAFellowCoder
Mar 27 at 18:35
|
show 6 more comments
I need to compute the proper number of months and days between a list of intervals:
31/03/2017 30/09/2017
01/10/2017 31/03/2018
01/04/2018 30/09/2018
01/10/2018 31/12/2019
If I compute all days between these intervals and then divide by 30, I got
MONTHS: 33 DAYS: 12
but what I want is:
MONTHS: 33 DAYS: 1 (the only day to compute is the first day of first interval)
java date
I need to compute the proper number of months and days between a list of intervals:
31/03/2017 30/09/2017
01/10/2017 31/03/2018
01/04/2018 30/09/2018
01/10/2018 31/12/2019
If I compute all days between these intervals and then divide by 30, I got
MONTHS: 33 DAYS: 12
but what I want is:
MONTHS: 33 DAYS: 1 (the only day to compute is the first day of first interval)
java date
java date
asked Mar 27 at 18:02
BaisoBaiso
346 bronze badges
346 bronze badges
1
can you show us some code please
– YCF_L
Mar 27 at 18:06
1
I don't think it is a right approach to divide the days by 30 as some months can be 30 or 31 or 28/29. It doesn't provide the accurate result. You may need to define the requirement correctly as the above example showing the end and start date of the month.
– notionquest
Mar 27 at 18:07
1
Use the the java time package probably
– JustAFellowCoder
Mar 27 at 18:09
2
@MichaelMurray Or on Java 6 or 7 even better, use the backport of java.time: ThreeTen Backport.
– Ole V.V.
Mar 27 at 18:28
1
@OleV.V. if someone is dealing with time and is below java 8, it is recommended to update to 8 or above because below 8 is just a mess when it comes to time. Additionally, it is much slower.
– JustAFellowCoder
Mar 27 at 18:35
|
show 6 more comments
1
can you show us some code please
– YCF_L
Mar 27 at 18:06
1
I don't think it is a right approach to divide the days by 30 as some months can be 30 or 31 or 28/29. It doesn't provide the accurate result. You may need to define the requirement correctly as the above example showing the end and start date of the month.
– notionquest
Mar 27 at 18:07
1
Use the the java time package probably
– JustAFellowCoder
Mar 27 at 18:09
2
@MichaelMurray Or on Java 6 or 7 even better, use the backport of java.time: ThreeTen Backport.
– Ole V.V.
Mar 27 at 18:28
1
@OleV.V. if someone is dealing with time and is below java 8, it is recommended to update to 8 or above because below 8 is just a mess when it comes to time. Additionally, it is much slower.
– JustAFellowCoder
Mar 27 at 18:35
1
1
can you show us some code please
– YCF_L
Mar 27 at 18:06
can you show us some code please
– YCF_L
Mar 27 at 18:06
1
1
I don't think it is a right approach to divide the days by 30 as some months can be 30 or 31 or 28/29. It doesn't provide the accurate result. You may need to define the requirement correctly as the above example showing the end and start date of the month.
– notionquest
Mar 27 at 18:07
I don't think it is a right approach to divide the days by 30 as some months can be 30 or 31 or 28/29. It doesn't provide the accurate result. You may need to define the requirement correctly as the above example showing the end and start date of the month.
– notionquest
Mar 27 at 18:07
1
1
Use the the java time package probably
– JustAFellowCoder
Mar 27 at 18:09
Use the the java time package probably
– JustAFellowCoder
Mar 27 at 18:09
2
2
@MichaelMurray Or on Java 6 or 7 even better, use the backport of java.time: ThreeTen Backport.
– Ole V.V.
Mar 27 at 18:28
@MichaelMurray Or on Java 6 or 7 even better, use the backport of java.time: ThreeTen Backport.
– Ole V.V.
Mar 27 at 18:28
1
1
@OleV.V. if someone is dealing with time and is below java 8, it is recommended to update to 8 or above because below 8 is just a mess when it comes to time. Additionally, it is much slower.
– JustAFellowCoder
Mar 27 at 18:35
@OleV.V. if someone is dealing with time and is below java 8, it is recommended to update to 8 or above because below 8 is just a mess when it comes to time. Additionally, it is much slower.
– JustAFellowCoder
Mar 27 at 18:35
|
show 6 more comments
2 Answers
2
active
oldest
votes
The Answer by Ole V.V. is correct, and wisely uses the modern java.time classes.
LocalDateRange
As a bonus, I will mention adding the excellent ThreeTen-Extra library to your project to access the LocalDateRange
class. This class represents a span of time as a pair of LocalDate
objects. That seems a match to your business problem.
LocalDate start = … ;
LocalDate stop = … ;
LocalDateRange range = LocalDateRange.of( start , stop ) ;
From this LocalDateRange
object you can obtain the Period
objects used in that Answer by Ole V.V.
Period period = range.toPeriod() ;
Notice that LocalDateRange
has handy methods for comparison, such as abuts
, contains
, overlaps
, and so on.
Half-Open
You may be confused about how to handle end-of-month/first-of-month.
Generally in date-time handling, it is best to represent a span-of-time using the Half-Open approach. In this approach, the beginning is inclusive while the ending is exclusive.
So a month starts on the first of the month and runs up to, but does not include the first of the next month.
LocalDateRange rangeOfMonthOfNovember2019 =
LocalDateRange.of(
LocalDate.of( 2019 , Month.NOVEMBER , 1 ) ,
LocalDate.of( 2019 , Month.DECEMBER , 1
)
;
You can ask each LocalDateRange
for days elapsed: LocalDateRange::lengthInDays
.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
List < LocalDateRange > ranges = new ArrayList <>( 4 );
ranges.add(
LocalDateRange.of(
LocalDate.parse( "31/03/2017" , f ) ,
LocalDate.parse( "30/09/2017" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2017" , f ) ,
LocalDate.parse( "31/03/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/04/2018" , f ) ,
LocalDate.parse( "30/09/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2018" , f ) ,
LocalDate.parse( "31/12/2019" , f )
)
);
// Sum the periods, one from each range.
Period period = Period.ZERO;
int days = 0;
for ( LocalDateRange range : ranges )
days = ( days + range.lengthInDays() );
period = period.plus( range.toPeriod() ).normalized();
Dump to console.
System.out.println( "ranges: " + ranges );
System.out.println( "days: " + days + " | pseudo-months: " + ( days / 30 ) + " and days: " + ( days % 30 ) );
System.out.println( "period: " + period );
ranges: [2017-03-31/2017-09-30, 2017-10-01/2018-03-31, 2018-04-01/2018-09-30, 2018-10-01/2019-12-31]
days: 1002 | pseudo-months: 33 and days: 12
period: P2Y5M119D
If you insist on fully-closed rather than half-open, LocalDateRange
can still help you with its ofClosed
method. But I strongly suggest you adopt half-open instead, as I believe you will find it makes your life easier to use one consistent approach across all your code. And educate your users. I have seen much confusion among office staff making incorrect assumptions about inclusive/exclusive dates. Your practice of tracking end-of-month to end-of-month seems likely to engender ever more confusion.
YearMonth
Another class you might find useful is built into Java: YearMonth
. This class represents a particular month as a whole unit.
YearMonth yearMonth = YearMonth.of( 2019 , Month.NOVEMBER ) ;
Notice methods such as atDay
to produce a LocalDate
from a YearMonth
.
ISO 8601
Tip: Make a habit of using only the ISO 8601 standard formats rather than localized formats when serializing date-time values as text.
So for a date, use YYYY-MM-DD.
The java.time classes use these formats by default when parsing/generating text. So no need to specify a formatting pattern.
LocalDate.parse( "2019-01-23" )
The standard ISO 8601 format for an entire month is YYYY-MM such as 2019-11
.
YearMonth yearMonth = YearMonth.parse( "2019-11" ) ; // Entire month of November 2019.
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.
You fail to mention periods as a valid and simple/useful method for each only specifies intervals. Therefore, I will be marking this answer as incorrect until further revision.
– JustAFellowCoder
Mar 28 at 14:42
@JustAFellowCoder Reread, looking forrange.toPeriod()
.
– Basil Bourque
Mar 28 at 14:53
1
@JustAFellowCoder Actually, upon further reflection, I now see thatPeriod
is not the solution here. The Question asks for pseudo-months as arbitrary 30-day chunks of time, unrelated to calendar. ThePeriod
class separates years-months from days. See the output of my example code: P2Y5M119D.
– Basil Bourque
Mar 28 at 18:36
BasilBourque fair
– JustAFellowCoder
Mar 28 at 18:47
add a comment |
You may ignore the dates in between and just calculate the difference between the first and the last date:
LocalDate first = LocalDate.of(2017, 3, 31);
LocalDate lastInclusive = LocalDate.of(2019, 12, 31);
LocalDate lastExclusive = lastInclusive.plusDays(1);
Period between = Period.between(first, lastExclusive);
System.out.format("Months: %s days: %d%n",
between.toTotalMonths(), between.getDays());
Output is in this case:
Months: 33 days: 1
Since Period.between()
calculates the difference up to the end date exclusive and you want the end date included, I add one day to your end date.
Months can be 28, 29, 30 and 31 days long and are longer than 30 days on the average, which is why dividing by 30 gave you too many days. You may read up on the exact working of Period.between()
and check if it always gives you what you want.
Links
- Oracle Turorial: section Period and Duration
- Documentation of
Period.bewteen()
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55383799%2fhow-to-get-right-number-of-months-and-day-between-several-dates%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The Answer by Ole V.V. is correct, and wisely uses the modern java.time classes.
LocalDateRange
As a bonus, I will mention adding the excellent ThreeTen-Extra library to your project to access the LocalDateRange
class. This class represents a span of time as a pair of LocalDate
objects. That seems a match to your business problem.
LocalDate start = … ;
LocalDate stop = … ;
LocalDateRange range = LocalDateRange.of( start , stop ) ;
From this LocalDateRange
object you can obtain the Period
objects used in that Answer by Ole V.V.
Period period = range.toPeriod() ;
Notice that LocalDateRange
has handy methods for comparison, such as abuts
, contains
, overlaps
, and so on.
Half-Open
You may be confused about how to handle end-of-month/first-of-month.
Generally in date-time handling, it is best to represent a span-of-time using the Half-Open approach. In this approach, the beginning is inclusive while the ending is exclusive.
So a month starts on the first of the month and runs up to, but does not include the first of the next month.
LocalDateRange rangeOfMonthOfNovember2019 =
LocalDateRange.of(
LocalDate.of( 2019 , Month.NOVEMBER , 1 ) ,
LocalDate.of( 2019 , Month.DECEMBER , 1
)
;
You can ask each LocalDateRange
for days elapsed: LocalDateRange::lengthInDays
.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
List < LocalDateRange > ranges = new ArrayList <>( 4 );
ranges.add(
LocalDateRange.of(
LocalDate.parse( "31/03/2017" , f ) ,
LocalDate.parse( "30/09/2017" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2017" , f ) ,
LocalDate.parse( "31/03/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/04/2018" , f ) ,
LocalDate.parse( "30/09/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2018" , f ) ,
LocalDate.parse( "31/12/2019" , f )
)
);
// Sum the periods, one from each range.
Period period = Period.ZERO;
int days = 0;
for ( LocalDateRange range : ranges )
days = ( days + range.lengthInDays() );
period = period.plus( range.toPeriod() ).normalized();
Dump to console.
System.out.println( "ranges: " + ranges );
System.out.println( "days: " + days + " | pseudo-months: " + ( days / 30 ) + " and days: " + ( days % 30 ) );
System.out.println( "period: " + period );
ranges: [2017-03-31/2017-09-30, 2017-10-01/2018-03-31, 2018-04-01/2018-09-30, 2018-10-01/2019-12-31]
days: 1002 | pseudo-months: 33 and days: 12
period: P2Y5M119D
If you insist on fully-closed rather than half-open, LocalDateRange
can still help you with its ofClosed
method. But I strongly suggest you adopt half-open instead, as I believe you will find it makes your life easier to use one consistent approach across all your code. And educate your users. I have seen much confusion among office staff making incorrect assumptions about inclusive/exclusive dates. Your practice of tracking end-of-month to end-of-month seems likely to engender ever more confusion.
YearMonth
Another class you might find useful is built into Java: YearMonth
. This class represents a particular month as a whole unit.
YearMonth yearMonth = YearMonth.of( 2019 , Month.NOVEMBER ) ;
Notice methods such as atDay
to produce a LocalDate
from a YearMonth
.
ISO 8601
Tip: Make a habit of using only the ISO 8601 standard formats rather than localized formats when serializing date-time values as text.
So for a date, use YYYY-MM-DD.
The java.time classes use these formats by default when parsing/generating text. So no need to specify a formatting pattern.
LocalDate.parse( "2019-01-23" )
The standard ISO 8601 format for an entire month is YYYY-MM such as 2019-11
.
YearMonth yearMonth = YearMonth.parse( "2019-11" ) ; // Entire month of November 2019.
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.
You fail to mention periods as a valid and simple/useful method for each only specifies intervals. Therefore, I will be marking this answer as incorrect until further revision.
– JustAFellowCoder
Mar 28 at 14:42
@JustAFellowCoder Reread, looking forrange.toPeriod()
.
– Basil Bourque
Mar 28 at 14:53
1
@JustAFellowCoder Actually, upon further reflection, I now see thatPeriod
is not the solution here. The Question asks for pseudo-months as arbitrary 30-day chunks of time, unrelated to calendar. ThePeriod
class separates years-months from days. See the output of my example code: P2Y5M119D.
– Basil Bourque
Mar 28 at 18:36
BasilBourque fair
– JustAFellowCoder
Mar 28 at 18:47
add a comment |
The Answer by Ole V.V. is correct, and wisely uses the modern java.time classes.
LocalDateRange
As a bonus, I will mention adding the excellent ThreeTen-Extra library to your project to access the LocalDateRange
class. This class represents a span of time as a pair of LocalDate
objects. That seems a match to your business problem.
LocalDate start = … ;
LocalDate stop = … ;
LocalDateRange range = LocalDateRange.of( start , stop ) ;
From this LocalDateRange
object you can obtain the Period
objects used in that Answer by Ole V.V.
Period period = range.toPeriod() ;
Notice that LocalDateRange
has handy methods for comparison, such as abuts
, contains
, overlaps
, and so on.
Half-Open
You may be confused about how to handle end-of-month/first-of-month.
Generally in date-time handling, it is best to represent a span-of-time using the Half-Open approach. In this approach, the beginning is inclusive while the ending is exclusive.
So a month starts on the first of the month and runs up to, but does not include the first of the next month.
LocalDateRange rangeOfMonthOfNovember2019 =
LocalDateRange.of(
LocalDate.of( 2019 , Month.NOVEMBER , 1 ) ,
LocalDate.of( 2019 , Month.DECEMBER , 1
)
;
You can ask each LocalDateRange
for days elapsed: LocalDateRange::lengthInDays
.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
List < LocalDateRange > ranges = new ArrayList <>( 4 );
ranges.add(
LocalDateRange.of(
LocalDate.parse( "31/03/2017" , f ) ,
LocalDate.parse( "30/09/2017" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2017" , f ) ,
LocalDate.parse( "31/03/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/04/2018" , f ) ,
LocalDate.parse( "30/09/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2018" , f ) ,
LocalDate.parse( "31/12/2019" , f )
)
);
// Sum the periods, one from each range.
Period period = Period.ZERO;
int days = 0;
for ( LocalDateRange range : ranges )
days = ( days + range.lengthInDays() );
period = period.plus( range.toPeriod() ).normalized();
Dump to console.
System.out.println( "ranges: " + ranges );
System.out.println( "days: " + days + " | pseudo-months: " + ( days / 30 ) + " and days: " + ( days % 30 ) );
System.out.println( "period: " + period );
ranges: [2017-03-31/2017-09-30, 2017-10-01/2018-03-31, 2018-04-01/2018-09-30, 2018-10-01/2019-12-31]
days: 1002 | pseudo-months: 33 and days: 12
period: P2Y5M119D
If you insist on fully-closed rather than half-open, LocalDateRange
can still help you with its ofClosed
method. But I strongly suggest you adopt half-open instead, as I believe you will find it makes your life easier to use one consistent approach across all your code. And educate your users. I have seen much confusion among office staff making incorrect assumptions about inclusive/exclusive dates. Your practice of tracking end-of-month to end-of-month seems likely to engender ever more confusion.
YearMonth
Another class you might find useful is built into Java: YearMonth
. This class represents a particular month as a whole unit.
YearMonth yearMonth = YearMonth.of( 2019 , Month.NOVEMBER ) ;
Notice methods such as atDay
to produce a LocalDate
from a YearMonth
.
ISO 8601
Tip: Make a habit of using only the ISO 8601 standard formats rather than localized formats when serializing date-time values as text.
So for a date, use YYYY-MM-DD.
The java.time classes use these formats by default when parsing/generating text. So no need to specify a formatting pattern.
LocalDate.parse( "2019-01-23" )
The standard ISO 8601 format for an entire month is YYYY-MM such as 2019-11
.
YearMonth yearMonth = YearMonth.parse( "2019-11" ) ; // Entire month of November 2019.
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.
You fail to mention periods as a valid and simple/useful method for each only specifies intervals. Therefore, I will be marking this answer as incorrect until further revision.
– JustAFellowCoder
Mar 28 at 14:42
@JustAFellowCoder Reread, looking forrange.toPeriod()
.
– Basil Bourque
Mar 28 at 14:53
1
@JustAFellowCoder Actually, upon further reflection, I now see thatPeriod
is not the solution here. The Question asks for pseudo-months as arbitrary 30-day chunks of time, unrelated to calendar. ThePeriod
class separates years-months from days. See the output of my example code: P2Y5M119D.
– Basil Bourque
Mar 28 at 18:36
BasilBourque fair
– JustAFellowCoder
Mar 28 at 18:47
add a comment |
The Answer by Ole V.V. is correct, and wisely uses the modern java.time classes.
LocalDateRange
As a bonus, I will mention adding the excellent ThreeTen-Extra library to your project to access the LocalDateRange
class. This class represents a span of time as a pair of LocalDate
objects. That seems a match to your business problem.
LocalDate start = … ;
LocalDate stop = … ;
LocalDateRange range = LocalDateRange.of( start , stop ) ;
From this LocalDateRange
object you can obtain the Period
objects used in that Answer by Ole V.V.
Period period = range.toPeriod() ;
Notice that LocalDateRange
has handy methods for comparison, such as abuts
, contains
, overlaps
, and so on.
Half-Open
You may be confused about how to handle end-of-month/first-of-month.
Generally in date-time handling, it is best to represent a span-of-time using the Half-Open approach. In this approach, the beginning is inclusive while the ending is exclusive.
So a month starts on the first of the month and runs up to, but does not include the first of the next month.
LocalDateRange rangeOfMonthOfNovember2019 =
LocalDateRange.of(
LocalDate.of( 2019 , Month.NOVEMBER , 1 ) ,
LocalDate.of( 2019 , Month.DECEMBER , 1
)
;
You can ask each LocalDateRange
for days elapsed: LocalDateRange::lengthInDays
.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
List < LocalDateRange > ranges = new ArrayList <>( 4 );
ranges.add(
LocalDateRange.of(
LocalDate.parse( "31/03/2017" , f ) ,
LocalDate.parse( "30/09/2017" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2017" , f ) ,
LocalDate.parse( "31/03/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/04/2018" , f ) ,
LocalDate.parse( "30/09/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2018" , f ) ,
LocalDate.parse( "31/12/2019" , f )
)
);
// Sum the periods, one from each range.
Period period = Period.ZERO;
int days = 0;
for ( LocalDateRange range : ranges )
days = ( days + range.lengthInDays() );
period = period.plus( range.toPeriod() ).normalized();
Dump to console.
System.out.println( "ranges: " + ranges );
System.out.println( "days: " + days + " | pseudo-months: " + ( days / 30 ) + " and days: " + ( days % 30 ) );
System.out.println( "period: " + period );
ranges: [2017-03-31/2017-09-30, 2017-10-01/2018-03-31, 2018-04-01/2018-09-30, 2018-10-01/2019-12-31]
days: 1002 | pseudo-months: 33 and days: 12
period: P2Y5M119D
If you insist on fully-closed rather than half-open, LocalDateRange
can still help you with its ofClosed
method. But I strongly suggest you adopt half-open instead, as I believe you will find it makes your life easier to use one consistent approach across all your code. And educate your users. I have seen much confusion among office staff making incorrect assumptions about inclusive/exclusive dates. Your practice of tracking end-of-month to end-of-month seems likely to engender ever more confusion.
YearMonth
Another class you might find useful is built into Java: YearMonth
. This class represents a particular month as a whole unit.
YearMonth yearMonth = YearMonth.of( 2019 , Month.NOVEMBER ) ;
Notice methods such as atDay
to produce a LocalDate
from a YearMonth
.
ISO 8601
Tip: Make a habit of using only the ISO 8601 standard formats rather than localized formats when serializing date-time values as text.
So for a date, use YYYY-MM-DD.
The java.time classes use these formats by default when parsing/generating text. So no need to specify a formatting pattern.
LocalDate.parse( "2019-01-23" )
The standard ISO 8601 format for an entire month is YYYY-MM such as 2019-11
.
YearMonth yearMonth = YearMonth.parse( "2019-11" ) ; // Entire month of November 2019.
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.
The Answer by Ole V.V. is correct, and wisely uses the modern java.time classes.
LocalDateRange
As a bonus, I will mention adding the excellent ThreeTen-Extra library to your project to access the LocalDateRange
class. This class represents a span of time as a pair of LocalDate
objects. That seems a match to your business problem.
LocalDate start = … ;
LocalDate stop = … ;
LocalDateRange range = LocalDateRange.of( start , stop ) ;
From this LocalDateRange
object you can obtain the Period
objects used in that Answer by Ole V.V.
Period period = range.toPeriod() ;
Notice that LocalDateRange
has handy methods for comparison, such as abuts
, contains
, overlaps
, and so on.
Half-Open
You may be confused about how to handle end-of-month/first-of-month.
Generally in date-time handling, it is best to represent a span-of-time using the Half-Open approach. In this approach, the beginning is inclusive while the ending is exclusive.
So a month starts on the first of the month and runs up to, but does not include the first of the next month.
LocalDateRange rangeOfMonthOfNovember2019 =
LocalDateRange.of(
LocalDate.of( 2019 , Month.NOVEMBER , 1 ) ,
LocalDate.of( 2019 , Month.DECEMBER , 1
)
;
You can ask each LocalDateRange
for days elapsed: LocalDateRange::lengthInDays
.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
List < LocalDateRange > ranges = new ArrayList <>( 4 );
ranges.add(
LocalDateRange.of(
LocalDate.parse( "31/03/2017" , f ) ,
LocalDate.parse( "30/09/2017" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2017" , f ) ,
LocalDate.parse( "31/03/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/04/2018" , f ) ,
LocalDate.parse( "30/09/2018" , f )
)
);
ranges.add(
LocalDateRange.of(
LocalDate.parse( "01/10/2018" , f ) ,
LocalDate.parse( "31/12/2019" , f )
)
);
// Sum the periods, one from each range.
Period period = Period.ZERO;
int days = 0;
for ( LocalDateRange range : ranges )
days = ( days + range.lengthInDays() );
period = period.plus( range.toPeriod() ).normalized();
Dump to console.
System.out.println( "ranges: " + ranges );
System.out.println( "days: " + days + " | pseudo-months: " + ( days / 30 ) + " and days: " + ( days % 30 ) );
System.out.println( "period: " + period );
ranges: [2017-03-31/2017-09-30, 2017-10-01/2018-03-31, 2018-04-01/2018-09-30, 2018-10-01/2019-12-31]
days: 1002 | pseudo-months: 33 and days: 12
period: P2Y5M119D
If you insist on fully-closed rather than half-open, LocalDateRange
can still help you with its ofClosed
method. But I strongly suggest you adopt half-open instead, as I believe you will find it makes your life easier to use one consistent approach across all your code. And educate your users. I have seen much confusion among office staff making incorrect assumptions about inclusive/exclusive dates. Your practice of tracking end-of-month to end-of-month seems likely to engender ever more confusion.
YearMonth
Another class you might find useful is built into Java: YearMonth
. This class represents a particular month as a whole unit.
YearMonth yearMonth = YearMonth.of( 2019 , Month.NOVEMBER ) ;
Notice methods such as atDay
to produce a LocalDate
from a YearMonth
.
ISO 8601
Tip: Make a habit of using only the ISO 8601 standard formats rather than localized formats when serializing date-time values as text.
So for a date, use YYYY-MM-DD.
The java.time classes use these formats by default when parsing/generating text. So no need to specify a formatting pattern.
LocalDate.parse( "2019-01-23" )
The standard ISO 8601 format for an entire month is YYYY-MM such as 2019-11
.
YearMonth yearMonth = YearMonth.parse( "2019-11" ) ; // Entire month of November 2019.
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.
edited Mar 28 at 18:35
answered Mar 28 at 3:04
Basil BourqueBasil Bourque
133k38 gold badges443 silver badges625 bronze badges
133k38 gold badges443 silver badges625 bronze badges
You fail to mention periods as a valid and simple/useful method for each only specifies intervals. Therefore, I will be marking this answer as incorrect until further revision.
– JustAFellowCoder
Mar 28 at 14:42
@JustAFellowCoder Reread, looking forrange.toPeriod()
.
– Basil Bourque
Mar 28 at 14:53
1
@JustAFellowCoder Actually, upon further reflection, I now see thatPeriod
is not the solution here. The Question asks for pseudo-months as arbitrary 30-day chunks of time, unrelated to calendar. ThePeriod
class separates years-months from days. See the output of my example code: P2Y5M119D.
– Basil Bourque
Mar 28 at 18:36
BasilBourque fair
– JustAFellowCoder
Mar 28 at 18:47
add a comment |
You fail to mention periods as a valid and simple/useful method for each only specifies intervals. Therefore, I will be marking this answer as incorrect until further revision.
– JustAFellowCoder
Mar 28 at 14:42
@JustAFellowCoder Reread, looking forrange.toPeriod()
.
– Basil Bourque
Mar 28 at 14:53
1
@JustAFellowCoder Actually, upon further reflection, I now see thatPeriod
is not the solution here. The Question asks for pseudo-months as arbitrary 30-day chunks of time, unrelated to calendar. ThePeriod
class separates years-months from days. See the output of my example code: P2Y5M119D.
– Basil Bourque
Mar 28 at 18:36
BasilBourque fair
– JustAFellowCoder
Mar 28 at 18:47
You fail to mention periods as a valid and simple/useful method for each only specifies intervals. Therefore, I will be marking this answer as incorrect until further revision.
– JustAFellowCoder
Mar 28 at 14:42
You fail to mention periods as a valid and simple/useful method for each only specifies intervals. Therefore, I will be marking this answer as incorrect until further revision.
– JustAFellowCoder
Mar 28 at 14:42
@JustAFellowCoder Reread, looking for
range.toPeriod()
.– Basil Bourque
Mar 28 at 14:53
@JustAFellowCoder Reread, looking for
range.toPeriod()
.– Basil Bourque
Mar 28 at 14:53
1
1
@JustAFellowCoder Actually, upon further reflection, I now see that
Period
is not the solution here. The Question asks for pseudo-months as arbitrary 30-day chunks of time, unrelated to calendar. The Period
class separates years-months from days. See the output of my example code: P2Y5M119D.– Basil Bourque
Mar 28 at 18:36
@JustAFellowCoder Actually, upon further reflection, I now see that
Period
is not the solution here. The Question asks for pseudo-months as arbitrary 30-day chunks of time, unrelated to calendar. The Period
class separates years-months from days. See the output of my example code: P2Y5M119D.– Basil Bourque
Mar 28 at 18:36
BasilBourque fair
– JustAFellowCoder
Mar 28 at 18:47
BasilBourque fair
– JustAFellowCoder
Mar 28 at 18:47
add a comment |
You may ignore the dates in between and just calculate the difference between the first and the last date:
LocalDate first = LocalDate.of(2017, 3, 31);
LocalDate lastInclusive = LocalDate.of(2019, 12, 31);
LocalDate lastExclusive = lastInclusive.plusDays(1);
Period between = Period.between(first, lastExclusive);
System.out.format("Months: %s days: %d%n",
between.toTotalMonths(), between.getDays());
Output is in this case:
Months: 33 days: 1
Since Period.between()
calculates the difference up to the end date exclusive and you want the end date included, I add one day to your end date.
Months can be 28, 29, 30 and 31 days long and are longer than 30 days on the average, which is why dividing by 30 gave you too many days. You may read up on the exact working of Period.between()
and check if it always gives you what you want.
Links
- Oracle Turorial: section Period and Duration
- Documentation of
Period.bewteen()
add a comment |
You may ignore the dates in between and just calculate the difference between the first and the last date:
LocalDate first = LocalDate.of(2017, 3, 31);
LocalDate lastInclusive = LocalDate.of(2019, 12, 31);
LocalDate lastExclusive = lastInclusive.plusDays(1);
Period between = Period.between(first, lastExclusive);
System.out.format("Months: %s days: %d%n",
between.toTotalMonths(), between.getDays());
Output is in this case:
Months: 33 days: 1
Since Period.between()
calculates the difference up to the end date exclusive and you want the end date included, I add one day to your end date.
Months can be 28, 29, 30 and 31 days long and are longer than 30 days on the average, which is why dividing by 30 gave you too many days. You may read up on the exact working of Period.between()
and check if it always gives you what you want.
Links
- Oracle Turorial: section Period and Duration
- Documentation of
Period.bewteen()
add a comment |
You may ignore the dates in between and just calculate the difference between the first and the last date:
LocalDate first = LocalDate.of(2017, 3, 31);
LocalDate lastInclusive = LocalDate.of(2019, 12, 31);
LocalDate lastExclusive = lastInclusive.plusDays(1);
Period between = Period.between(first, lastExclusive);
System.out.format("Months: %s days: %d%n",
between.toTotalMonths(), between.getDays());
Output is in this case:
Months: 33 days: 1
Since Period.between()
calculates the difference up to the end date exclusive and you want the end date included, I add one day to your end date.
Months can be 28, 29, 30 and 31 days long and are longer than 30 days on the average, which is why dividing by 30 gave you too many days. You may read up on the exact working of Period.between()
and check if it always gives you what you want.
Links
- Oracle Turorial: section Period and Duration
- Documentation of
Period.bewteen()
You may ignore the dates in between and just calculate the difference between the first and the last date:
LocalDate first = LocalDate.of(2017, 3, 31);
LocalDate lastInclusive = LocalDate.of(2019, 12, 31);
LocalDate lastExclusive = lastInclusive.plusDays(1);
Period between = Period.between(first, lastExclusive);
System.out.format("Months: %s days: %d%n",
between.toTotalMonths(), between.getDays());
Output is in this case:
Months: 33 days: 1
Since Period.between()
calculates the difference up to the end date exclusive and you want the end date included, I add one day to your end date.
Months can be 28, 29, 30 and 31 days long and are longer than 30 days on the average, which is why dividing by 30 gave you too many days. You may read up on the exact working of Period.between()
and check if it always gives you what you want.
Links
- Oracle Turorial: section Period and Duration
- Documentation of
Period.bewteen()
answered Mar 27 at 21:27
Ole V.V.Ole V.V.
37.4k7 gold badges47 silver badges64 bronze badges
37.4k7 gold badges47 silver badges64 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55383799%2fhow-to-get-right-number-of-months-and-day-between-several-dates%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
can you show us some code please
– YCF_L
Mar 27 at 18:06
1
I don't think it is a right approach to divide the days by 30 as some months can be 30 or 31 or 28/29. It doesn't provide the accurate result. You may need to define the requirement correctly as the above example showing the end and start date of the month.
– notionquest
Mar 27 at 18:07
1
Use the the java time package probably
– JustAFellowCoder
Mar 27 at 18:09
2
@MichaelMurray Or on Java 6 or 7 even better, use the backport of java.time: ThreeTen Backport.
– Ole V.V.
Mar 27 at 18:28
1
@OleV.V. if someone is dealing with time and is below java 8, it is recommended to update to 8 or above because below 8 is just a mess when it comes to time. Additionally, it is much slower.
– JustAFellowCoder
Mar 27 at 18:35