How to get a random Date with linear distribution? - java

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

Related

How to get Months from a given quarter

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

Appointment class

I'm trying to create a method that would add an appointment to an arraylist appointmentCalndar. This method would validate the date to see if the user input is equal to the SimpleDateFormat in my code, the startTime and the endTime of the appointment and to see if its in the future or not.
I have tried using the java Date api to check this but when I try to extend the class to get access to the attributes it always causes an error on compile time. So overall my question is what would the best way to compare an object of appointment type to an object of type date? I try using accesors to getDate() and startTime and endTime but it won't allow me to get them also.
public AppointmentDate(String appString)
{
// 1) split ithe string into Date/from/to
// 2) consturct the Date object for the appDate
// 3) consturct the Date object for the startTime
// 4) consturct the Date object for the endTime
String[] appDetails = appString.split(",");
if(appDetails.length == 2)
{
try {
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
this.appDate = df.parse(appDetails[0]);
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy,mm:HH");
String dFormat = appDetails[0] + "," + appDetails[1];
this.startTime = formatter.parse(dFormat);
dFormat = appDetails[0] + "," + appDetails[2];
this.endTime = formatter.parse(dFormat);
}
catch (Exception ex)
{
}
}
else
{
System.out.print("User Date is Invalid");
}
}
public void setStartTime(Date startTime)
{
this.startTime = startTime;
}
public Date getStartTime()
{
return startTime;
}
public void setEndTime(Date endTime)
{
this.endTime = endTime;
}
public Date getEndTime()
{
return endTime;
}
public void setAppdate(Date appDate)
{
this.appDate = appDate;
}
public Date getAppDate()
{
return appDate;
}
public void add(Appointment a)
{
if (a.equals(a.getDate()))
{
if(a.getStartTime() < a.getEndTime())
{
}
}
else
{
System.out.print("");
}
}
Static block (almost)
Your code to exercise the class is in the wrong place. You have it stuck at the top of the class which is not syntactically correct. We can run code at the top, as a static block, but it needs to be labeled static { … }. A static block is not commonly used in my experience. And certainly is not the right place for what you are doing there.
main method
Instead you should be using a main method. This non-OOP little thingie is a trick, a hack, to solve the chicken-or-the-egg conundrum, to get us from no-app-running to our OOP idea of heaven with a bunch of objects floating around and passing messages to one another.
When first learning Java, do not try to understand all the syntax and purpose of the main method. Just accept it as a necessary evil to get the app running, it is merely the entrance point to execute the app. Focus on learning the OOP concepts and practices. Later, the main method and syntax will make more sense.
Accessors
Here is a simplified re-write of your example code. We are just using a LocalDate for simplicity, just enough to show (a) a main method, and (b) getter/setter accessor methods.
package com.basilbourque.example;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
public class AppointmentDate {
private LocalDate localDate;
// Constructor
public AppointmentDate ( LocalDate localDate ) {
this.localDate = localDate;
}
public LocalDate getLocalDate ( ) {
return localDate;
}
public void setLocalDate ( LocalDate localDate ) {
this.localDate = localDate;
}
#Override
public String toString ( ) {
return "AppointmentDate{ " +
"localDate=" + localDate +
" }";
}
// Not really a part of this class. A `main` method is just a hack to get our app launched.
public static void main ( String[] args ) {
String input = "23/01/2018";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
LocalDate ld = LocalDate.parse( input , f );
AppointmentDate ad = new AppointmentDate( ld );
ad.setLocalDate( ld.plusWeeks( 1 ) );
LocalDate newValue = ad.getLocalDate();
System.out.println( newValue.toString() ); // Generate text representing the value of this `LocalDate` object in standard ISO 8601 format.
List < AppointmentDate > list = new ArrayList <>( 3 );
list.add( ad );
list.add( new AppointmentDate( LocalDate.parse( "2018-02-13" ) ) );
list.add( new AppointmentDate( LocalDate.parse( "2018-12-21" ) ) );
System.out.println( list );
}
}
2018-01-30
[AppointmentDate{ localDate=2018-01-30 }, AppointmentDate{ localDate=2018-02-13 }, AppointmentDate{ localDate=2018-12-21 }]
java.time
You are using terrible old date-time classes that were supplanted years ago by the java.time classes. Never use Date, Calendar, SimpleDateFormat, etc.
Appointments are tricky
While appointment tracking may seem intuitively simple, you are actually working on a very tricky subject.
The core problem is that politicians around the world are fond of redefining the time zone(s) under their jurisdiction. They do so quite frequently. They do so in both times of relative quiet and in times of turmoil.
The US and Canada have changed their offsets multiple times in recent decades. Turkey and Russia have changed their minds about going on or off DST multiple times in the last several years.
And politicians change their time zones with very little advance notice. And the notice seems to be growing shorter, despite the increased disturbance this causes in ever-more-computerized societies. Just last month, Morocco announced their country would stay on Daylight Saving Time (DST) permanent, cancelling on a Friday the DST cutover scheduled for that Sunday, leaving 0 business days warning — what a mess for IT staff. In May this year, North Korea slipped their clock a half-hour to sync with South Korea, with apparently immediate effect (no advance notice at all).
These frequent and unpredictable changes mean we cannot responsibly track future appointments as moments, as specific points on the timeline. When we say something like “3 PM on January 23rd” we usually mean 3 PM after politicians may have made their changes to the clock.
So we must store future appointments as a date and a time-of-day without a time zone or offset-from-UTC. Then, when calculating a calendar we must dynamically apply the rules for the intended time zone as currently defined on that day. If we perform this dynamic-determination of a moment today, and again in three days, if the politicians have announced a change in the time zone definition, and if we have been able to update our tzdata data files in our operating systems, database engines, Java Virtual Machines, and various libraries, then we will arrive at a different moment in time.
LocalDateTime
The Local… types in Java purposely lack any concept of time zone or offset-from-UTC. So they cannot represent a moment. So we never use these to pinpoint actual events that happened in the past. But these types are what we need for future appointments.
The LocalDateTime class represents a date with a time-of-day without any zone/offset.
LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 15 , 0 ) ; // 3 PM in 24-hour time.
LocalDateTime ldt= LocalDateTime.of( ld , lt ) ;
ZonedDateTime
When calculating a calendar, when we need a specific moment, we apply a time zone (ZoneId) to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ; // Determine a moment, a specific point on the timeline.
Instant
We can view that same moment in UTC by extracting a Instant.
Instant instant = zdt.toInstant() ; // Adjust to UTC.
Duration
Appointments are generally best stored as a starting point plus a duration. No need to store the stopping point as that can be calculated.
Duration d = Duration.ofHours( 1 ) ; // A one-hour appointment.
While we often want to adjust into a time zone for presentation to a user, generally behind-the-scenes it is best practice to track moments in UTC. So the starting and stopping points of an appointment calculated as moments should be done as a pair of Instant objects.
Instant start = ldt.atZone( z ).toInstant() ;
Instant stop = start.plus( d ) ;
Interval
We can leverage a class to represent this pair of Instant objects, Interval.
This class is found in the ThreeTen-Extra library, a project led by the same man than led the Joda-Time, JSR 310, and java.time projects, Stephen Colebourne.
This class has very handy methods for comparison such as abuts, overlaps, contains, and so on. You will likely want to use these methods in a scheduling app.
Appointment.java
Put this all together and we get a class like this:
package com.basilbourque.example;
import org.threeten.extra.Interval;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Appointment {
private LocalDateTime start;
private Duration duration;
// Constructor.
public Appointment ( LocalDateTime start , Duration duration ) {
this.start = start;
this.duration = duration;
}
// Might add some getter/setter methods in here.
// Dynamically determine the start and stop points of this appointment, given today’s definition of the intended time zone.
public Interval toInterval ( ZoneId zoneId ) {
ZonedDateTime zdtStart = this.start.atZone( zoneId );
Interval interval = Interval.of( zdtStart.toInstant() , this.duration );
return interval;
}
}
When you generate a Interval by calling your toInterval method, you may want the individual start and stop moments.
Instant start = interval.getStart() ;
Instant stop = interval.getEnd() ;
Those two Instant objects are in UTC by definition. If you want to see them through the lens of the wall-clock time used by the people of a particular region, apply a ZoneId to get a ZonedDateTime object.
ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdtStart = start.atZone( z ) ; // Adjust from UTC to some time zone. Same moment, same point on the timeline, different wall-clock time.
ZonedDateTime zdtStop = stop.atZone( z ) ;
Future
You asked about checking to see if this appointment is in the future. Again, we need a time zone to properly answer than. The time zones around the world currently cover a range of about 26 to 27 hours. So within in that many hours of the current moment we cannot tell if a LocalDateTime is in the future or past without considering a time zone.
So let's add a method testing for the future that requires passing a time zone.
// Dynamically determine if this appointment will be in the future for some specific time zone.
public Boolean isFuture ( ZoneId zoneId ) {
Objects.requireNonNull( zoneId , "Must pass a time zone to determine if an appointment is in the future. Message # e1c64bc1-9a44-4d15-b20d-e68414fb5ab5.");
ZonedDateTime zdtStart = this.start.atZone( zoneId );
ZonedDateTime zdtNow = ZonedDateTime.now( zoneId );
boolean isInTheFuture = zdtNow.isBefore( zdtStart );
return isInTheFuture ;
}
Start/Stop moments
Continuing the same theme on dynamically determining moments, let's add some methods to return the starting moment (inclusive) and stopping moment (exclusive). As discussed above, this requires passing a time zone.
The calling programmer could do this work herself. But I suspect this might be frequently needed enough to warrant adding these methods as a convenience.
// Get start moment for a particular time zone.
public ZonedDateTime toStartMoment ( ZoneId zoneId ) {
ZonedDateTime zdt = this.toInterval( zoneId ).getStart().atZone( zoneId );
return zdt;
}
// Get stop moment for a particular time zone.
public ZonedDateTime toStopMoment ( ZoneId zoneId ) {
ZonedDateTime zdt = this.toInterval( zoneId ).getEnd().atZone( zoneId );
return zdt;
}
Notice that I did not name these methods with the get…. Accessor methods, getters & setters, by convention imply accessing a simple property stored within the object. But here we are not storing the ZonedDateTime objects. These are dynamically-determined, so using a get… method could be misleading. Instead, I am trying to follow the naming conventions laid down in the java.time project.
Immutable objects
Another lesson to learn from the java.time project is the immutable objects pattern.
Certain kinds of classes lend themselves to being read-only, created but not modified. The java.time classes certainly qualify. Whereas an invoice, for example, is expected to “mutate” (change), intuitively as a programmer I do not expect the date on the invoice to change unless I explicitly replace the date with a new object. So I want invoice to be a mutable object, but I want the LocalDate object stored on that invoice to be immutable.
I suspect our Appointment class might also be best designed an an immutable. So we have no setter methods involved. To effectively alter an appointment in your scheduling app, create a new Appointment object based on some of the values of the existing Appointment object. Notice in the java.time classes how this is done with various with methods, where the methods return a new object based on the original’s values but with some alteration.
Appointment.java version 2
Let's put all that together into one example class.
And let's add a main method to exercise this class. First we create one appointment, and look at its dynamically-determined moments in UTC. Second, we collect some Appointment objects in a collection.
We have added a toString method override to report on the object’s state.
package com.basilbourque.example;
import org.threeten.extra.Interval;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
// An example class to show date-time handling for future appointments.
// Not necessarily ready for production use. Use at your own risk.
// Methods named according to the java.time naming conventions:
// https://docs.oracle.com/javase/tutorial/datetime/overview/naming.html
public class Appointment {
private LocalDateTime start;
private Duration duration;
// Constructor.
public Appointment ( LocalDateTime start , Duration duration ) {
this.start = start;
this.duration = duration;
}
// Dynamically determine the start and stop points of this appointment, given today’s definition of the intended time zone.
public Interval toInterval ( ZoneId zoneId ) {
Objects.requireNonNull( zoneId , "Must pass a time zone to get the start/stop interval of an appointment. Message # bbf021e6-baa7-468d-83ad-cf73acb6702e." );
ZonedDateTime zdtStart = this.start.atZone( zoneId );
Interval interval = Interval.of( zdtStart.toInstant() , this.duration );
return interval;
}
// Get start moment for a particular time zone.
public ZonedDateTime toStartMoment ( ZoneId zoneId ) {
ZonedDateTime zdt = this.toInterval( zoneId ).getStart().atZone( zoneId );
return zdt;
}
// Get stop moment for a particular time zone.
public ZonedDateTime toStopMoment ( ZoneId zoneId ) {
ZonedDateTime zdt = this.toInterval( zoneId ).getEnd().atZone( zoneId );
return zdt;
}
// Dynamically determine if this appointment will be in the future for some specific time zone.
public Boolean isFuture ( ZoneId zoneId ) {
Objects.requireNonNull( zoneId , "Must pass a time zone to determine if an appointment is in the future. Message # e1c64bc1-9a44-4d15-b20d-e68414fb5ab5." );
ZonedDateTime zdtStart = this.start.atZone( zoneId );
ZonedDateTime zdtNow = ZonedDateTime.now( zoneId );
boolean isInTheFuture = zdtNow.isBefore( zdtStart );
return isInTheFuture;
}
// -----------| Object overrides |---------------------------
#Override
public String toString ( ) {
return "Appointment{ " +
"start=" + start +
" | duration=" + duration +
" }";
}
// -----------| main |-------------
public static void main ( String[] args ) {
// See if a new appointment is in the future.
Appointment a = new Appointment( LocalDateTime.of( 2018 , 12 , 25 , 0 , 0 , 0 , 0 ) , Duration.ofHours( 2 ) );
ZoneId z = ZoneId.of( "America/Montreal" );
System.out.println( "For time zone: " + z + ", appointment interval is: " + a.toInterval( z ) );
System.out.println( "Start: " + a.toStartMoment( z ) );
System.out.println( "Stop: " + a.toStopMoment( z ) );
Boolean isFuture = a.isFuture( z );
System.out.println( a.toString() + " is future t/f: " + isFuture );
// Collect some appointments.
List < Appointment > list = new ArrayList <>( 3 );
list.add( a );
list.add( new Appointment( LocalDateTime.of( 2018 , 12 , 13 , 15 , 0 , 0 , 0 ) , Duration.ofMinutes( 90 ) ) );
list.add( new Appointment( LocalDateTime.of( 2018 , 12 , 30 , 16 , 0 , 0 , 0 ) , Duration.ofHours( 1 ) ) );
System.out.println( list );
}
}
When run.
For time zone: America/Montreal, appointment interval is: 2018-12-25T05:00:00Z/2018-12-25T07:00:00Z
Start: 2018-12-25T00:00-05:00[America/Montreal]
Stop: 2018-12-25T02:00-05:00[America/Montreal]
Appointment{ start=2018-12-25T00:00 | duration=PT2H } is future t/f: true
[Appointment{ start=2018-12-25T00:00 | duration=PT2H }, Appointment{ start=2018-12-13T15:00 | duration=PT1H30M }, Appointment{ start=2018-12-30T16:00 | duration=PT1H }]
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, 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.

