Summing durations using Joda Time - java

I am trying to sum durations in the following format: "hh:mm:ss" (e.g.: "08:55:12") using Joda Time:
PeriodFormatter formatter = new PeriodFormatterBuilder()
.printZeroAlways().minimumPrintedDigits(2).appendHours()
.appendLiteral(":").printZeroAlways().printZeroAlways()
.minimumPrintedDigits(2).appendMinutes().appendLiteral(":")
.printZeroAlways().minimumPrintedDigits(2).appendSeconds()
.toFormatter();
Duration totalTime = Duration.ZERO;
for (Entry entry : entries) {
Period period = formatter.parsePeriod(entry.getTime());
Duration duration = period.toStandardDuration();
totalTime = totalTime.plus(duration);
}
Period totalPeriod = totalTime.toPeriod();
if (totalPeriod.getHours() < 10) {
hours = "0" + totalPeriod.getHours();
} else {
hours = Integer.toString(totalPeriod.getHours());
}
mTextView.setTextView(hours
+ String.format("%02d:%02d", totalPeriod.getMinutes(),
totalPeriod.getSeconds()));
For some reason, it is giving me wrong results (summed durations is way too long). Can you help me find the cause of this problem?

I think you have just forgotten a colon between hour-part and minute part causing the total sum looking like 2701:44 instead of 27:01:44 (this is an example for the sum of the three elements "03:20:45", "00:40:11", "23:00:48" which is correctly calculated by Joda-Time).
So your solution should finally look like:
String output =
hours + String.format(":%02d:%02d", totalPeriod.getMinutes(), totalPeriod.getSeconds());
System.out.println(output); // 27:01:44
But easier is just to reuse your formatter object for printing:
System.out.println(formatter.print(totalPeriod)); // 27:01:44
If you are interested in a pattern-based solution then check out my library Time4J with this example:
// input
String[] periods = { "03:20:45", "00:40:11", "23:00:48" };
// initialization
Duration.Formatter<ClockUnit> timeFormat =
Duration.Formatter.ofPattern(ClockUnit.class, "hh:mm:ss");
Duration<ClockUnit> dur = Duration.ofZero();
// calculate the sum
for (String entry : periods) {
dur = dur.plus(timeFormat.parse(entry));
}
dur = dur.with(Duration.STD_CLOCK_PERIOD); // normalization
System.out.println(timeFormat.format(dur)); // 27:01:44

Related

How to return sum of LocalTime in Java

It wont get the minutes. i need to return minutes.
How to return sum of minutes while iterating over Localtime in Java?
public String userLunchHoursSum(String username) {
List<WorkHour> workHours = workHourRepository.findWorkHoursByUsername(username);
System.out.println(Arrays.toString(workHours.toArray()));
long diff = 0;
LocalTime lunchTime;
long minutes = 0;
LocalTime plusMinutes = null;
for (WorkHour workHour : workHours) {
lunchTime = workHour.getLunch_time().toLocalTime(); //00:30:00
plusMinutes = lunchTime.plusMinutes(lunchTime.getMinute());
}
if(workHours.size()!= 0) {
return Long.toString(plusMinutes.getMinute());
}
return "00:00";
}
getLunch_time returns java.sql.Time.
As mentioned, you should be storing duration instead of localtime. If this is something you have no control over, consider migrating the database or creating a intermediate parsing function. Example code that I have not run, because I don't know what is in WorkHour.
// leave the string formatting to other functions
public long userLunchHoursSum(String username) {
List<WorkHour> workHours = workHourRepository.findWorkHoursByUsername(username);
Duration totalDuration = Duration.ZERO;
for (WorkHour workHour : workHours) {
// save your time in the appropriate format beforehand
// do not use local time to store duration.
Duration lunchTime = Duration.between(LocalTime.MIDNIGHT, workHour.getLunch_time().toLocalTime()); //00:30:00
totalDuration = totalDuration.plus(lunchTime);
}
return totalDuration.toMinutes();
}

Biweekly/google-rfc-2445 RRule different behaviour based on start date

