Checking dates if it is in a range - java

My Java FX app handles hours worked. I have work start and end time in 2 date fields. I succeeded in calculating the differences between 2 datesTime; but now how could I check if the result is in a night or day range???? The day begin at 6 and ends at 22h. For example someone who worked between 3Am till 11Pm.
Here is below how I did to have the total number of hours worked.
public void CalculNbreJourTravaille() {
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyy HH:mm");
try {
Date ddtt = format.parse(ddt.getText());
Date dftt = format.parse(dft.getText());
long diff = dftt.getTime() - ddtt.getTime();
long diffhours = diff / (60*60*1000)%24;
long diffdays = diff/(24*60*60*1000);
long total = diffhours + (diffdays*24);
result.setText(total + " Hours");
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
We have workers who can work beyond 10PM, and the pay would not be the same. If they work after 10pm, they will have a special pay. We pay at the end of the work. They could would work only 10 days or more.

You should use the new DateTimeFormatter class to give you a LocalDateTime object, which you can pull the hour from.
DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
LocalDateTime localDateTimeFrom = format.parse(dateFrom.getText(), LocalDateTime::from);
LocalDateTime localDateTimeTo = format.parse(dateTo.getText(), LocalDateTime::from);
int hoursFrom = localDateTimeFrom.getHour();
int hoursTo = localDateTimeTo.getHour();
boolean workedNight = hoursFrom < 6 || hoursTo > 22;

Here’s my attempt to cover all of your requirements. I wrote the code before reading that you don’t require that summer time (DST) is taken into account, so I am using ZonedDateTime to get correct hours also across summer time transitions. For the same reason I need to iterate over each day. For each date I calculate the hours worked at night time and the hours worked at day time.
If you want to make sure that summer time is not taken into account, use LocalDateTime instead of ZonedDateTime. In this case there may also be a possible performance gain in calculating the whole work days in one lump rather than one day at a time.
The code below uses 28/03/2018 03:00 and 29/03/2018 23:30 as example start and end time. Expected total hours worked are 44.5 since one day is 24 hours and there are 20.5 hours from 03:00 to 23:30. The expected day time hours are 32 since there are 16 daytime hours each of the two days. This leaves 12.5 hours as night time. And indeed the code prints
Day 32.0 hours; night 12.5 hours
The program follows. Please fill in the correct time zone where I put America/Monterey.
static ZoneId zone = ZoneId.of("America/Monterrey");
static LocalTime dayStart = LocalTime.of(6, 0);
static LocalTime dayEnd = LocalTime.of(22, 0);
static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu H:mm");
public static void main(String[] args) {
String workStartString = "28/03/2018 03:00";
String workEndString = "29/03/2018 23:30";
calculateWorkingHours(workStartString, workEndString);
}
public static void calculateWorkingHours(String workStartString, String workEndString) {
ZonedDateTime workStart
= LocalDateTime.parse(workStartString, formatter).atZone(zone);
ZonedDateTime workEnd
= LocalDateTime.parse(workEndString, formatter).atZone(zone);
if (workEnd.isBefore(workStart)) {
throw new IllegalArgumentException("Work end must not be before work start");
}
LocalDate workStartDate = workStart.toLocalDate();
LocalDate workEndDate = workEnd.toLocalDate();
Duration workedDaytime = Duration.ZERO;
// first calculate work at nighttime before the start date, that is, work before 06:00
Duration workedNighttime
= calculateNightTime(workStartDate.minusDays(1), workStart, workEnd);
for (LocalDate d = workStartDate; ! d.isAfter(workEndDate); d = d.plusDays(1)) {
workedDaytime = workedDaytime.plus(calculateDayTime(d, workStart, workEnd));
workedNighttime = workedNighttime.plus(calculateNightTime(d, workStart, workEnd));
}
double dayHours = workedDaytime.toMinutes() / (double) TimeUnit.HOURS.toMinutes(1);
double nightHours = workedNighttime.toMinutes() / (double) TimeUnit.HOURS.toMinutes(1);
System.out.println("Day " + dayHours + " hours; night " + nightHours + " hours");
}
/**
* Calculates amount of work in daytime on d,
* that is between 06:00 and 22:00 on d.
* Only time that falls with in workStart to workAnd
* and also falls within 06:00 to 22:00 on d is included.
*
* #param d The date for which to calculate day work
* #param workStart
* #param workEnd
* #return Amount of daytime work on the said day
*/
private static Duration calculateDayTime(LocalDate d, ZonedDateTime workStart, ZonedDateTime workEnd) {
ZonedDateTime dayStartToday = d.atTime(dayStart).atZone(zone);
ZonedDateTime dayEndToday = d.atTime(dayEnd).atZone(zone);
if (workStart.isAfter(dayEndToday) || workEnd.isBefore(dayStartToday)) {
return Duration.ZERO;
}
// restrict calculation to daytime on d
if (workStart.isBefore(dayStartToday)) {
workStart = dayStartToday;
}
if (workEnd.isAfter(dayEndToday)) {
workEnd = dayEndToday;
}
return Duration.between(workStart, workEnd);
}
/**
* Calculates amount of night work in the night after d,
* that is from 22:00 on d until 06:00 the next morning.
*
* #param d The date for which to calculate night work
* #param workStart
* #param workEnd
* #return Amount of nighttime work in said night
*/
private static Duration calculateNightTime(LocalDate d, ZonedDateTime workStart, ZonedDateTime workEnd) {
assert ! workEnd.isBefore(workStart);
ZonedDateTime nightStart = d.atTime(dayEnd).atZone(zone);
ZonedDateTime nightEnd = d.plusDays(1).atTime(dayStart).atZone(zone);
if (workEnd.isBefore(nightStart) || workStart.isAfter(nightEnd)) {
return Duration.ZERO;
}
// restrict calculation to the night after d
if (workStart.isBefore(nightStart)) {
workStart = nightStart;
}
if (workEnd.isAfter(nightEnd)) {
workEnd = nightEnd;
}
return Duration.between(workStart, workEnd);
}

You can check the LocalTime part of a LocalDateTime to have a simple check using isAfter and isBefore.
I will use those values for this example.
LocalDateTime start = LocalDateTime.of(2018, Month.APRIL, 30, 23, 0);
LocalDateTime end = LocalDateTime.of(2018, Month.MAY, 1, 5, 0);
Then define the limit for the night.
LocalTime startNight = LocalTime.of(22, 0);
LocalTime endNight = LocalTime.of(6, 0);
And simply use get the LocalTime of both date and check if they are in the range. You can get the value using toLocalTime.
if(start.toLocalTime().isAfter(startNight) &&
end.toLocalTime().isBefore(endNight)){
System.out.println("NIGHT TIME");
} else {
System.out.println("DAY TIME");
}
NIGHT TIME
The output is valid since we start at 23:00 and end at 05:00.
Using this allow a simpler solution if you need to define a time like LocalTime.of(5,45) for 5:45
This is an example, this might need some adaptation if it is allowed to start part 22 but keep working after 6. This is just an example on how to use those methods.

This is easier, if you use the java.time API. You simply need to check, if the dates differ or if the starting time not in the range from 6:00 to 22:00:
private static final LocalTime START_TIME = LocalTime.of(6, 0); // 06:00
private static final LocalTime END_TIME = LocalTime.of(22, 0); // 22:00
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
// parse from input strings
LocalDateTime start = LocalDateTime.parse(startText, FORMATTER);
LocalDateTime end = LocalDateTime.parse(endText, FORMATTER);
boolean nightTime =
!start.toLocalDate().equals(end.toLocalDate())
|| start.toLocalTime().isBefore(START_TIME)
|| end.toLocalTime().isAfter(END_TIME);
// todo: change output to gui
System.out.println("night time: " + nightTime);
System.out.println("duration : " + Duration.between(start, end).toHours());

Define two formatters. One Fromatter to get date with time from edittext. And other On to get 12AM of that day. Now we need Date Objects corresponding to 6AM and 11PM of the same day. We can get those by adding that much milliseconds to the 12AM Object. These added dates can be used for comparison.
SimpleDateFormat df_zero_hours = new SimpleDateFormat("dd/MM/yyy");
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
Date ddtt = format.parse(ddt.getText()); //Work Start Time
Date dftt = format.parse(dft.getText()); //Work End Time
Date dateStart = df_zero_hours.parse(ddt.getText()); //12AM of the day job started
Date dayStart = new Date();
dayStart.setTime(dateStart.getTime()+6*60*60*1000); // Get 6AM of that day
Date dayEnd = new Date();
dayEnd.setTime(dateStart.getTime()+22*60*60*1000); //Get 10PM of that day
// Now check the worked hours. in Whatever way you need
boolean isBefore6AM = (dayStart.getTime()-ddtt.getTime())>0;
boolean isAfter10PM = (dftt.getTime()-dayEnd.getTime())>0;

Related

how to calculate and split a float value into two separate integer values ?? e.g 18.5f hours equals int h=18 int m=30

I am creating a Workday calendar program that calculates a 'start' and 'end' date
the results should output:
"Starting date: 24-05-2004 07:03 with addition of 8.276628 working days is end date: 04-06-2004 10:12"
or
24-05-2004 18:03 with the addition of -6.7470217 working days is 13-05-2004 10:02
The mathematical solution is to multiply hours pr day with incrementInWokringdays
like 8.0f hours a day * 2.5f days = 18.4f hours and then the result of this should be added to the Date calendar this way
-date.add( Calendar.Hours_of_Day, 18.0f ) //but from float converted to integers
-date.add( Calendar.Minutes_of_Day, 0.4f )//
how do i split the value 18.4f hours in to
'int hours = 18;'
and
'int minutes = 40;'
????
public Date getWorkdayIncrement(Calendar date, float incrementInWorkdays) {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm");
System.out.println("start day: " + f.format(date.getTime()));
// so if chosen incrementDays is 2.3 days and workinghours pr day is 7.5h you multiply them together to get total working hours
float totalHoursWorkedPrDay = getWorkdayStartAndStop() * incrementInWorkdays;
// needed to convert hours and minutes to integer values in order to increment calendar
int hoursToIncrement = (int) totalHoursWorkedPrDay; //gets only hours
// get the last to decimals 0.25 representing the minutes which means 25 percent of 60min
float lastTwoDecimalsOfTotalWorkingHours = ((totalHoursWorkedPrDay - (float) hoursToIncrement) * 100);
//calculate percent of minutes and convert to integer (25 / 100 * 60) = 15min
int minutesToIncrement = (int) ((lastTwoDecimalsOfTotalWorkingHours / 100) *60);
System.out.println("Hours to increment: " + hoursToIncrement);
System.out.println("Minutes to increment: " + minutesToIncrement);
//increment calendar
date.add(Calendar.HOUR_OF_DAY, hoursToIncrement);
date.add(Calendar.MINUTE, minutesToIncrement);
Date endDate = date.getTime();
System.out.println("End date excluding holidays: " + f.format(endDate));
}
I didn’t follow everything you were doing in the question. So for now I focus on calculating the working hours of a working day given start and end time. I am assuming that you get start and end as GregorianCalendar objects from some legacy API that you cannot afford to upgrade to java.time just now.
I recommend that you use java.time, the modern Java date and time API, for your date and time work. Even if you are getting your data as objects of the old-fashioned date-time types. java.time is so much nicer to work with.
static float getHoursBetween(Calendar start, Calendar end) {
ZonedDateTime startZdt = ((GregorianCalendar) start).toZonedDateTime();
ZonedDateTime endZdt = ((GregorianCalendar) end).toZonedDateTime();
long wholeDays = ChronoUnit.DAYS.between(startZdt, endZdt);
startZdt = startZdt.plusDays(wholeDays);
Duration workDay = Duration.between(startZdt, endZdt);
return (float) workDay.toMinutes() / (float) Duration.ofHours(1).toMinutes();
}
The method ignores the date difference between start and end by adding the number of full days to the start time. This means that the result we get is based only on the hours and minutes. To try the method out, let’s construct a couple of GregorianCalendar objects (of course I am using java.time for that too):
ZoneId zone = ZoneId.of("America/Araguaina");
ZonedDateTime workDayStart = ZonedDateTime.of(2020, 6, 14, 7, 30, 0, 0, zone);
Calendar workDayStartCal = GregorianCalendar.from(workDayStart);
ZonedDateTime workDayEnd = ZonedDateTime.of(2020, 6, 15, 15, 15, 0, 0, zone);
Calendar workDayEndCal = GregorianCalendar.from(workDayEnd);
float workingDay = getHoursBetween(workDayStartCal, workDayEndCal);
System.out.println(workingDay);
Output from the example is:
7.75
Edit: for the opposite conversion this works since Java 9:
float hours = 7.75f;
Duration dur = Duration.ofMinutes(Math.round(hours * Duration.ofHours(1).toMinutes()));
System.out.println("Hours: " + dur.toHours());
System.out.println("Minutes: " + dur.toMinutesPart());
Hours: 7
Minutes: 45
Link
Oracle tutorial: Date Time explaining how to use java.time.

Get current time and check if time has passed a certain period

this code below gets the current time and timezone of the area
Date date = new Date();
DateFormat df = new SimpleDateFormat("HH:mm:ss");
df.setTimeZone(TimeZone.getDefault());
System.out.println("Time: " + df.format(date));
right now its 1:01 pm (at the time of typing)
what i need help doing is implementing a feature in the code that checks if the current time has passed, for example 1:00PM
but I have no idea where to even start, can you help me out?
Use the Java 8+ Time API class LocalTime:
LocalTime refTime = LocalTime.of(13, 0); // 1:00 PM
// Check if now > refTime, in default time zone
LocalTime now = LocalTime.now();
if (now.isAfter(refTime)) {
// passed
}
// Check if now >= refTime, in pacific time zone
LocalTime now = LocalTime.now(ZoneId.of("America/Los_Angeles"))
if (now.compareTo(refTime) >= 0) {
// passed
}
I see it has already answered with Time, but as a teaching point, if you really wanted to use Date, you could have done something like this:
public static void main(String[] args) {
Date date = new Date();
DateFormat df = new SimpleDateFormat("HH:mm:ss");
df.setTimeZone(TimeZone.getDefault());
System.out.println("Time: " + df.format(date));
//If you print the date you'll see how it is formatted
//System.out.println(date.toString());
//So you can just split the string and use the segment you want
String[] fullDate = date.toString().split(" ");
String compareAgainstTime = "01:00PM";
System.out.println(isPastTime(fullDate[3],compareAgainstTime));
}
public static boolean isPastTime(String currentTime, String comparedTime) {
//We need to make the comparison time into the same format as the current time: 24H instead of 12H:
//then we'll just convert the time into only minutes to that we can more easily compare;
int comparedHour = comparedTime[-2].equals("AM") ? String.valueOf(comparedTime[0:2]) : String.valueOf(comparedTime[0:2] + 12 );
int comparedMin = String.valueOf(comparedTime[3:5]);
int comparedT = comparedHour*60 + comparedMin;
//obviously currentTime is alredy the correct format; just need to convert to minutes
int currentHour = String.valueOf(currentTime[0:2]);
int currentMin = String.valueOf(currentTime[3:5]);
int currentT = currentHour*60 + currentMin;
return (currentT > comparedT);
}
It's a bit messier, having to muddy into the Strings and whatnot, but it is possible. You would also have to be careful the zero-pad the comparedTime or just check for that in the function

Converting timestamp to days and back results in a different date

I need to store year-moth-day information w/o timezone info.
Here's some code:
private static void test() {
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("US/Pacific"));
System.out.println("Before: " + cal.get(DAY_OF_MONTH));
//
long datestamp = toDatestamp(cal.getTimeInMillis());
long timestamp = toTimestamp(datestamp);
cal.setTimeInMillis(timestamp);
System.out.println("After: " + cal.get(DAY_OF_MONTH));
}
private static long toTimestamp(long datestamp) {
return TimeUnit.DAYS.toMillis(datestamp);
// return datestamp * DS_MULT;
}
private static long toDatestamp(long timestamp) {
return TimeUnit.MILLISECONDS.toDays(timestamp);
// return timestamp / DS_MULT;
}
// hours * minutes * seconds * milliseconds
private static long DS_MULT = 24 * 60 * 60 * 1000;
with 2 approaches, one of which is commented out. But result is the same:
Before: 26
After: 25
Why does the date change after conversion? Am I missing something obvious?
By converting to days and back to milliseconds, you're effectively re-setting the calendar to midnight of that day. But, when you set the time in milliseconds, it's interpreted as UTC time (roughly equivalent to GMT), so you're resetting the calendar to midnight UTC. Because the timezone "US/Pacific" has a negative offset from UTC, it appears as the previous day.
You can see this by adding another line at the end of test:
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC: " + cal.get(DAY_OF_MONTH));
And you should see:
UTC: 26

Get the number of weeks between two Dates.

Im working in a project and I got two types in Date. I want to calculate the number of weeks between these two dates. The dates can be in diffrent years. Is there any good solution for this?
I have tried to implemenent this with Joda-time which was suggested in other topics..
Im not familar with this library, but I tried to do something like this:
public static int getNumberOfWeeks(Date f, Date l){
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTime(f);
c2.setTime(l);
DateTime start = new DateTime(c1.YEAR, c1.MONTH, c1.DAY_OF_MONTH, 0, 0, 0, 0);
DateTime end = new DateTime(c2.YEAR, c2.MONTH, c2.DAY_OF_MONTH, 0, 0, 0, 0);
Interval interval = new Interval(start, end);
Period p = interval.toPeriod();
return p.getWeeks();
}
But this is completely wrong... any suggestions ?
Updating answer to account for Java 8
// TechTrip - ASSUMPTION d1 is earlier than d2
// leave that for exercise
public static long getFullWeeks(Calendar d1, Calendar d2){
Instant d1i = Instant.ofEpochMilli(d1.getTimeInMillis());
Instant d2i = Instant.ofEpochMilli(d2.getTimeInMillis());
LocalDateTime startDate = LocalDateTime.ofInstant(d1i, ZoneId.systemDefault());
LocalDateTime endDate = LocalDateTime.ofInstant(d2i, ZoneId.systemDefault());
return ChronoUnit.WEEKS.between(startDate, endDate);
}
It is pretty easy with joda time:
DateTime dateTime1 = new DateTime(date1);
DateTime dateTime2 = new DateTime(date2);
int weeks = Weeks.weeksBetween(dateTime1, dateTime2).getWeeks();
tl;dr
ChronoUnit
.WEEKS
.between(
myJavaUtilDate_Start.toInstant().atZone( ZoneId.of( "Asia/Tokyo" ) ) ,
myJavaUtilDate_Stop.toInstant().atZone( ZoneId.of( "Asia/Tokyo" ) )
)
7
java.time
The java.time framework is built into Java 8 and later. These new classes supplant the old date-time classes bundled with the earliest versions of Java.
The java.time classes also supplant the highly successful Joda-Time framework. Both java.time and Joda-Time are led by Stephen Colbourne.
Instant replaces java.util.Date
The modern class Instant replaces the legacy class java.util.Date. Both represent a moment in UTC, a specific point on the timeline. Both internally use a count since the same epoch reference of the first moment of 1970 in UTC, 1970-01-01T00:00Z. The old class uses a count of milliseconds, while Instant uses a finer count of nanoseconds.
To convert, call new methods added to the old classes.
Instant start = myJavaUtilDateStart.toInstant() ;
Instant stop = myJavaUtilDateStop.toInstant() ;
Let's make this concrete with some example values.
Instant start = OffsetDateTime.of( 2020 , 1 , 23 , 15 , 30 , 0 , 0 , ZoneOffset.UTC ).toInstant();
Instant stop = OffsetDateTime.of( 2020 , 1 , 23 , 15 , 30 , 0 , 0 , ZoneOffset.UTC ).plusWeeks(7 ).toInstant();
Moments versus dates
Both of our Instant objects represent a moment. The goal is a count of weeks. Weeks means days, and days mean certain dates on the calendar.
So we have a bit of a mismatch. For any given moment, the date varies around the globe by time zone. A few minutes after midnight in Paris France is a new date. Meanwhile in Montréal Québec, being several hours behind, that same moment is still “yesterday”, the date before on the calendar. So we cannot directly calculate weeks from a pair of moments.
You must first decide on the time zone by which you want to perceive a calendar for those moments.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-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
Apply this ZoneId to our Instant objects to adjust into a time zone, yielding a pair of ZonedDateTime objects.
ZonedDateTime startZdt = start.atZone( z ) ;
ZonedDateTime stopZdt = stop.atZone( z ) ;
ChronoUnit.WEEKS
Now we can use the ChronoUnit enum to calculate elapsed weeks.
long weeks = ChronoUnit.WEEKS.between( startZdt , stopZdt );
Dump to console.
System.out.println( "start.toString() = " + start );
System.out.println( "stop.toString() = " + stop );
System.out.println( "startZdt.toString() = " + startZdt );
System.out.println( "stopZdt.toString() = " + stopZdt );
System.out.println( "weeksCount: " + weeksCount );
See this code run live at IdeOne.com.
start.toString() = 2020-01-23T15:30:00Z
stop.toString() = 2020-03-12T15:30:00Z
startZdt.toString() = 2020-01-23T10:30-05:00[America/Montreal]
stopZdt.toString() = 2020-03-12T11:30-04:00[America/Montreal]
weeksCount: 7
ThreeTen-Extra
The ThreeTen-Extra project adds functionality to the java.time framework built into Java 8 and later.
Weeks class
That project includes a Weeks class to represent a number of weeks. Not only can it calculate, it is also meant to be used in your code as a type-safe object. Such use also helps to make your code self-documenting.
You can instantiate by providing a pair of points in time with the Weeks.between method. Those points in time can be anything implementing java.time.temporal.Temporal including Instant, LocalDate, OffsetDateTime, ZonedDateTime, Year, YearMonth, and more.
Your java.util.Date objects can be easily converted to Instant objects, moments on the timeline in UTC with a resolution in nanoseconds. Look at new methods added to the old date-time classes. For going from Date to Instant, call java.util.Date::toInstant.
Weeks weeks = Weeks.between( startZdt , stopZdt );
You can ask for the number of weeks.
int weeksNumber = weeks.getAmount(); // The number of weeks in this Weeks object.
You can also do much more.
Generate a string in standard ISO 8601 format. The P marks the beginning. The W indicates a number of weeks.
PW7
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.
Using the date arithmetic in java.util.Calendar:
public static int getWeeksBetween (Date a, Date b) {
if (b.before(a)) {
return -getWeeksBetween(b, a);
}
a = resetTime(a);
b = resetTime(b);
Calendar cal = new GregorianCalendar();
cal.setTime(a);
int weeks = 0;
while (cal.getTime().before(b)) {
// add another week
cal.add(Calendar.WEEK_OF_YEAR, 1);
weeks++;
}
return weeks;
}
public static Date resetTime (Date d) {
Calendar cal = new GregorianCalendar();
cal.setTime(d);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
If your requirement is like the start date is 03-Apr-2020 and end date is 07-Apr-2020. the difference between the two dates is 4 days. Now the number of weeks between two dates as 1 for this you can use below snippet.
ChronoUnit.WEEKS.between(LocalDate startDate, LocalDate endDate);
But If your requirement is like 03-Apr-2020 is in one week and 07-Apr-2020 is in another week so you want the number of weeks between two dates as 2 you can use the below snippet.
LocalDate actualStartDate=...
LocalDate actualEndDate=...
LocalDate startDate = actualStartDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))
LocalDate endDate = actualEndDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SATURDAY))
long daysBetweenTwoDates = ChronoUnit.DAYS.between(startDate, endDate);
int numberOfWeeks = (int)Math.ceil(daysBetweenTwoDates/7.0);
Tested in java 1.8
Calendar a = new GregorianCalendar(2002,1,22);
Calendar b = new GregorianCalendar(2002,1,28);
System.out.println(a.get(Calendar.WEEK_OF_YEAR));
System.out.println(b.get(Calendar.WEEK_OF_YEAR));
int weeks = b.get(Calendar.WEEK_OF_YEAR)-a.get(Calendar.WEEK_OF_YEAR);
System.out.println(weeks);
try this must work
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.set(2007, 01, 10);
calendar2.set(2007, 07, 01);
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
int diffWeeks = (int)diff / (7*24 * 60 * 60 * 1000);
Here are 2 methods I wrote that not based on an external library.
The first method is when Monday is the first day of the week.
The second method is when Sunday is the first day of the week.
Please read the comments inside the code, there is an option to return the number of the full weeks between 2 dates, and also with the fraction of the remaining days before and after the 2 dates.
public static int getNumberOfFullWeeks(LocalDate startDate,LocalDate endDate)
{
int dayBeforeStartOfWeek = 0;
int daysAfterLastFullWeek = 0;
if(startDate.getDayOfWeek() != DayOfWeek.MONDAY)
{
// get the partial value before loop starting
dayBeforeStartOfWeek = 7-startDate.getDayOfWeek().getValue() + 1;
}
if(endDate.getDayOfWeek() != DayOfWeek.SUNDAY)
{
// get the partial value after loop ending
daysAfterLastFullWeek = endDate.getDayOfWeek().getValue();
}
LocalDate d1 = startDate.plusDays(dayBeforeStartOfWeek); // now it is the first day of week;
LocalDate d2 = endDate.minusDays(daysAfterLastFullWeek); // now it end in the last full week
// Count how many days there are of full weeks that start on Mon and end in Sun
// if the startDate and endDate are less than a full week the while loop
// will not iterate at all because d1 and d2 will be the same date
LocalDate looper = d1;
int counter = 1;
while (looper.isBefore(d2))
{
counter++;
looper = looper.plusDays(1);
}
// Counter / 7 will always be an integer that will represents full week
// because we started to count at Mon and stop counting in Sun
int fullWeeks = counter / 7;
System.out.println("Full weeks between dates: "
+ fullWeeks + " Days before the first monday: "
+ dayBeforeStartOfWeek + " "
+ " Days after the last sunday: " + daysAfterLastFullWeek);
System.out.println(startDate.toString() + " - " + endDate.toString());
// You can also get a decimal value of the full weeks plus the fraction if the days before
// and after the full weeks
float full_weeks_decimal = (float)fullWeeks;
float fraction = ((float)dayBeforeStartOfWeek + (float)daysAfterLastFullWeek) / 7.0F;
System.out.println("Full weeks with fraction: " + String.valueOf(fraction + full_weeks_decimal));
return fullWeeks;
}
public static int getNumberOfFullWeeks_WeekStartAtSunday(LocalDate startDate,LocalDate endDate)
{
int dayBeforeStartOfWeek = 0;
int daysAfterLastFullWeek = 0;
if(startDate.getDayOfWeek() != DayOfWeek.SUNDAY)
{
// get the partial value before loop starting
dayBeforeStartOfWeek = 7-getDayOfWeekBySundayIs0(startDate.getDayOfWeek()) + 1;
}
if(endDate.getDayOfWeek() != DayOfWeek.SATURDAY)
{
// get the partial value after loop ending
daysAfterLastFullWeek = 1+getDayOfWeekBySundayIs0(endDate.getDayOfWeek());
}
LocalDate d1 = startDate.plusDays(dayBeforeStartOfWeek); // now it is the first day of week;
LocalDate d2 = endDate.minusDays(daysAfterLastFullWeek); // now it end in the last full week
// Count how many days there are of full weeks that start on Sun and end in Sat
// if the startDate and endDate are less than a full week the while loop
// will not iterate at all because d1 and d2 will be the same date
LocalDate looper = d1;
int counter = 1;
while (looper.isBefore(d2))
{
counter++;
looper = looper.plusDays(1);
}
// Counter / 7 will always be an integer that will represents full week
// because we started to count at Sun and stop counting in Sat
int fullWeeks = counter / 7;
System.out.println("Full weeks between dates: "
+ fullWeeks + " Days before the first sunday: "
+ dayBeforeStartOfWeek + " "
+ " Days after the last saturday: " + daysAfterLastFullWeek);
System.out.println(startDate.toString() + " - " + endDate.toString());
// You can also get a decimal value of the full weeks plus the fraction if the days before
// and after the full weeks
float full_weeks_decimal = (float)fullWeeks;
float fraction = ((float)dayBeforeStartOfWeek + (float)daysAfterLastFullWeek) / 7.0F;
System.out.println("Full weeks with fraction: " + String.valueOf(fraction + full_weeks_decimal));
return fullWeeks;
}
public static int getDayOfWeekBySundayIs0(DayOfWeek day)
{
if(day == DayOfWeek.SUNDAY)
{
return 0;
}
else
{
// NOTE: getValue() is starting to count from 1 and not from 0
return day.getValue();
}
}
If you want exact number of full weeks use below method, where end date is exclusive:
public static long weeksBetween(Date date1, Date date2) {
return WEEKS.between(date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
}
If you want a ceil version of this, use below:
public static long weeksBetween(Date date1, Date date2) {
long daysBetween = DAYS.between(date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()) + 1;
return daysBetween / 7 + (daysBetween % 7 == 0 ? 0 : 1);
}
You may do it the following way:
// method header not shown
// example dates:
f = new GregorianCalendar(2009,Calendar.AUGUST,1);
l = new GregorianCalendar(2010,Calendar.SEPTEMBER,1);
DateTime start = new DateTime(f);
DateTime end = new DateTime(l);
// Alternative to above - example dates with joda:
// DateTime start = new DateTime(2009,8,1,0,0,0,0);
// DateTime end = new DateTime(2010,9,1,0,0,0,0);
Interval interval = new Interval(start,end);
int weeksBetween = interval.toPeriod(PeriodType.weeks()).getWeeks();
// return weeksBetween;
This should give you an int representing the number of weeks between the two dates.
Joda Time computes weeks with durations of two dates which may not meet our requirements in some cases. I have a method with Joda Time to compute natural weeks between two dates. Hope it can help you. If you don't use Joda Time, you may modify the code with Calendar to do the same thing.
//Unlike Joda Time Weeks.weeksBetween() that returns whole weeks computed
//from duration, we return natural weeks between two dates based on week of year
public static int weeksBetween(ReadablePartial date1, ReadablePartial date2) {
int comp = date1.compareTo(date2);
if (comp == 0) {
return 0;
}
if (comp > 0) {
ReadablePartial mid = date2;
date2 = date1;
date1 = mid;
}
int year1 = date1.get(DateTimeFieldType.weekyear());
int year2 = date2.get(DateTimeFieldType.weekyear());
if (year1 == year2) {
return date2.get(DateTimeFieldType.weekOfWeekyear()) - date1.get(DateTimeFieldType.weekOfWeekyear());
}
int weeks1 = 0;
LocalDate lastDay1 = new LocalDate(date1.get(DateTimeFieldType.year()), 12, 31);
if (lastDay1.getWeekyear() > year1) {
lastDay1 = lastDay1.minusDays(7);
weeks1++;
}
weeks1 += lastDay1.getWeekOfWeekyear() - date1.get(DateTimeFieldType.weekOfWeekyear());
int midWeeks = 0;
for (int i = year1 + 1; i < year2; i++) {
LocalDate y1 = new LocalDate(i, 1, 1);
int yearY1 = y1.getWeekyear();
if (yearY1 < i) {
y1 = y1.plusDays(7);
midWeeks++;
}
LocalDate y2 = new LocalDate(i, 12, 31);
int yearY2 = y2.getWeekyear();
if (yearY2 > i) {
y2 = y2.minusDays(7);
midWeeks++;
}
midWeeks += y2.getWeekOfWeekyear() - y1.getWeekOfWeekyear();
}
int weeks2 = 0;
LocalDate firstDay2 = new LocalDate(date2.get(DateTimeFieldType.year()), 1, 1);
if (firstDay2.getWeekyear() < firstDay2.getYear()) {
firstDay2 = firstDay2.plusDays(7);
weeks2++;
}
weeks2 += date2.get(DateTimeFieldType.weekOfWeekyear()) - firstDay2.getWeekOfWeekyear();
return weeks1 + midWeeks + weeks2;
}
int startWeek = c1.get(Calendar.WEEK_OF_YEAR);
int endWeek = c2.get(Calendar.WEEK_OF_YEAR);
int diff = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
int deltaYears = 0;
for(int i = 0;i < diff;i++){
deltaYears += c1.getWeeksInWeekYear();
c1.add(Calendar.YEAR, 1);
}
diff = (endWeek + deltaYears) - startWeek;
Includes the year differences.
This worked for me :)
private int weeksBetween(Calendar startDate, Calendar endDate) {
startDate.set(Calendar.HOUR_OF_DAY, 0);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
int start = (int)TimeUnit.MILLISECONDS.toDays(
startDate.getTimeInMillis())
- startDate.get(Calendar.DAY_OF_WEEK);
int end = (int)TimeUnit.MILLISECONDS.toDays(
endDate.getTimeInMillis());
return (end - start) / 7;
}
if this method returns 0 they are in the same week
if this method return 1 endDate is the week after startDate
if this method returns -1 endDate is the week before startDate
you get the idea
Without using JodaTime, I was able to accurately calculate the number of weeks between 2 calendars (which accounts for leap years etc.)
private fun calculateNumberOfWeeks() {
val calendarFrom = Calendar.getInstance()
calendarFrom.set(Calendar.HOUR_OF_DAY, 0)
calendarFrom.set(Calendar.MINUTE, 0)
calendarFrom.set(Calendar.SECOND, 0)
calendarFrom.set(Calendar.MILLISECOND, 0)
val calendarTo = Calendar.getInstance()
calendarTo.add(Calendar.MONTH, months)
calendarTo.set(Calendar.HOUR_OF_DAY, 0)
calendarTo.set(Calendar.MINUTE, 0)
calendarTo.set(Calendar.SECOND, 0)
calendarTo.set(Calendar.MILLISECOND, 0)
var weeks = -1
while (calendarFrom.timeInMillis < calendarTo.timeInMillis) {
calendarFrom.add(Calendar.DATE, 7)
weeks++
Log.d(Constants.LOG_TAG, "weeks $weeks")
}
}
Easy way
Calendar cal1 = new GregorianCalendar();
Calendar cal2 = new GregorianCalendar();
cal1.set(2014, 3, 3);
cal2.set(2015, 3, 6);
weekscount.setText("weeks= "+ ( (cal2.getTime().getTime() - cal1.getTime().getTime()) / (1000 * 60 * 60 * 24))/7);
Here is a simple way to find the number of weeks between two dates.
SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String classStartData = "31 01 2021";
String classEndData = "08 03 2021";
Date dateClassStart = myFormat.parse(classStartData);
Date dateClassEnd = myFormat.parse(classEndData);
long differenceWeek = dateClassEnd.getTime() - dateClassStart.getTime();
int programLength = (int)(TimeUnit.DAYS.convert(differenceWeek, TimeUnit.MILLISECONDS)/7);
System.out.println("Class length in weeks: " +programLength);
After referring many solution, this worked for me.
{Provided I did not want to use external Libraries}
public static int getNumberOfWeeks(Date date1, Date date2) {
if (date1.after(date2)) {
return getNumberOfWeeks(date2, date1);
}
Date date = date1;
int days = 0;
while (date.before(date2)) {
days++;
date = addDays(date, 1);
}
return days/7;
}
To add days to a date :
Date addDays(Date date, int days) {
if (days == 0) {
return date;
} else {
Date shiftedDate = new Date(date.getTime() + (long)days * 86400000L);
return shiftedDate;
}
}
Take a look at the following article: Java - calculate the difference between two dates
The daysBetween method will allow you to get the number of days between dates. Then you can simply divide by 7 to get the number of full weeks.
Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();
date1.clear();
date1.set(datePicker1.getYear(), datePicker1.getMonth(),
datePicker1.getDayOfMonth());
date2.clear();
date2.set(datePicker2.getYear(), datePicker2.getMonth(),
datePicker2.getDayOfMonth());
long diff = date2.getTimeInMillis() - date1.getTimeInMillis();
float dayCount = (float) diff / (24 * 60 * 60 * 1000);
int week = (dayCount / 7) ;
Hope this might Help you
public int diffInWeeks(Date start, Date end) {
long diffSeconds = (end.getTime() - start.getTime())/1000;
return (int)diffSeconds/(60 * 60 * 24 * 7);
}