java - Get the last date of input day of week

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.

How to display a date mm/dd/yy as a decimal in Java?

Basically im trying to make a countdown timer to specific date, but i dont want the output to be a standard yy/mm/dd/ss format, i want it to display the number of years and the a decimal percentage, like so : 16.39872937498273 years left until blah..
and so far i have created a system clock that updates as far as milliseconds but no further..
so how to get a date to convert to year + decimal
and how do you update a clock farther than milliseconds?
so far this is my code, only counts up and displays system time, i need to change it to count down and to a date.
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class Base extends JFrame{
private JPanel p1;
private JLabel time;
public static void main(String[] args){
Base myFrame = new Base();
myFrame.pack();
myFrame.setTitle("Digital Clock");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setLocationRelativeTo(null);
myFrame.setVisible(true);
}//main()
public Base(){
System.out.println(currentTime());
JPanel p1 = new JPanel();
p1.setLayout(new FlowLayout());
JLabel time = new JLabel(currentTime());
time.setFont(new Font("Gulim", Font.BOLD, 20));
time.setForeground(Color.blue);
p1.add(time);
this.setLayout(new BorderLayout());
this.add(p1, BorderLayout.CENTER);
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println(currentTime());
time.setText(currentTime());
}
};
Timer t = new Timer(50, taskPerformer);
t.start();
}
public String currentTime(){
DateFormat df = new SimpleDateFormat("MM/dd/yy hh:mm:ssSSS");
Date dateobj = new Date();
String currentTime = df.format(dateobj);
return currentTime;
}
public String checkTime(int t){
String time1;
if (t < 10){
time1 = ("0"+t);
}
else{
time1 = (""+t);
}
return time1;
}
public String amP(int ap){
String amPm;
if( ap == 0)
amPm = "AM";
else
amPm = "PM";
return amPm;
}
}
Avoid legacy date-time classes
You are using old date-time classes that have proven to be troublesome, confusing, and flawed.
The old Calendar and Date classes are now legacy. Supplanted by the java.time classes.
java.time
Use the java.time classes for date-time work.
Caveat: I do not recommend representing a span of time as a decimal number. Counting a span of time as something like “1.062 years later” has no utility that I know of. Instead I suggest using the standard ISO 8601 format for a textual representation (PnYnMnDTnHnMnS). Nevertheless, I took on this Question as a puzzle challenge.
To obtain a decimal fraction representing a fraction of the year, use the Period and Duration classes, with Year helping out. The strategy is to get a fraction of year and determine the length of that fractional year in nanoseconds. Divide that number by the number of nanoseconds in that particular year (years vary in length by Leap Year and by anomalies such as redefinition of time zone), to get our decimal fraction. Add the total number of whole years for a result.
Determine the start and stop of our span of time.
ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdtStart = ZonedDateTime.of ( 2015 , 2 , 21 , 12 , 34 , 56 , 0 , z );
ZonedDateTime zdtStop = ZonedDateTime.of ( 2016 , 3 , 15 , 12 , 34 , 56 , 0 , z );
Get the count of whole years via Period.
Period p = Period.between ( zdtStart.toLocalDate () , zdtStop.toLocalDate () );
int years = p.getYears ();
Now focus on the fraction of a year. Add the number of whole years to the starting moment to get the start of that last fractional year.
ZonedDateTime zdtStartFractional = zdtStart.plusYears ( years );
Get the span of time, unattached from timeline, between our start of fractional year and the stopping point of our original span.
Duration fractionalYear = Duration.between ( zdtStartFractional , zdtStop );
Calculate our divisor, the length of this particular year in nanoseconds. Get the moment the year starts, and get a year later when following year starts.
ZonedDateTime zdtFractionalYear_StartOfYear = zdtStartFractional.with ( TemporalAdjusters.firstDayOfYear () ).toLocalDate ().atStartOfDay ( z );
Duration wholeYear = Duration.between ( zdtFractionalYear_StartOfYear , zdtFractionalYearStart.plusYears ( 1 ) );
Get the nanoseconds. To avoid the extraneous extra digits of floating point technology, we avoid float/Float and double/Double, using BigDecimal for accuracy. Specify the scale (number of decimal fraction digits) you want in your result; here we use 32 arbitrarily.
BigDecimal fractionalYearAsNanos = new BigDecimal ( fractionalYear.toNanos () );
BigDecimal wholeYearAsNanos = new BigDecimal ( wholeYear.toNanos () );
BigDecimal ratio = fractionalYearAsNanos.divide ( wholeYearAsNanos , 32 , RoundingMode.HALF_EVEN );
BigDecimal result = ratio.add ( new BigDecimal ( years ) );
Dump to console.
System.out.println ( zdtStart + "/" + zdtStop );
System.out.println ( "Years: " + result.toPlainString () );
2015-02-21T12:34:56-05:00[America/Montreal]/2016-03-15T12:34:56-04:00[America/Montreal]
Years: 1.06272768670309653916211293260474
See live code in IdeOne.com.
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….
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 solution is to solve it straight,you can calculate the days and hours into seconds,compared to the year,as the following shows,change the code:
public String currentTime(){
DateFormat df = new SimpleDateFormat("MM/dd/yy hh:mm:ssSSS");
Date dateobj = new Date();
String currentTime = df.format(dateobj);
return currentTime;
}
to :
public String currentTime(){
double year = Calendar.getInstance().get(Calendar.YEAR);
double day_in_year = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
double nanoTime0=System.nanoTime()/(1000000000);
double nanoTime1=nanoTime0/(3600*12*365);
double cTime=year+day_in_year/365+nanoTime1;
String currentTime=new BigDecimal(cTime).toPlainString();
return currentTime;
}
the output is:
...
2016.9509955606290532159619033336639404296875
2016.9509955606290532159619033336639404296875
2016.9509955606290532159619033336639404296875
2016.9509955606290532159619033336639404296875
2016.9509955606290532159619033336639404296875
2016.9509955606290532159619033336639404296875
2016.9509955606290532159619033336639404296875
2016.9509955606290532159619033336639404296875
2016.95099562404857351793907582759857177734375
2016.95099562404857351793907582759857177734375
2016.95099562404857351793907582759857177734375
2016.95099562404857351793907582759857177734375
2016.95099562404857351793907582759857177734375
2016.95099562404857351793907582759857177734375
2016.95099562404857351793907582759857177734375
...
Notice:because the nanoTime() method create the small digits which are too samll to be recognized by the compiler,there are some samee time in the output.
Waiting for a better solution.
You can use System.nanoTime() to go beyond milliseconds, and then you can use your logic to calculate the years in the desired format.