Different behaviour of RRULE based on start time :
Hi, I am currently trying to write a cron to rrule convertor and encountered some issues with some particular rules.
For the following rule :
"FREQ=YEARLY;BYMONTH=1,2,3,4,5,6,7,8,9,10,11,12;BYMONTHDAY=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;BYDAY=SU,MO,TU,WE,TH,FR,SA;BYHOUR=0,10,20;BYMINUTE=0"
The behaviour of the dates iterator iss different depending on what the start time specified is :
final String rule2 = "FREQ=YEARLY;BYMONTH=1,2,3,4,5,6,7,8,9,10,11,12;BYMONTHDAY=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;BYDAY=SU,MO,TU,WE,TH,FR,SA;BYHOUR=0,10,20;BYMINUTE=0";
final Date startDate = new SimpleDateFormat("yyyy-MM-dd").parse("2019-10-01");
final Date startDate2 = new SimpleDateFormat("yyyy-MM-dd").parse("2019-12-01");
System.out.println("Biweekly Rule Date 1");
final List<Date> biweeklyStartDate1 = biweeklyDates(rule2, startDate, 100);
System.out.println("Biweekly Rule Date 1 Result Count " + biweeklyStartDate1.size());
System.out.println("Biweekly Rule Date 2");
final List<Date> biweeklyStartDate2 = biweeklyDates(rule2, startDate2, 100);
System.out.println("Biweekly Rule Date 2 Result Count " + biweeklyStartDate2.size());
private static List<Date> biweeklyDates(final String rule, final Date date, final int limit) {
final RecurrenceRuleScribe scribe = new RecurrenceRuleScribe();
final ParseContext context = new ParseContext();
context.setVersion(ICalVersion.V2_0);
final RecurrenceRule recurrenceRule = scribe.parseText("RRULE:" + rule,null, new ICalParameters(), context);
final DateIterator iterator = recurrenceRule.getDateIterator(date, TimeZone.getTimeZone("GMT"));
final List<Date> values = new ArrayList<>();
while (iterator.hasNext()) {
final Date next = iterator.next();
values.add(next);
System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(next));
if (values.size() >= limit) {
break;
}
}
return values;
}
In this example I try to retrieve a 100 occurences using the same rule. The occurences returned differ based on start time specified.
The first date would return the expected 100 results, the second one would return a single invalid occurence, which seem to be the start date.
It seems to be caused by last month of the year, whn specifying another date with December, the same return seems to be returned.
Google-rfc-2445 has the same behaviour but ical4j and some other rrule evaluators from other languages were able to produce the expected results.

Android: get UsageStats per hour

