Count occurrences of an approximate date in an entity - java

I need to count the points of a chart for a duration picked by an user.
My chart is about logs, we need to know how many users are connected for every specified minutes while a specific duration. We don't want to use too many queries, so I work essentially with lists.
Dates are stored in String format as "yyyy-MM-dd HH:mm:ss".
My code works but is really too long to load:
old=ofy().load().type(Log.class).filter("site in",selectedSites).filter("license in",ofy().load().type(License.class).filter("name", name)).filter("date_out >=",datemin).filter("date_out <=",datemax).list();
Duration duration = new Duration(firstIn, lastDateOut); //Duration between two dates choosen by the user
int dimension=(int) ((duration.getStandardMinutes())/divideBy); //Number of abscissa points in the chart
DateTime[] dates=new DateTime[dimension+1]; //Init of the dates
int[] counts=new int[dimension+1]; //Init of the count table (count of logged users at the date
DateTime transfert=firstIn; //First date
for(int i=0;i<=dimension;i++){
counts[i]=0;
dates[i]=transfert.minusSeconds(transfert.getSecondOfMinute());
transfert=transfert.plusMinutes(divideBy);
for(Log log:old){
if((StaticMethods.toDateTime(log.getDate_in()).minusSeconds(StaticMethods.toDateTime(log.getDate_in()).getSecondOfMinute()).equals(dates[i]))
||((StaticMethods.toDateTime(log.getDate_in()).minusSeconds(StaticMethods.toDateTime(log.getDate_in()).getSecondOfMinute()).isBefore(dates[i]))
&&(StaticMethods.toDateTime(log.getDate_out()).minusSeconds(StaticMethods.toDateTime(log.getDate_out()).getSecondOfMinute()).isAfter(dates[i])))
||(StaticMethods.toDateTime(log.getDate_out()).minusSeconds(StaticMethods.toDateTime(log.getDate_out()).getSecondOfMinute()).equals(dates[i]))
){
counts[i]++;
}
}
GraphData nw=new GraphData(dates[i].toDate(), counts[i]);
}
I want to know if there is a possible less loading time (have read this and I need to know if there's similar way for approximate values).

you should order your data by Date_out value first, in ascending order. Also you don't need tables for Dates and Counts, try the following instead
Duration duration = new Duration(firstIn, lastDateOut); //Duration between two dates choosen by the user
int dimension=(int) ((duration.getStandardMinutes())/divideBy); //Number of abscissa points in the chart
DateTime transfert=firstIn; //First date
DateTime currentDate=transfert; // X-Axis Date
int currentCount=0; // Y-Axis LoggedUser Count
//Log data
DateTime log_DateIn;
DateTime log_DateOut;
for(int i=0;i<=dimension;i++)
{
currentDate = transfert;
currentCount = 0;
transfert = transfert.plusMinutes(divideBy);
for(Log log:old)
{
// We store our dates into variables, that way we avoid doing the time conversion twice
log_DateIn = StaticMethods.toDateTime(log.getDate_in()).minusSeconds(StaticMethods.toDateTime(log.getDate_in()).getSecondOfMinute());
log_DateOut = StaticMethods.toDateTime(log.getDate_out()).minusSeconds(StaticMethods.toDateTime(log.getDate_out()).getSecondOfMinute());
// Since we made the list ordered by DateOut, we are sure that if the stored DateOut is greater than transfert we can't find another user, that way we can break the for without parsing each log
if(log_DateOut.isAfter(transfert))
break;
// Now we can do checks to see if we need to increase the count
// We just check if the DateIn is between the currentDate and currentDate + divideBy (transfert)
if(log_DateIn.isAfter(currentDate) && log_DateIn.isBefore(transfert))
currentCount++;
// Same thing for DateOut
else if(log_DateOut.isAfter(currentDate) && log_DateOut.isBefore(transfert))
currentCount++;
// Now we need both cases
else if(log_DateIn.isBefore(currentDate) && log_DateOut.isAfter(transfert))
currentCount++;
// Equalities
else if(log_DateIn.equals(currentDate) || log_DateIn.equals(transfert) || log_DateOut.equals(currentDate) || log_DateOut.equals(transfert))
currentCount++;
}
GraphData nw = new GraphData(currentDate, currentCount);
}

Related

Get total seconds hourly given a list of start time and end time

I have a list of start times and end times when the user is active on my app.
I have to calculate the total time in seconds that the user is active on my application and classify them hourly.
For example
start time: 28/06/2021 13:14:15, end time: 28/06/2021 15:12:09
start time: 28/06/2021 23:14:15, end time: 29/06/2021 01:12:09
start time: 28/06/2021 8:14:15, end time: 28/06/2021 9:12:09
start time: 28/06/2021 1:14:15, end time: 28/06/2021 1:16:09
For the above list, I would like to calculate the amount of time user has been active in total between 00-01, 01-02, 02-03 .... 23-00.
I have written following code:
for (Object object: objectList) {
if (object.getStartTime().equalsIgnoreCase(object.getEndTime())) continue;
String[] startTimeArray = object.getStartTime().split(" ")[1].split(":");
String[] endTimeArray = object.getEndTime().split(" ")[1].split(":");
int startHour = Integer.parseInt(startTimeArray[0]);
int endHour = Integer.parseInt(endTimeArray[0]);
if (startHour == endHour) {
// difference between two dates getTime gives you difference of time in milliseconds.
// dividing that by 1000 will give you difference in seconds.
hourlyUsageList[startHour] += (MyUtils.dateFormat.parse(object.getEndTime()).getTime() -
MyUtils.dateFormat.parse(object.getStartTime()).getTime()) / 1000;
} else {
int startMinute = Integer.parseInt(startTimeArray[1]);
int endMinute = Integer.parseInt(endTimeArray[1]);
int startSecond = Integer.parseInt(startTimeArray[2]);
int endSecond = Integer.parseInt(endTimeArray[2]);
hourlyUsageList[startHour] += (3600 - (startMinute * 60L) - startSecond);
hourlyUsageList[endHour] += ((endMinute * 60L) + endSecond);
if ((startHour + 1) == endHour) continue;
// All hours in between start and end hour have to be completely added to usage time.
for (int i = startHour + 1; (i % 24) != endHour; i++) {
hourlyUsageList[i] += 3600;
}
}
}
The above code is working as well. However, I would like to know if there is some better and clean code solution for the problem.
Any help is appreciated.
Let's assume you were about to use a java.time.LocalDateTime…
And let's say you would provide the hour slots as well as the usage times in form of pairs of LocalDateTimes.
You could create a method that calculates the seconds for a given slot like this:
public static long getSlotSeconds(LocalDateTime fromHourDateTime, LocalDateTime toHourDateTime,
LocalDateTime usageFromDateTime, LocalDateTime usageToDateTime) {
// define some date times as temp variables
LocalDateTime calculateFrom;
LocalDateTime calculateTo;
/*
* find out where the calculation has to begin:
* - usage start
* - slot start
* - skip this slot resp. return usage time of 0 seconds
*/
// if usage time start was before slot start
if (usageFromDateTime.isBefore(fromHourDateTime)) {
// begin calculation at the start of the slot.
calculateFrom = fromHourDateTime;
// if usage time started after slot end
} else if (usageFromDateTime.isAfter(toHourDateTime)) {
// you will directly know that no time was spent in this slot
return 0;
// and otherwise, usage start was within this slot, so
} else {
// begin calculation at the start of usage
calculateFrom = usageFromDateTime;
}
/*
* find out which end time to use:
* - usage end
* - slot end
*/
// if the usage ended before this slot did
if (usageToDateTime.isBefore(toHourDateTime)) {
// calculate until the end of usage
calculateTo = usageToDateTime;
// and if the slot ended before the usage
} else {
// calculate until the end of the slot
calculateTo = toHourDateTime;
}
// finally calculate the result in seconds and return it
return Duration.between(calculateFrom, calculateTo).toSeconds();
}
A possible usage of this could look as follows
public static void main(String[] args) {
// a single example usage time
String fromOne = "28/06/2021 13:14:15";
String toOne = "28/06/2021 15:12:09";
// define how to parse the input Strings
DateTimeFormatter parser = DateTimeFormatter.ofPattern("dd/MM/uuuu H:mm:ss");
// then parse them
LocalDateTime fromUsageDateTime = LocalDateTime.parse(fromOne, parser);
LocalDateTime toUsageDateTime = LocalDateTime.parse(toOne, parser);
// define the slot to be checked (here only one relevant for the example usage time)
LocalTime slotFrom = LocalTime.of(13, 0);
LocalTime slotTo = LocalTime.of(14, 0);
// then add the dates of the input, they are relevant for the calculation!
LocalDateTime slotFromDateTime = LocalDateTime.of(fromUsageDateTime.toLocalDate(),
slotFrom);
LocalDateTime slotToDateTime = LocalDateTime.of(toUsageDateTime.toLocalDate(),
slotTo);
// call the method and pass the arguments
long usageSecondsInSlot = getSlotSeconds(slotFromDateTime, slotToDateTime,
fromUsageDateTime, toUsageDateTime);
// print something that shows you the result and the base of calculation
System.out.println(String.format("User was using the app between %s and %s for %d seconds",
slotFromDateTime, slotToDateTime, usageSecondsInSlot));
}
The output produced by this example is
User was using the app between 2021-06-28T13:00 and 2021-06-28T14:00 for 2745 seconds
This is no out-of-the-box solution working exactly as you wish, but in includes all you need for a more readable way that doesn't need to split Strings or parse Integers.
The example method only handles a single hour slot and a single usage time.
You will have to make it work for Collections of LocalDateTimes or even some custom classes, like HourSlot and UsageTime yourself.

How to RESET Arraylist at the end of the week?

I have an arraylist:
ArrayList<String> wholeWeekArrayList = new ArrayList<>();
DatabaseHelper(SQLite) is storing the values into the(above) arrayList:
Cursor data = mDatabaseHelper.getData();
while (data.moveToNext() ) {
wholeWeekArrayListString.add(data.getString(1));
//getString(1) is column values from SQLite
}
Then I have SumofWeek where all the data in wholeWeekArrayListString is added together.
(I Convert wholeWeekArrayListString to double to view it in a TEXTVIEW);
I want this SumOfWeek to reset to Zero at the end of the week but the data inside the SQLite must keep adding(for SumOfMonth view).
So by Sunday the data may be $50.00 (for Example) and Starting on int Monday. the data must reset to 0.0 and sum all the way up until Sunday.
This must happen weekly.
How would u do this? I have tried assining days of weeks.
Monday =1;
Tuesday = 2;
Wednesday =3;
// ...
and iterate through the whole week but Im not able to get(i), which is the data of each single day of the week and then reset it on which is
int Sunday =7;
I have the total amount but dont know what method to use to reset the data at the end of the week?
Without changing the DB calls, you´ll have to store the timestamp of the latest reset (resetTimestamp in the example below). If the current time is in a different week, the code will trigger a reset of sumofWeek. After that, it´s your normal sumofWeek logic.
Thread safety: to be added depending on the application specifics.
private ArrayList<Long> sumofWeek = new ArrayList<>();
private Long resetTimestamp;
public void populateWeek() {
if(resetTimestamp == null || isDifferentWeek(resetTimestamp)) {
sumofWeek = new ArrayList<Long>();
for(int i = 0; i < 7; i++){
sumofWeek.add(0l);
}
System.out.println(sumofWeek);
resetTimestamp = java.lang.System.currentTimeMillis();
}
// populate sumofWeek here
}
private boolean isDifferentWeek(long resetTimestamp) {
Calendar cl1 = new GregorianCalendar();
cl1.setTimeInMillis(java.lang.System.currentTimeMillis());
Calendar cl2 = new GregorianCalendar();
cl2.setTimeInMillis(resetTimestamp);
return cl1.get(Calendar.WEEK_OF_YEAR) != cl2.get(Calendar.WEEK_OF_YEAR);
}

Iterator between two given hours

I was in a job interview and got this question: " Write a function that gets 2 strings s,t that represents 2 hours ( in format HH: MM: SS ). It's known that s is earlier than t.
The function needs to calculate how many hours between the two given hours contains at most 2 digits.
For example- s- 10:59:00, t- 11:00:59 -
Answer- 11:00:00, 11:00:01,11:00:10, 11:00:11.
I tried to do while loops and got really stuck. Unfortunately, I didn't pass the interview.
How can I go over all the hours (every second is a new time) between 2 given hours in java as explained above? Thanks a lot
Java 8 allows you to use LocalTime.
LocalTime time1 = LocalTime.parse(t1);
LocalTime time2 = LocalTime.parse(t2);
The logic would require you to count the amount of different digits in a LocalTime, something like
boolean isWinner(LocalTime current) {
String onlyDigits = DateTimeFormatter.ofPattern("HHmmss").format(current);
Set<Character> set = new HashSet<>();
for (int index = 0; index < onlyDigits.length(); index++) {
set.add(onlyDigits.charAt(index));
}
return set.size() <= 2;
}
You can loop between the times like this
int count = 0;
for (LocalTime current = time1; current.isBefore(time2); current = current.plusSeconds(1)) {
if (isWinner(current)) {
count++;
}
}
That's it.
The question is really more geared towards getting a feel of how you'd approach the problem, and if you know about LocalTime API etc.

Java : given a list of object that has range of dates find two objects whose end month is closest to current date month

List of dates are as below (The list can be in any order):
3-Jan to 31-Mar, 2-Apr to 30-Jun, 1-Jul to 30-Sep, 4-Oct to 31-Dec
Current Date is: 19-Feb
Can someone please help me with the logic?
My approach is:
if(the given date should be greater than start date and less than end date){//this gives current quarter}else if(difference of the month of current date from the end date of each object should be less than or equal to 5)
i am hard coding the condition less than 5, which may break if in future the range of date will be of 4 months
Second approach is:
we can sort the list in ascending order and can get the current quarter index by comparing with current date and the next quarter will be of next index. But the complexity will be more.
I tried below code, but it gives only current quarter date. I am not able to get next quarter considering there would be only 3 objects and current date month is feb.
public static List getCurrentQtrOffr(List detail,Date currentDate) throws ParseException{
int currentQuarter = 9999, diff1;
int nextquarter = 9999, diff2;
Detail detail1;
Detail detail2;
Detail detail3 = null;
Detail detail4 = null;
Iterator<Detail> iterator = detail.iterator();
List<Detail> list = new ArrayList<Detail>();
while(iterator.hasNext()){
detail1 = iterator.next();
diff1 = getDiff(currentDate,detail1.startTime());
if(diff1>0){
if(iterator.hasNext()){
detail2 = iterator.next();
}else{
detail2 = null;
}
if(detail2 != null){
diff2 = getDiff(currentDate,detail2.startTime());
if(diff1 < diff2 ){
if(currentQuarter > diff1){
nextquarter = currentQuarter;
currentQuarter = diff1;
//how to assign detail3 before updating it with next minimum value, as if there will be only 3 object and flow comes in this if block then detail4 will be null
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff1){
nextquarter = diff1;
detail4=detail1;
}
}else{
if(currentQuarter > diff2){
nextquarter = currentQuarter;
currentQuarter = diff2;
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff2){
nextquarter = diff2;
detail4=detail1;
}
}
}else{
if(currentQuarter > diff1){
nextquarter = currentQuarter;
currentQuarter = diff1;
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff1){
nextquarter = diff1;
detail4=detail1;
}
}
}else{
System.out.println("skipped "+diff1);
}
}
list.add(detail3);
list.add(detail4);
return list;
}
If the periods are mutually exclusive (not overlapping) the you simply check for the first occurrence where:
The target is equal to or later than the start, and…
The target is before the stop.
This logic follows the Half-Open approach commonly used in date-time work where the beginning is inclusive while the ending is exclusive.
A shorter way of saying "the target is equal to or later than the start" is "not before start". The exclamation mark ! means not in Java syntax.
Boolean periodContainsTarget = ( ! target.isBefore( start ) ) && target.isBefore( stop ) ;
The above logic would be used with LocalDate if you meant date with a year. If you literally meant a month and day without a year, use the MonthDay class. The logic works for both.
Use Period class to represent the span of time between a pair of LocalDate objects. See Tutorial.
You might also find useful the Interval class in the ThreeTen-Extra project that supplements java.time.

Java Apache POI -- Creating an iterator to find a date

I am attempting to find the cell reference for a specific date in an Excel file. The Excel is set up so that the "Date" header is in A1, and dates are included across the same row in B1, C1, etc.
I attempted to create an iterator to go through these dates and compare them to an input date.
I omitted some code below for conciseness.
public static void main(String[] args) throws IOException, ParseException {
SimpleDateFormat formatter ;
formatter = new SimpleDateFormat("MM/dd/yyyy");
Date date = formatter.parse(args[0]);
// ............
// iterator to find date
int dateRef = 0; //logs column of date
Date tempDate = null;
// while loop to check the date contents of each cell
while (dateRef < 1000) { // random number inserted
dateRef++;
tempDate = cell.getDateCellValue();
if (date == tempDate) {
break; //beaks if contents are equal
}
cell = results.getRow(0).getCell(dateRef); // else continue and iterate one cell
}
}
When I run this, the iterator keeps going right up to column 1000. I checked this with print statements. Even though the cell is landing on the correct date, it does not recognize the input date and the cell date value as the same, and therefore does not break.
I know this may not be the most efficient way of doing things, so if you have more suggestions, let me know about them. Thank you!
You should not use the == operator in this case. I would try with equals or compareTo in your case in order to find the proper date.
See the Question: What is the difference between == vs equals() in Java?

Categories

Resources