See if the current time falls within a specific range of time in the current day in Java

I am sure this was done 1000 times in 1000 different places. The question is I want to know if there is a better/standard/faster way to check if current "time" is between two time values given in hh:mm:ss format. For example, my big business logic should not run between 18:00:00 and 18:30:00. So here is what I had in mind:
public static boolean isCurrentTimeBetween(String starthhmmss, String endhhmmss) throws ParseException{
DateFormat hhmmssFormat = new SimpleDateFormat("yyyyMMddhh:mm:ss");
Date now = new Date();
String yyyMMdd = hhmmssFormat.format(now).substring(0, 8);
return(hhmmssFormat.parse(yyyMMdd+starthhmmss).before(now) &&
hhmmssFormat.parse(yyyMMdd+endhhmmss).after(now));
}
Example test case:
String doNotRunBetween="18:00:00,18:30:00";//read from props file
String[] hhmmss = downTime.split(",");
if(isCurrentTimeBetween(hhmmss[0], hhmmss[1])){
System.out.println("NOT OK TO RUN");
}else{
System.out.println("OK TO RUN");
}
What I am looking for is code that is better
in performance
in looks
in correctness
What I am not looking for
third-party libraries
Exception handling debate
variable naming conventions
method modifier issues
this is all you should need to do, this method is loosely coupled from the input and highly coherent.
boolean isNowBetweenDateTime(final Date s, final Date e)
{
final Date now = new Date();
return now.after(s) && now.before(e);
}
how you get the Date objects for start and end is irrelevant to comparing them. You are making things way more complicated than you need to with passing String representations around.
Here is a better way to get the start and end dates, again loosely coupled and highly coherent.
private Date dateFromHourMinSec(final String hhmmss)
{
if (hhmmss.matches("^[0-2][0-9]:[0-5][0-9]:[0-5][0-9]$"))
{
final String[] hms = hhmmss.split(":");
final GregorianCalendar gc = new GregorianCalendar();
gc.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hms[0]));
gc.set(Calendar.MINUTE, Integer.parseInt(hms[1]));
gc.set(Calendar.SECOND, Integer.parseInt(hms[2]));
gc.set(Calendar.MILLISECOND, 0);
return gc.getTime();
}
else
{
throw new IllegalArgumentException(hhmmss + " is not a valid time, expecting HH:MM:SS format");
}
}
Now you can make two well named method calls that will be pretty self documenting.
tl;dr
LocalTime now =
ZonedDateTime
.now( ZoneId.of( "America/Montreal" ) )
.toLocalTime() ;
Boolean isBetween =
( ! now.isBefore( LocalTime.of( 18 , 0 ) ) // "not before" means "is equal to OR after".
&&
now.isBefore( LocalTime.of( 18 , 30 ) ) ; // Half-Open, beginning is *inclusive* while ending is *exclusive*.
Using java.time
You are using old date-time classes that have proven to be poorly designed, confusing, and troublesome. They are now legacy, supplanted by the java.time classes.
LocalTime
Do not pass mere strings representing time-of-day values. We now have a type for that, the LocalTime class.
LocalTime start = LocalTime.of( 18 , 0 );
LocalTime stop = LocalTime.of( 18 , 30 );
Pass those instances to your utility method. That method should not have to do any parsing, so no need to throw the parsing exception.
public static boolean isCurrentTimeBetween( LocalTime start , LocalTime stop ) {
…
ZonedDateTime
A time zone is crucial in determining the current date and time-of-day. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.now( z );
To compare the time-of-day of now, we could simply extract a LocalTime from that ZonedDateTime. But we have the problem of anomalies, such as Daylight Saving Time (DST) and politicians redefining time zones. There may not be any 6 PM hour on a particular date. The solution to this conundrum depends on your business context and your business rules. You could either ignore the conundrum and stick with literally asking if the current time is between your target start-stop time. Or you could apply the time zone to your start-stop times-of-day of day and let ZonedDateTime class make adjustments as it sees fit. Let's look at both approaches.
Ignore anomalies
First, ignore any anomalies. Ask simply and literally if the current time-of-day is between the target start and stop times-of-day.
We can extract a time-of-day object from the zoned date-time object.
LocalTime localTimeNow = zdt.toLocalTime(); // Extract a time-of-day from the zoned date-time object.
Compare that to our stop-start times-of-day. Note that we use here the Half-Open approach to defining a span of time. In this approach the beginning is inclusive while the ending is exclusive. This approach is common in date-time work and generally is the wise way to go.
Boolean isNowOnOrAfterStart = ( ! localTimeNow.isBefore( start ) ) ; // A briefer way of asking "is equal to OR is after" is "is not before".
Boolean isNowBeforeStop = localTimeNow.isBefore( stop );
Boolean isNowInTargetZone = ( isNowOnOrAfterStart && isNowBeforeStop ); // Half-Open: beginning is inclusive while ending is exclusive.
Consider anomalies
Next we consider any anomalies. We apply the start and stop times-of-day to the current date within the same time zone. We extract the date-only from the zoned date-time object.
LocalDate localDateToday = zdt.toLocalDate();
ZonedDateTime zdtStart = ZonedDateTime.of( localDateToday , start , z );
ZonedDateTime zdtStop = ZonedDateTime.of( localDateToday , stop , z );
Study the class documentation to understand the behavior of ZonedDateTime.of in resolving invalid time-of-day values. There is no perfect way to resolve nonexistent time-of-day values, so you must decide if this class’ way meets your business rules.
ZonedDateTime.of
public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone)
Obtains an instance of ZonedDateTime from a local date and time.
This creates a zoned date-time matching the input local date and time as closely as possible. Time-zone rules, such as daylight savings, mean that not every local date-time is valid for the specified zone, thus the local date-time may be adjusted.
The local date time and first combined to form a local date-time. The local date-time is then resolved to a single instant on the time-line. This is achieved by finding a valid offset from UTC/Greenwich for the local date-time as defined by the rules of the zone ID.
In most cases, there is only one valid offset for a local date-time. In the case of an overlap, when clocks are set back, there are two valid offsets. This method uses the earlier offset typically corresponding to "summer".
In the case of a gap, when clocks jump forward, there is no valid offset. Instead, the local date-time is adjusted to be later by the length of the gap. For a typical one hour daylight savings change, the local date-time will be moved one hour later into the offset typically corresponding to "summer".
Apply the same comparison logic as we saw above.
Boolean isNowOnOrAfterStart = ( ! zdt.isBefore( zdtStart ) ) ; // A briefer way of asking "is equal to OR is after" is "is not before".
Boolean isNowBeforeStop = zdt.isBefore( zdtStop );
Boolean isNowInTargetZone = ( isNowOnOrAfterStart && isNowBeforeStop ); // Half-Open: beginning is inclusive while ending is exclusive.
Alternative way to make the comparison is to use the handy Interval class from the ThreeTen-Extra project. That class takes a pain of Instant objects, which you can extract from your ZonedDateTime objects. 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).
Interval interval = Interval.of( zdtStart.toInstant() , zdtStop.toInstant() );
Boolean isNowInTargetZone = interval.contains( zdt.toInstant() );
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.
As pointed out by Kevin, Fuzzy Lollipop's Regex won't pick up times between 14:00 and 19:00.
To get match a full 24 hour clock, you can use this:
if (hhmmss.matches("^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"))
{
// Do stuff here
}
The following Class is something I just created out of some of the code from other answers. It encapsulates the behavior of a 'time period' without relating to specific days. Our system is using this Class to check if the current time is within one of our designated maintenance windows. i.e. 05:00:00 - 07:00:00
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
/**
*
* #author Adam Yocum
*/
public class ExclusionTimePeriod {
private String timeStart;
private String timeEnd;
/**
* #return the timeStart
*/
public String getTimeStart() {
return timeStart;
}
/**
* #param timeStart the timeStart to set
*/
public void setTimeStart(String timeStart) {
if (timeStart.matches("^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"))
{
this.timeStart = timeStart;
}
else
{
throw new IllegalArgumentException(timeStart + " is not a valid time, expecting HH:MM:SS format");
}
}
/**
* #return the timeEnd
*/
public String getTimeEnd() {
return timeEnd;
}
/**
* #param timeEnd the timeEnd to set
*/
public void setTimeEnd(String timeEnd) {
if (timeEnd.matches("^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"))
{
this.timeEnd = timeEnd;
}
else
{
throw new IllegalArgumentException(timeEnd + " is not a valid time, expecting HH:MM:SS format");
}
}
private Date toDate(String hhmmss){
final String[] hms = hhmmss.split(":");
final GregorianCalendar gc = new GregorianCalendar();
gc.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hms[0]));
gc.set(Calendar.MINUTE, Integer.parseInt(hms[1]));
gc.set(Calendar.SECOND, Integer.parseInt(hms[2]));
gc.set(Calendar.MILLISECOND, 0);
Date date = gc.getTime();
return date;
}
public boolean isNowInPeriod()
{
final Date now = new Date();
return now.after(toDate(getTimeStart())) && now.before(toDate(getTimeEnd()));
}
public static void main(String[] args){
//Test All possible hours
for(int hour=0;hour<=23;hour++){
String hourStr = "";
if(hour<=9){
hourStr = "0"+hour;
}else{
hourStr = ""+hour;
}
for(int min=0;min<60;min++){
String minStr = "";
if(min<=9){
minStr = "0"+min;
}else{
minStr = ""+min;
}
for(int sec=0;sec<60;sec++){
String secStr = "";
if(sec<=9){
secStr = "0"+sec;
}else{
secStr = ""+sec;
}
String hhmmss = hourStr+":"+minStr+":"+secStr;
ExclusionTimePeriod period = new ExclusionTimePeriod();
period.setTimeStart(hhmmss);
period.setTimeEnd(hhmmss);
System.out.println(hhmmss+" Ok");
}
}
}
//Test isInPeriod functionality
ExclusionTimePeriod isInTest = new ExclusionTimePeriod();
isInTest.setTimeStart("10:00:00");
isInTest.setTimeEnd("10:43:00");
System.out.println((new Date())+" is between "+isInTest.getTimeStart()+" and "+isInTest.getTimeEnd()+" = "+isInTest.isNowInPeriod());
}
}
The Midnight Problem
Other answers fail to mention it - and the OP doesn't ask - but you should really consider when the interval spans across midnight.
Time is difficult. I purposely left the "long" version of the code and didn't abbreviate logical conditions to make it as clear as possible the what's and the why's.
/**
* Takes into consideration that the interval may span accross midnight
*
* #param clock to make unit testing easier, just replace for Clock.systemUTC() in your code
* #param start the interval start
* #param end the interval end
* #return true if "now" is inside the specified interval
*/
static boolean isNowBetweenLocalTime(Clock clock, final LocalTime start, final LocalTime end) {
LocalTime now = LocalTime.now(clock);
// if interval crosses midnight
if (end.isBefore(start)) {
if (now.isAfter(start) && now.isAfter(end)) {
return true;
}
if (now.isBefore(start) && now.isBefore(end)) {
return true;
}
return false;
}
// if interval does not cross midnight
if (end.isAfter(start)) {
if (now.isAfter(start) && now.isBefore(end)) {
return true;
}
return false;
}
return false; // interval is 0 so start and end always outside interval
}
Verbosity is not always wrong. This method will be buried in a utility class and two years from now you'll thank yourself for understanding what it does!
The dateFromHourMinSec method is flawed as written. It won't allow any hours where the seconde digit is greater than 3, e.g. 18:00:00. If you change it to allow [0-2][0-9] it will allow times such as 29:00:00.
Have a fix for that?

Categories

Resources