Ical4j. RFC5545. Calculate event occurrences, duration hack - java

I check ical4j library. At time I need calculate event occurrences. Useful example to calculate is here. I try to shift start date and end date. In original start date is 20101113 - 2010 November, Saturday (it maps on pattern see BYDAY=...SA). I want do not care if start match or not. So I used start date with value 20101112 - 2010 November, Friday (it doesn't map on any day in pattern see BYDAY=MO,TU,SA)
VEvent event = new ContentBuilder().vevent {
dtstart('20101112', parameters: parameters() {value('DATE')})
dtend('20101113', parameters: parameters() {value('DATE')})
rrule('FREQ=WEEKLY;WKST=MO;INTERVAL=3;BYDAY=MO,TU,SA')
}
def dates = event.calculateRecurrenceSet(new Period('20101101T000000/20110101T000000'))
println dates
result is
[20101112T000000Z/20101113T000000Z, 20101113T000000Z/P1D, 20101129T000000Z/P1D, 20101130T000000Z/P1D, 20101204T000000Z/P1D, 20101220T000000Z/P1D, 20101221T000000Z/P1D, 20101225T000000Z/P1D]
almost as expected (except first period in result 20101112T000000Z/20101113T000000Z is redundant). So I continue investigate how to exclude one. In debug mode I see
result = {PeriodList#1497} size = 8
0 = {Period#2240} "20101112T000000Z/20101113T000000Z"
duration = null
rangeStart = {DateTime#2243} "20101112T000000Z"
rangeEnd = {DateTime#2244} "20101113T000000Z"
1 = {Period#2264} "20101113T000000Z/P1D"
duration = {Dur#2284} "P1D"
rangeStart = {DateTime#2285} "20101113T000000Z"
rangeEnd = {DateTime#2286} "20101114T000000Z"
2 = {Period#2265} "20101129T000000Z/P1D"
duration = {Dur#2284} "P1D"
rangeStart = {DateTime#2290} "20101129T000000Z"
rangeEnd = {DateTime#2291} "20101130T000000Z"
3 = {Period#2266} "20101130T000000Z/P1D"
duration = {Dur#2284} "P1D"
rangeStart = {DateTime#2295} "20101130T000000Z"
rangeEnd = {DateTime#2296} "20101201T000000Z"
4 = {Period#2267} "20101204T000000Z/P1D"
duration = {Dur#2284} "P1D"
rangeStart = {DateTime#2300} "20101204T000000Z"
rangeEnd = {DateTime#2301} "20101205T000000Z"
5 = {Period#2268} "20101220T000000Z/P1D"
duration = {Dur#2284} "P1D"
rangeStart = {DateTime#2315} "20101220T000000Z"
rangeEnd = {DateTime#2316} "20101221T000000Z"
6 = {Period#2269} "20101221T000000Z/P1D"
duration = {Dur#2284} "P1D"
rangeStart = {DateTime#2310} "20101221T000000Z"
rangeEnd = {DateTime#2311} "20101222T000000Z"
7 = {Period#2270} "20101225T000000Z/P1D"
duration = {Dur#2284} "P1D"
rangeStart = {DateTime#2305} "20101225T000000Z"
rangeEnd = {DateTime#2306} "20101226T000000Z"
Eureka! I've found marker to detect redundant dates in generated set (corrupted period has null duration). I continue handling it filtering periods with null value. But filter have filtered nothing. Continue checking...
package net.fortuna.ical4j.model;
...
public class Period extends DateRange implements Comparable<Period> {
private static final long serialVersionUID = 7321090422911676490L;
private Dur duration;
...
public final Dur getDuration() {
if (duration == null) {
return new Dur(getStart(), getEnd());
}
return duration;
}
...
as you can see, class Period has private Dur duration and public final Dur getDuration(). I can't access duration without workaround...
Question is
How should I do?
Use reflection hack to get duration - ugly solution.
Download library sources to change Period class and rebuild library - follows bad support new library versions.
Ask to ical4j developers to expand Period facade - it needs time to change and for release.
Use duration hack over toString (it's unreliable solution).

I've raised issue. I'will add details if they consider the issue.

Related

.toNanos() method does not work correctly

I tried to make a method that will give me an idea of how much time it takes to my programs to run, and for an unknown reason, I can not get the nanoseconds.
I tried to read about the below classes but could not find out what I am doing wrong:
import java.time.Duration;
import java.time.Instant;
The methods:
public static String calcExecutionTime(Instant startTime, Instant endTime) {
if ((Duration.between(startTime, endTime).toNanos()) < 1000000) {
return Duration.between(startTime, endTime).toNanos() + " nanoseconds.";
} else if ((Duration.between(startTime, endTime).toMillis()) < 1000) {
return Duration.between(startTime, endTime).toMillis() + " milliseconds.";
} else if ((Duration.between(startTime, endTime).toSeconds()) < 100) {
return Duration.between(startTime, endTime).toSeconds() + " seconds.";
} else if ((Duration.between(startTime, endTime).toMinutes()) < 60) {
return Duration.between(startTime, endTime).toMinutes() + " minutes.";
} else {
return Duration.between(startTime, endTime).toHours() + " hoursm.";
}
}
Main here:
Instant instantStart = Instant.now();
Instant instantEnd = Instant.now();
System.out.print("Execution time for this program: " + calcExecutionTime(instantStart, instantEnd));
If I use the old System.nanoTime(); I get a result of 300-400 nanoseconds but with toNanos() I get 0 in this same situation.
Edit:
I do not use getNano() I use toNanos()
I would go with #Pshemo's comment about Instant.now().
https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html#now-- :
This will query the system UTC clock to obtain the current instant.
Where the link leads to:
This may use System.currentTimeMillis(), or a higher resolution clock if one is available.
So it may or may not have a higher precision than milliseconds. In your case the "may not have" seems to apply.

TWSz Java API Set duration

When I try set duration using this code:
Job job = new Job();
job.setName("5");
long dur = 1000;
job.setEstimatedDuration(1000);
job.setPriority(-1);
ZOSJobDefinition jobDef = new ZOSJobDefinition();
jobDef.setFlowTargetKey(new FlowTargetKey("CPU1"));
jobDef.setTaskType(TaskTypes.ZOS_JOB_TASK);
jobDef.setJclName("DMSORT");
job.setJobDefinition(jobDef);
I get error EQQX489E THE DURATION OF OPERATION CPU1 5 IS INVALID, 0 SEC*100.
I do it in the same way like in the documentation, however, I try also:
long dur = Long.valueOf(1000);
job.setEstimatedDuration(dur);
and
long dur = 1000L;
job.setEstimatedDuration(dur);
but I still get the same error.
There is wrong example in documentation. Solution is:
Job job = new Job();
job.setName("5");
job.setPriority(1);
**//job.setEstimatedDuration(1000);**
ZOSJobDefinition jobDef = new ZOSJobDefinition();
jobDef.setFlowTargetKey(new FlowTargetKey("CPU1"));
jobDef.setTaskType(TaskTypes.ZOS_JOB_TASK);
jobDef.setJclName("DMSORT");
**jobDef.setNormalElapsedTime(1000L);**
job.setJobDefinition(jobDef);

How to obtain , record and duration of app usage in minutes , seconds or hours

I have block of code that allows me to retreive all the apps/services running on my android device including the app that I
am building. I am not entirely sure if I am on the right path butbecause I am debugging on android 4.3 I would like to use ActivityManager.RunningService.activeSince
(per service/app) and subtract it from SystemClock.elapsedRealtime(); which I understand is total milliseconds since reboot . So for example
if the device was rebboted at 10am and whatsapp was started at 10:15 and the current time is 1030 I want to be able to use these values
to get an a close estimate of the amount spent on whatsapp. I have a feeling that this is not the most elegant way to achieve this and I am therefore very open to
any advice. This my code below thus far . For now I am using android 4.3
ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(Integer.MAX_VALUE);
for (ActivityManager.RunningServiceInfo info : services) {
cal.setTimeInMillis(currentMillis-info.activeSince);
long millisSinceBoot = SystemClock.elapsedRealtime();
long appStartTime = info.activeSince;
long appDuration = appStartTime - millisSinceBoot ;
//long time = ((millisSinceBoot - values.get(position).activeSince)/1000);
//long time = ((millisSinceBoot - currentMillis-info.activeSince)/1000);
//Log.i("HRHHRHRHRHR", "%%%%%%%%%%%%%%%%"+time);
//String time1 = String.valueOf(time);
int seconds = (int) (appDuration / 1000) % 60 ;
int minutes = (int) ((appDuration / (1000*60)) % 60);
int hours = (int) ((appDuration / (1000*60*60)) % 24);
String time11 = hours+":"+minutes+":"+seconds;
Log.i("Time", "Secs:- " + seconds + " " + "Mins:- " + minutes + " " + "Hours:- " + hours);
Log.i(TAG, String.format("Process %s with component %s has been running since %s (%d milliseconds)",
info.process, info.service.getClassName(), cal.getTime().toString(), info.activeSince ));
}

localized duration format for french

What is the Python analog of Time4J's code example:
// duration in seconds normalized to hours, minutes and seconds
Duration<?> dur = Duration.of(337540, ClockUnit.SECONDS).with(Duration.STD_CLOCK_PERIOD);
// custom duration format => hh:mm:ss
String s1 = Duration.Formatter.ofPattern("hh:mm:ss").format(dur);
System.out.println(s1); // output: 93:45:40
// localized duration format for french
String s2 = PrettyTime.of(Locale.FRANCE).print(dur, TextWidth.WIDE);
System.out.println(s2); // output: 93 heures, 45 minutes et 40 secondes
It is easy to get 93:45:40:
#!/usr/bin/env python3
from datetime import timedelta
dur = timedelta(seconds=337540)
print(dur) # -> 3 days, 21:45:40
fields = {}
fields['hours'], seconds = divmod(dur // timedelta(seconds=1), 3600)
fields['minutes'], fields['seconds'] = divmod(seconds, 60)
print("%(hours)02d:%(minutes)02d:%(seconds)02d" % fields) # -> 93:45:40
but how do I emulate PrettyTime.of(Locale.FRANCE).print(dur, TextWidth.WIDE) Java code in Python (without hardcoding the units)?
babel module allows to get close to desired output:
from babel.dates import format_timedelta # $ pip install babel
print(", ".join(format_timedelta(timedelta(**{unit: fields[unit]}),
granularity=unit.rstrip('s'),
threshold=fields[unit] + 1,
locale='fr')
for unit in "hours minutes seconds".split()))
# -> 93 heures, 45 minutes, 40 secondes
It handles locale and plural forms automatically e.g., for dur = timedelta(seconds=1) it produces:
0 heure, 0 minute, 1 seconde
Perhaps a better solution would be to translate the format string manually using standard tools such as gettext.
If you're using Kotlin, I just came across a similar problem with the Kotlin Duration type with localized formatting and because I couldn't find a good solution, I wrote one myself. It is based on APIs provided starting in Android 9 (for localized units), but with a fallback to English units for lower Android versions so it can be used with lower targeting apps.
Here's how it looks like on the usage side (see Kotlin Duration type to understand 1st line):
val duration = 5.days.plus(3.hours).plus(2.minutes).plus(214.milliseconds)
DurationFormat().format(duration) // "5day 3hour 2min"
DurationFormat(Locale.GERMANY).format(duration) // "5T 3Std. 2Min."
DurationFormat(Locale.forLanguageTag("ar").format(duration) // "٥يوم ٣ساعة ٢د"
DurationFormat().format(duration, smallestUnit = DurationFormat.Unit.HOUR) // "5day 3hour"
DurationFormat().format(15.minutes) // "15min"
DurationFormat().format(0.hours) // "0sec"
As you can see, you can specify a custom locale to the DurationFormat type. By default it uses Locale.getDefault(). Languages that have different symbols for number than romanic are also supported (via NumberFormat). Also, you can specify a custom smallestUnit, by default it is set to SECOND, so milliseconds will not be shown. Note that any unit with a value of 0 will be ignored and if the entire number is 0, the smallest unit will be used with the value 0.
This is the full DurationFormat type, feel free to copy (also available as a GitHub gist incl. unit tests):
import android.icu.text.MeasureFormat
import android.icu.text.NumberFormat
import android.icu.util.MeasureUnit
import android.os.Build
import java.util.Locale
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
import kotlin.time.days
import kotlin.time.hours
import kotlin.time.milliseconds
import kotlin.time.minutes
import kotlin.time.seconds
#ExperimentalTime
data class DurationFormat(val locale: Locale = Locale.getDefault()) {
enum class Unit {
DAY, HOUR, MINUTE, SECOND, MILLISECOND
}
fun format(duration: kotlin.time.Duration, smallestUnit: Unit = Unit.SECOND): String {
var formattedStringComponents = mutableListOf<String>()
var remainder = duration
for (unit in Unit.values()) {
val component = calculateComponent(unit, remainder)
remainder = when (unit) {
Unit.DAY -> remainder - component.days
Unit.HOUR -> remainder - component.hours
Unit.MINUTE -> remainder - component.minutes
Unit.SECOND -> remainder - component.seconds
Unit.MILLISECOND -> remainder - component.milliseconds
}
val unitDisplayName = unitDisplayName(unit)
if (component > 0) {
val formattedComponent = NumberFormat.getInstance(locale).format(component)
formattedStringComponents.add("$formattedComponent$unitDisplayName")
}
if (unit == smallestUnit) {
val formattedZero = NumberFormat.getInstance(locale).format(0)
if (formattedStringComponents.isEmpty()) formattedStringComponents.add("$formattedZero$unitDisplayName")
break
}
}
return formattedStringComponents.joinToString(" ")
}
private fun calculateComponent(unit: Unit, remainder: Duration) = when (unit) {
Unit.DAY -> remainder.inDays.toLong()
Unit.HOUR -> remainder.inHours.toLong()
Unit.MINUTE -> remainder.inMinutes.toLong()
Unit.SECOND -> remainder.inSeconds.toLong()
Unit.MILLISECOND -> remainder.inMilliseconds.toLong()
}
private fun unitDisplayName(unit: Unit) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val measureFormat = MeasureFormat.getInstance(locale, MeasureFormat.FormatWidth.NARROW)
when (unit) {
DurationFormat.Unit.DAY -> measureFormat.getUnitDisplayName(MeasureUnit.DAY)
DurationFormat.Unit.HOUR -> measureFormat.getUnitDisplayName(MeasureUnit.HOUR)
DurationFormat.Unit.MINUTE -> measureFormat.getUnitDisplayName(MeasureUnit.MINUTE)
DurationFormat.Unit.SECOND -> measureFormat.getUnitDisplayName(MeasureUnit.SECOND)
DurationFormat.Unit.MILLISECOND -> measureFormat.getUnitDisplayName(MeasureUnit.MILLISECOND)
}
} else {
when (unit) {
Unit.DAY -> "day"
Unit.HOUR -> "hour"
Unit.MINUTE -> "min"
Unit.SECOND -> "sec"
Unit.MILLISECOND -> "msec"
}
}
}
This humanize package may help. It has a french localization, or you can add your own. For python 2.7 and 3.3.
Using pendulum module:
>>> import pendulum
>>> it = pendulum.interval(seconds=337540)
>>> it.in_words(locale='fr_FR')
'3 jours 21 heures 45 minutes 40 secondes'

Convert seconds to W,D,H,M format in JAVA

I have time in seconds i want to convert it into a format like 6w 3d 9h 5m . Can someone please provide a method which can do this task. Thanks :)
w=weeks
d=days
h=hours
m=minutes
I have tried the below code but i dont get weeks using
int day = (int)TimeUnit.SECONDS.toDays(seconds);
long hours = TimeUnit.SECONDS.toHours(seconds) - TimeUnit.SECONDS.toHours(TimeUnit.SECONDS.toDays(seconds));
long minute = TimeUnit.SECONDS.toMinutes(seconds) - TimeUnit.SECONDS.toMinutes(TimeUnit.SECONDS.toHours(seconds));
System.out.println("Day :"+day+" Hours :"+hours+" Minutes :"+minute);
this will give you:
1w 4d 10h 20m
there should be more elegant way, but this works:
long s = 987654l;
final long M=60,H=60*M, D=24*H, W=7*D;
long w = s/W;
s%=W;
long d = s/D;
s%=D;
long h = s/H;
s%=H;
long m = s/M;
System.out.printf("%dw %dd %dh %dm",w,d,h,m);
int seconds=98765410;
int weeks = (int) (TimeUnit.SECONDS.toDays(seconds) / 7);
int days = (int) (TimeUnit.SECONDS.toDays(seconds) - 7 * weeks);
long hours = TimeUnit.SECONDS.toHours(seconds) - TimeUnit.DAYS.toHours(days) - TimeUnit.DAYS.toHours(7*weeks);
long minutes = TimeUnit.SECONDS.toMinutes(seconds) - (TimeUnit.SECONDS.toHours(seconds) * 60);
System.out.println(weeks+"w "+days+"d "+hours+"h "+minutes+"m");
Will print out:
163w 2d 2h 50m

Categories

Resources