I use UsageStats feature of Android, but the smallest interval is DAILY INTERVAL.
long time = System.currentTimeMillis();
List<UsageStats> appList = manager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - DAY_IN_MILLI_SECONDS, time);
How can I get UsageStats in an hourly interval?
All credit goes to this answer. I have learned from that one.
How can we collect app usage data for customized time range (e.g. for per 1 hour)?
We have to call queryEvents(long begin_time, long end_time) method as it will provide us all data starting from begin_time to end_time. It give us each app data through foreground and background events instead of total spent time like queryUsageStats() method. So, using foreground and background events time stamp, we can count the number of times an app has been launched and also can find out the usage duration for each app.
Implementation to Collect Last 1 Hour App Usage Data
At first, add the following line in the AndroidManifest.xml file and also request user to get permission of usage access.
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
Add the following lines inside any method
long hour_in_mil = 1000*60*60; // In Milliseconds
long end_time = System.currentTimeMillis();
long start_time = end_time - hour_in_mil;
Then, call the method getUsageStatistics()
getUsageStatistics(start_time, end_time);
getUsageStatistics methiod
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
void getUsageStatistics(long start_time, long end_time) {
UsageEvents.Event currentEvent;
// List<UsageEvents.Event> allEvents = new ArrayList<>();
HashMap<String, AppUsageInfo> map = new HashMap<>();
HashMap<String, List<UsageEvents.Event>> sameEvents = new HashMap<>();
UsageStatsManager mUsageStatsManager = (UsageStatsManager)
context.getSystemService(Context.USAGE_STATS_SERVICE);
if (mUsageStatsManager != null) {
// Get all apps data from starting time to end time
UsageEvents usageEvents = mUsageStatsManager.queryEvents(start_time, end_time);
// Put these data into the map
while (usageEvents.hasNextEvent()) {
currentEvent = new UsageEvents.Event();
usageEvents.getNextEvent(currentEvent);
if (currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED ||
currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_PAUSED) {
// allEvents.add(currentEvent);
String key = currentEvent.getPackageName();
if (map.get(key) == null) {
map.put(key, new AppUsageInfo(key));
sameEvents.put(key,new ArrayList<UsageEvents.Event>());
}
sameEvents.get(key).add(currentEvent);
}
}
// Traverse through each app data which is grouped together and count launch, calculate duration
for (Map.Entry<String,List<UsageEvents.Event>> entry : sameEvents.entrySet()) {
int totalEvents = entry.getValue().size();
if (totalEvents > 1) {
for (int i = 0; i < totalEvents - 1; i++) {
UsageEvents.Event E0 = entry.getValue().get(i);
UsageEvents.Event E1 = entry.getValue().get(i + 1);
if (E1.getEventType() == 1 || E0.getEventType() == 1) {
map.get(E1.getPackageName()).launchCount++;
}
if (E0.getEventType() == 1 && E1.getEventType() == 2) {
long diff = E1.getTimeStamp() - E0.getTimeStamp();
map.get(E0.getPackageName()).timeInForeground += diff;
}
}
}
// If First eventtype is ACTIVITY_PAUSED then added the difference of start_time and Event occuring time because the application is already running.
if (entry.getValue().get(0).getEventType() == 2) {
long diff = entry.getValue().get(0).getTimeStamp() - start_time;
map.get(entry.getValue().get(0).getPackageName()).timeInForeground += diff;
}
// If Last eventtype is ACTIVITY_RESUMED then added the difference of end_time and Event occuring time because the application is still running .
if (entry.getValue().get(totalEvents - 1).getEventType() == 1) {
long diff = end_time - entry.getValue().get(totalEvents - 1).getTimeStamp();
map.get(entry.getValue().get(totalEvents - 1).getPackageName()).timeInForeground += diff;
}
}
smallInfoList = new ArrayList<>(map.values());
// Concatenating data to show in a text view. You may do according to your requirement
for (AppUsageInfo appUsageInfo : smallInfoList)
{
// Do according to your requirement
strMsg = strMsg.concat(appUsageInfo.packageName + " : " + appUsageInfo.launchCount + "\n\n");
}
TextView tvMsg = findViewById(R.id.MA_TvMsg);
tvMsg.setText(strMsg);
} else {
Toast.makeText(context, "Sorry...", Toast.LENGTH_SHORT).show();
}
}
AppUsageInfo.class
import android.graphics.drawable.Drawable;
class AppUsageInfo {
Drawable appIcon; // You may add get this usage data also, if you wish.
String appName, packageName;
long timeInForeground;
int launchCount;
AppUsageInfo(String pName) {
this.packageName=pName;
}
}
How can I customize these codes to collect per 1 hour data?
As you want to get per hour data, please change the end_time and start_time value for every hour data. For instance: If I would try to collect past per hour data (for past 2 hour data). I would do the following thing.
long end_time = System.currentTimeMillis();
long start_time = end_time - (1000*60*60);
getUsageStatistics(start_time, end_time);
end_time = start_time;
start_time = start_time - hour_in_mil;
getUsageStatistics(start_time, end_time);
However, you may use a Handler to skip repeatedly writing start_time and end_time to change value of these variables. Each time data will be collected for one hour, a task will be completed and after automatically changing the values of the variables, you will again call the getUsageStatistics method.
Note: Maybe, you will not be able to retrieve data for more than past 7.5 days as events are only kept by the system for a few days.
Calendar cal = (Calendar) Calendar.getInstance().clone();
//I used this and it worked, only for 7 days and a half ago
if (daysAgo == 0) {
//Today - I only count from 00h00m00s today to present
end = cal.getTimeInMillis();
start = LocalDate.now().toDateTimeAtStartOfDay().toInstant().getMillis();
} else {
long todayStartOfDayTimeStamp = LocalDate.now().toDateTimeAtStartOfDay().toInstant().getMillis();
if (mDaysAgo == -6) {
//6 days ago, only get events in time -7 days to -7.5 days
cal.setTimeInMillis(System.currentTimeMillis());
cal.add(Calendar.DATE, daysAgo + 1);
end = cal .getTimeInMillis();
start = end - 43200000;
} else {
//get events from 00h00m00s to 23h59m59s
//Current calendar point to 0h0m today
cal.setTimeInMillis(todayStartOfDayTimeStamp);
cal.add(Calendar.DATE, daysAgo + 1);
end = calendar.getTimeInMillis();
cal.add(Calendar.DATE, -1);
start = calendar.getTimeInMillis();
}
}
I don't think it's possible, even if you ask for data in the middle of an interval, it looks like the data is stored in buckets and the minimum bucket is a day.
In UsageStatsManager documentation, it says:
A request for data in the middle of a time interval will include that interval.
Also, INTERVAL_BEST is not a real interval, it just selects one of the available intervals for the given time range. In
UsageStatsManager.java source code, it says:
/**
* The number of available intervals. Does not include {#link #INTERVAL_BEST}, since it
* is a pseudo interval (it actually selects a real interval).
* {#hide}
*/
public static final int INTERVAL_COUNT = 4;
Yes, Android is providing minimum INTERVAL_DAILY. But for the best result, you can use INTERVAL_BEST. Android is giving the best interval timer for the given time range in queryUsageStats(int, long, long).
Happy coding...