Comparing dates in milliseconds

Say I have two date fields receiveDate and currentDate. I want to check if receiveDate was 5 days before currentDate. What I did was to convert the dates in milliseconds and then compare against 5. Is there a better way of doing so? If so, how and why mine is any less better? Thanks.
Method I wrote -
private static final double DAY_IN_MILLISECONDS = 86400000;
// Param date is the receivedDate
private long getDaysOld(final Date date) {
Calendar suppliedDate = Calendar.getInstance();
suppliedDate.setTime(date);
Calendar today = Calendar.getInstance();
today.setTime(currentDate);
double ageInMillis = (today.getTimeInMillis() - suppliedDate.getTimeInMillis());
double tempDouble;
if(isEqual(ageInMillis, 0.00) || isGreaterThan(Math.abs(ageInMillis), DAY_IN_MILLISECONDS)) {
tempDouble = ageInMillis / DAY_IN_MILLISECONDS;
} else {
tempDouble = DAY_IN_MILLISECONDS / ageInMillis;
}
long ageInDays = Math.round(tempDouble);
return ageInDays;
}
Then I have something like-
long daysOld = getDaysOld(receivedDate) ;
if(daysOld <= 5) {
.... some business code ....
}
give a try to joda-time. Time calculations with the native API is always akwards at best. Joda time makes this type of calculation MUUUCH simpler and will handle time zones pretty well also.
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class Test {
private static long DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
public static void main(String[] args) throws Exception {
//
Date currentDate = getGregorianDate(1990, Calendar.JANUARY, 20);
Date receiveDate = getGregorianDate(1990, Calendar.JANUARY, 23);
//
if (getDifferenceBetweenDates(receiveDate, currentDate) < 5 * DAY_IN_MILLISECONDS) {
System.out.println("Receive date is not so old.");
}
else {
System.out.println("Receive date is very old.");
}
}
private static long getDifferenceBetweenDates(Date date1, Date date2) {
return Math.abs(date1.getTime() - date2.getTime());
}
private static Date getGregorianDate(int year, int month, int date) {
Calendar calendar = GregorianCalendar.getInstance();
calendar.set(year, month, date);
return calendar.getTime();
}
}
It can be shortened a lot:
int daysOld = (System.currentTimeMillis() - date.getTime()) / DAY_IN_MILLISECONDS;
You can't simply subtract and divide by 24*60*60*1000, because of daylight savings (in which a day could have 23 or 25 hours).
For example, in the UK the clocks moved forward by one hour on 28/03/2010. The difference between 27/03/2010 and 28/03/2010 should be 1 day, but if you follow that approach you will get 0.
You need to take the offset into account:
public static long daysBetween(Date dateEarly, Date dateLater) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(dateEarly);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(dateLater);
long endL = cal2.getTimeInMillis() + cal2.getTimeZone().getOffset( cal2.getTimeInMillis() );
long startL = cal1.getTimeInMillis() + cal1.getTimeZone().getOffset( cal1.getTimeInMillis() );
return (endL - startL) / (24 * 60 * 60 * 1000);
}
public static void main(String[] args) throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
Date foo = new Date(2010,02,27);
Date bar= new Date(2010,02,28);
System.out.println(daysBetween(foo,bar)); //prints 1
}
This all depends on what "five days" means. If you receive something monday lunchtime, then on saturday afternoon, did you receive it within five days or not? The elapsed time is greater than five days, but the day you received it is five days ago. Think about how you'd answer that question; now thing about how your mother would answer that question. It might not be the same - I would suggest that most people, particularly non-programmers, count the passing of days by the passing of local midnights. Five o'clock on wednesday morning is a day after eleven thirty on tuesday night, even though it's less than a day (less than a quarter of a day!) later.
So, i think what you want to do is compare just the dates, not the times. You can do this with Calendar by zeroing all the time fields. Given an arrivedDate and a locale (so you can tell when midnight is), i think this is correct:
Calendar deadline = Calendar.getInstance(locale);
deadline.set(Calendar.HOUR_OF_DAY, 0);
deadline.set(Calendar.MINUTE, 0);
deadline.set(Calendar.SECOND, 0);
deadline.set(Calendar.MILLISECOND, 0);
deadline.add(Calendar.DAY_OF_MONTH, 5);
Calendar arrived = Calendar.getInstance(locale);
arrived.setTime(arrivedDate);
deadline.set(Calendar.HOUR_OF_DAY, 0);
deadline.set(Calendar.MINUTE, 0);
deadline.set(Calendar.SECOND, 0);
deadline.set(Calendar.MILLISECOND, 0);
boolean arrivedWithinDeadline = arrived.compareTo(deadline) <= 0;
You should test that thoroughly before actually using it, though.
Below is my method that returns me exact difference in days,
/**
* method to get difference of days between current date and user selected date
* #param selectedDateTime: your date n time
* #param isLocalTimeStamp: defines whether the timestamp d is in local or UTC format
* #return days
*/
public static long getDateDiff(long selectedDateTime, boolean isLocalTimeStamp)
{
long timeOne = Calendar.getInstance().getTime().getTime();
long timeTwo = selectedDateTime;
if(!isLocalTimeStamp)
timeTwo += getLocalToUtcDelta();
long delta = (timeOne - timeTwo) / ONE_DAY;
if(delta == 0 || delta == 1) {
Calendar cal1 = new GregorianCalendar();
cal1.setTimeInMillis(timeOne);
Calendar cal2 = new GregorianCalendar();
cal2.setTimeInMillis(timeTwo);
long dayDiff = cal1.get(Calendar.DAY_OF_MONTH) - cal2.get(Calendar.DAY_OF_MONTH);
return dayDiff;
}
return delta;
}

Categories