table structure:
sysdurationtimeday , sysdurationtimehour, sysdurationtimeminute
1, 12,10
3, 23,10
0, 0,10
i have these 3 fields from database, after getting these 3 values, what is the technique that i can use do cast to which Java Object? (maybe Calendar.class, TimeStamp.class) ?
and use it to compared with record is spent less than 1 day, more than 1 day + less than 3 days. etc?
As long as you're talking durations and not absolute times, this is pretty easy. Just express the time in a convenient unit, say seconds:
time_in_seconds = 86400*sysdurationtimeday +
3600*sysdurationtimehour +
60*sysdurationtimeminute
In Java the standard way to represent this is actually as a long value in milliseconds, ala System.currentTimeMillis().
All the standard Java classes are intended to handle absolute times and need to deal with daylight savings, leap years, and all that crap. At least with the data you gave us, you don't have the required info anyway: there's no way to tell if the day was a daylight savings day and therefore took 23 or 25 hours instead of 24.
I would prefer my own class, overriding the "essential" methods.
public class SysDuration implements Comparable {
int day;
int hour;
int min;
public SysDuration(int day,int hour,int min) {
}
public boolean equals(Object obj) {
}
public int hashCode() {
}
public int compareTo(Object obj) {
}
public boolean spendLess(SysDuration dur) {
}
}
Lots of good answers already.
A sugegstion, perhaps out of scope, if you use durations in java I would prefer to
just calculate and store this in one variable, typically a long in milliseconds
if this resolution is good enough. The splitting in 3 variables usually
make most of the code more complicated.
Calculations are easier and intergartion with libs such as jodatime and similar will be
even more simple.
If you literally want "more than 1 day", that is there's no rounding so d=1, h=23, m=59 gives you 1 day, not 2 days then you can just use sysdurationtimeday and completely ignore hours and minutes. (That assumes you don't have more than 24 in sysdurationtimehour).
Classes such as Calendar don't help, they are for manipulating actual dates, you already are working in durations.
Jodatime supports durations and then you get the operations needed for free.
If you are hesitant to add another dependency and learning curve, I would create a little custom class with a field storing the duration as a number in the desired precision. Then add some methods to do your comparisons or return a Calendar object or a Date aded and subtracted with your duration.
My guess is this will end up being cleaner than using the standard Java API's which always end up in complicated, clunky code when you start manipulating time.
Related
I have a Duration, like P3M (3 months). How can I get number of days it is from now?
All I have now is this:
Duration.parseWeekBasedPeriod("P3M")
I know the period parameter will never be shorter than 1 week, so parseWeekBasedPeriod() should be ok. But I'm reading JavaDoc, and I can't figure out how to get those days.
I understand, the problem is that months can has 31, 30, 29 and 28 days.
Using parseWeekBasedPeriod(...) is certainly wrong if you want to apply durations measured in months. This very special method handles week based years which can last either 364 or 371 days (52 or 53 weeks). So I suggest just to use the standard parsing method for calendar-based durations. The following code also strongly simplifies the evaluation of days between two dates (see last line).
Duration<CalendarUnit> duration = Duration.parseCalendarPeriod("P3M");
PlainDate today = PlainDate.nowInSystemTime();
PlainDate later = today.plus(duration);
long days = CalendarUnit.DAYS.between(today, later);
By the way, I have tested the method for weekbased durations once again. It will usually throw an exception if it tries to parse months. You didn't seem to have seen any exception so I assume that the fact that you use untyped constructs like "val" has shadowed the necessary type information in processing the duration string (and Time4J is a strongly typed library). Hence - if technically possible for you -, I strongly recommend to use type-safe code as shown in my solution.
Finaly figured it out:
val period = Duration.parseWeekBasedPeriod("P3M")
val start = PlainDate.nowInSystemTime()
val end = start.plus(period)
val days: Long = Duration.`in`(CalendarUnit.DAYS).between(start, end).getPartialAmount(CalendarUnit.DAYS)
I'm writing a class that is dependent on months and how many days each month has. At the beginning of my class, I've written:
static final int JAN = 1;
static final int FEB = 2;
...
static final int DEC = 12;
It looks like a messy way of doing this, and I feel that enums would be more efficient. I need to be able to "increment" the month (where DEC + 1 = JAN), and need to be able to know have many days there are in the month (with FEB having 28).
I see two ways of doing this:
My current way, defining static final ints and using a switch statement to find the number of days, and when incrementing I always checks for whether the value would be greater than 12.
Create a set of enums, each with inputs for which month of the year it is and how many days it contains, and defining an "increment" method.
Is there a better way of doing this, or is (presumably) 2. the best way of doing this?
I recommend using java.util.Calendar for this sort of situation. It already has constants defined for virtually every date- and time-related concept that you'll ever have to use; plus, it is smart enough to know about things like February's wishy-washy length (29 days 25% of the time).
Java has a Class that does what you need. See the Calendar class, which also has constants for Month and Day of Week:
https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
First of all I'm new to java.time package.
I'm writing a webapp that need to work with specific times of the day and with several durations of events.
So I wrote my code using LocalTime and Duration classes of java.time package.
When I need to render their value in JSP it is very simple for LocalTime object (because .toString() returns a human readable vale), so I can just write ${startTime} and everything goes in the right way (e.g. it is rendered as 9:00).
The same approach doesn't work for Duration, because its representation is something like PT20M (in this case for 20 minutes).
Does it exist an elegant way to perform a human-readable conversion in JSP directly by EL?
Yes, I know I can convert the object in a string in my classes (before JSP), but I'm searching for the suggested approach (that I'm not able to find)... another point is that I not see an official "convert()" (or whatever else) method in Duration object... so I'm thinking I'm using the wrong object to map a duration of time (to add or subtract on LocalTimes).
Thank you.
Unfortunately there exists no elegant builtin way to format a Duration in Java 8. The best i have found is to use the method bobince describes in this answer:
Duration duration = Duration.ofHours(1).plusMinutes(20);
long s = duration.getSeconds();
System.out.println(String.format("%d:%02d:%02d", s/3600, (s%3600)/60, (s%60)));
Which prints:
1:20:00
The code will have to be tuned if you need longer durations.
I'm not sure what you mean that you are missing a convert method, but Duration is well suited for adding/subtracting on LocalTime. The methods LocalTime.plus() and LocalTime.minus() accepts Duration as argument.
If you're interested in words, apache commons will do the trick:
DurationFormatUtils.formatDurationWords(System.currentTimeMillis() - start, true, false))
2 days 1 hour 5 minutes 20 seconds
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/time/DurationFormatUtils.html#formatDurationWords-long-boolean-boolean-
I need to compare time zones such that Asia/Singapore < UTC < Pacific/Honolulu.
I'm working with java.util.TimeZone (which doesn't implement Comparable).
My search for an existing implementation was unsuccessful because of the overwhelming number of questions about comparing dates with different time zones.
Question: What is a correct implementation of Comparator<TimeZone> that will solve this problem (and what makes it better than other solutions, if applicable)?
Note that I'm not able to use Joda Time for this problem, so "use Joda Time" is not a valid answer.
Edit for clarity
The < notation above was not well defined. My particular use case only requires a naive "geographical" ordering from east to west. As the comments have pointed out, a more advanced and generalizable solution would take into account temporal factors like daylight savings time and historical GMT offset changes. So I think there are two orderings we can consider, each requiring a different Comparator<TimeZone> implementation:
Strictly geographical (current UTC) - addressed by my answer.
Sensitive to local or civil time changes - addressed by rgettman's answer.
I rolled my own Comparator<TimeZone> implementation using getRawOffset for the comparison:
#Override
public int compare(TimeZone tz1, TimeZone tz2) {
return tz2.getRawOffset() - tz1.getRawOffset();
}
It seems to have passed a quick test:
final List<TimeZone> timeZones = Arrays.asList(
TimeZone.getTimeZone("UTC"),
TimeZone.getTimeZone("America/Los_Angeles"),
TimeZone.getTimeZone("America/New_York"),
TimeZone.getTimeZone("Pacific/Honolulu"),
TimeZone.getTimeZone("Asia/Singapore")
);
final List<TimeZone> expectedOrder = Arrays.asList(
TimeZone.getTimeZone("Asia/Singapore"),
TimeZone.getTimeZone("UTC"),
TimeZone.getTimeZone("America/New_York"),
TimeZone.getTimeZone("America/Los_Angeles"),
TimeZone.getTimeZone("Pacific/Honolulu")
);
Collections.sort(timeZones, new Comparator<TimeZone>() {
#Override
public int compare(TimeZone tz1, TimeZone tz2) {
return tz2.getRawOffset() - tz1.getRawOffset();
}
});
//Impl note: see AbstractList.equals
System.out.println(timeZones.equals(expectedOrder)); //true
But I'm still wondering whether there are pitfalls to this solution and/or if there's something preferable.
One might be able to create a Comparator<TimeZone> that takes into account time zone differences. The TimeZone may or may not obvserve daylight savings time, which would adjust the raw offset, thus messing up raw-offset-only comparisons. The TimeZone class seems to support the adjustment based on the 2 getOffset methods, but they need a reference date. How about:
public class TimeZoneComparator implements Comparator<TimeZone>
{
private long date;
public TimeZoneComparator(long date)
{
this.date = date;
}
public int compare(TimeZone tz1, TimeZone tz2)
{
return tz2.getOffset(this.date) - tz2.getOffset(this.date);
}
}
Timezones are purely political, so any use of them that is non-conforming will cause LOTS of problems for users, depending on what the app does and who needs it or uses it. You question would be better asked by explaining why you need them ordered like that. There are adjacent timezones where one uses DST the other does not. So 60% of the year, the TZ1 == TZ2, the other 40% TZ1 < TZ2. Or whatever the case may be.
There are geographic (lat long) timezone data sets, and web sites to query for timezone. Even current DST settings. So you may have to settle for a data set that you need to update frequently at least yearly. Or web access.
You probably should not assign magnitude to them. Only geographic ordering - by longitude.
First of if you could tell us what you are trying to do it'd be great. And the answer is not: strict a>b>c order based on local time. I coded calendrics for a while, so I actually used to know this stuff.
What explictly do believe requires this kind of ordering?
ok not as simple as title may make it sound. I tried this in a very primal way with c# and it worked, but I have a feeling a better job could be achieved with Java and Oracle as database. So the thing is:
I have a reservation system. multiple bookings could be made on the same day for period between date X and date Y as long as each day in the range can accommodate the requested number. Maximum number of clusters to reserve is 46. Hence logically you would look at each day as a holder of 46 cluster reservation and deduce from that.
Now what I have difficulty working out is:
when there are n number of bookings stored and valid in database, then I want to make new booking. So how do I check if this new date range falls within any of the previously booked days or not. Not talking simply here about x falling in y (as ranges). More like:
X_______________________________________Y
X________________________________y
X________________________________Y
X________________________________Y
as u can see the overlap is happening.
Please let me know how could I do this as it will affect early design of objects
Regards
Assume your date has two methods: isBefore(Date other) and isAfter(Date other). Obviously if they don't you can cure this with an external method or wrapping or something. Edit: java.util.Date has compareTo method you could use.
You do this:
public boolean overlapsWithExisting(Booking booking) {
final Date early = booking.getStart();
final Date late = booking.getEnd();
for(Booking existing : existingBookings) {
if(!(early.isAfter(existing.getEnd()) || late.isBefore(existing.getStart()))
return true;
}
return false;
}
We compare this booking to all existing bookings. If this booking ends before the existing booking even starts, or if this booking starts after the existing booking ends, then it doesn't conflict. Any other condition and they will overlap.
Do this to each booking.
Joda-Time – Interval
Rather than roll your own, use the Interval class in the Joda-Time library. An Interval is a pair of specific points along the timeline, each defined as a DateTime instance.
The Interval class offers overlap, gap, and abuts methods.
Half-Open
Those methods wisely use the Half-Open approach to spans of time where the beginning is inclusive while the ending is exclusive. Search StackOverflow for more info.