java code to store milliseconds into an array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have a table in which I've assigned burst time for each of machines in the form of time type in second for eg: 00:00:03, 00:00:02 etc.
I have a JAVA code that retrieves these burst times from the database and store it in a list and then convert each burst time into "milliseconds" type.
ArrayList<String>list22=new ArrayList<String>();
ResultSet rs = stmt1
.executeQuery("SELECT burst_time FROM virtual_machine WHERE VM_id <= 4");
while (rs.next()) {
list22.add(rs.getString("burst_time"));
}
String tempStamp = list22.get(0);
int i;
for(i=0;i<=list22.size()-1;i++){
System.out.println(list22.get(i));
}
for(String startstamp : list22){
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
java.util.Date d = null;
try
{
d = formatter.parse(startstamp);}
catch (java.text.ParseException e) {
System.err.println("Error: " + e.getMessage());
}
long qtm= d.getTime();
System.out.println(qtm);
}
This gives me the following result:
00:00:03
00:00:02
00:00:02
00:00:03
3000
2000
2000
3000
Now I need to store those milliseconds values in an array bur[] and use it in the program so that the corresponding machines should run for the assigned time which is stored in the array.
And can u please tell me whether I'm going through the right path in case of storing the milliseconds in array and giving it to the machines.
Following solution is nearly identical to the answer of #nikis, but preserves the important timezone setting. Otherwise users will get a surprising experience if this code runs in UK (Europe/London) because in year 1970 there was summer time - resulting in duration longs with one full hour too much:
long[] bur = new long[list22.size()];
for(int i=0; i < list22.size(); i++) {
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
// important, but avoid deprecated Etc/GMT-notation
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
try
{
java.util.Date d = formatter.parse(list22.get(i));
long qtm= d.getTime();
bur[i] = qtm;
System.out.println(qtm);
} catch (java.text.ParseException e) {
System.err.println("Error: " + e.getMessage());
}
}
Hereby I have presented a workaround for an unsupported handling of durations in JDK pre 8. The truth is that SimpleDateFormat is designed to parse points in time, but not durations. Therefore it is so important to have a fixed starting point which never changes, hence the choice of UTC time zone and the reference point 1970-01-01T00:00:00,000Z (elapsed milliseconds since UNIX epoch).
JodaTime offers a specialized PeriodFormatter which really yields a org.joda.time.Period. Else it is possible to write your own specialized string parser (by help of substring(), indexOf() etc.) to factor out the integer parts and then to use Integer.valueOf(String) and then to calculate a long using this simple formula: (hour * 3600 + minute * 60 + second) * 1000.
I've modified your code to avoid NPE and also added bur[] array:
ArrayList<String>list22=new ArrayList<String>();
ResultSet rs = stmt1
.executeQuery("SELECT burst_time FROM virtual_machine WHERE VM_id <= 4");
while (rs.next()) {
list22.add(rs.getString("burst_time"));
}
for(int i=0;i<list22.size();i++){
System.out.println(list22.get(i));
}
long[] bur = new long[list22.size()];
for(int i=0;i<list22.size();i++){
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
try
{
java.util.Date d = formatter.parse(list22.get(i));
long qtm= d.getTime();
bur[i] = qtm;
System.out.println(qtm);
} catch (java.text.ParseException e) {
System.err.println("Error: " + e.getMessage());
}
}
Try this:
int bur[] = new int[list22.size()];
for(int i = 0; i < list22.size(); i++) {
String timeStamp = list22.get(i);
String s, m, h, split;
split = timeStamp.split(":");
h = split[0];
m = split[1];
s = split[2];
bur[i] = Integer.parseInt(s) * 1000 + Integer.parseInt(m) * 60000 + Integer.parseInt(h) * 3600000;
}
This solution doesn't use any date objects, since you won't need them in your case, if I'm not totally on the wrong way ;-)

java code to use timestamp items inside a loop

ResultSet rs2 = stmt2.executeQuery("SELECT starttime FROM user_req ORDER BY req_id ASC LIMIT 1");
Timestamp a;
while (rs2.next()) {
a = rs2.getTimestamp("starttime");
System.out.println(a);
long t=a.getTime();
long m=5*60*1000;
Timestamp b= new Timestamp(t+m);
System.out.println(b);
}
This code produces two timestamps: 2013-12-12 09:00:00 and 2013-12-12 09:05:00.
In this code I get two timestamp items one with adding 5 min to the previous one, can anyone pls help me out in how to put it in a for loop such that it should start wd the "timestamp a" till "timestamp b" and it should increment with 1 minute, so that I can perform roundrobin code in it. please help me how to iterate over the timestamps.
Simply:
for(long current = a ; current <= a+5*60*1000 ; current += 60*1000) {
// do something with current
}
You can use :
long starTime=a.getTime();
long endTime=starTime+5*60*1000;
for (long currTime = starTime; currTime < endTime; currTime += 60*1000) {
// Do your stuff, currTime will increment in 1 minute steps
}

Categories

Resources