I'm aware that you can use DateUtils.formatElapsedTime(seconds) to convert a number of seconds into a String with the format HH:MM:SS. But are there any utility functions that let me perform the same conversion but without the seconds?
For example, I want to convert 3665 seconds into 1:01, even though it's exactly 1:01:05. In other words, simply dropping the seconds part.
Would strongly prefer an answer that points to a utility function (if one exists) rather than a bunch of home rolled algorithms.
Use Apache Commons Lang
You could use utility class DateFormatUtils of Apache's well known utility library Commons Lang, combined with TimeUnit to convert from seconds to milliseconds:
static String format(long durationSeconds) {
long durationMillis = TimeUnit.SECONDS.toMillis(durationSeconds);
// Commons lang:
return DurationFormatUtils.formatDuration(durationMillis, "HH:mm");
}
Use with input 3665 it prints:
01:01
Personally I'd prefer to use Java8 or Java9 standard library (see the other answers) rather than introducing a dependency just to make it 1 method call.
MadProgrammer has already provided a good Java 8 answer (which will work in Java 6 and 7 too when you use the ThreeTen Backport). In Java 9 still a bit more of the calculation can be done in the library:
int seconds = 3665;
Duration dur = Duration.ofSeconds(seconds);
String formatted = String.format("%d:%02d", dur.toHours(), dur.toMinutesPart());
System.out.println(formatted);
Output:
1:01
The toMinutesPart method and other toXxxPart methods were introduced in Java 9.
Based on the available information, you seem to be wanting to format a duration based value. Lucky for us, since Java 8, there is now a new java.time API which includes a Duration class.
Unfortunately, it doesn't (at least the last time checked) support a formatter for it.
However, you could easily roll your own...
protected static String format(Duration duration) {
long hours = duration.toHours();
long mins = duration.minusHours(hours).toMinutes();
return String.format("%02d:%02d", hours, mins);
}
Which when used with something like...
System.out.println(format(Duration.ofSeconds(3665)));
prints out 01:01.
Now I know you'd "prefer" utility methods, but you're unlikely to find something that fits your "every" need and this at least gives you a starting point. Besides, you could always make a pull request ;)
Related
I want to parse some dates in Java, but the format is not defined and could be a lot of them (any ISO-8601 format which is already a lot, Unix timestamp in any unit, and more)
Here are some samples :
1970-01-01T00:00:00.00Z
1234567890
1234567890000
1234567890000000
2021-09-20T17:27:00.000Z+02:00
The perfect parsing might be impossible because of ambiguous cases but, a solution to parse most of the common dates with some logical might be achievable (for example timestamps are considered in seconds / milli / micro / nano in order to give a date close to the 2000 era, dates like '08/07/2021' could have a default for month and day distinction).
I didn't find any easy way to do it in Java while in python it is kind of possible (not working on all my samples but at least some of them) using infer_datetime_format of panda function to_datetime (https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html).
Are there some easy approach in Java?
Well, first of all, I agree with rzwitserloot here that date parsing in free format is extremely difficult and full of ambiguities. So you are skating on thin ice and will eventually run into trouble if you just assume that a user input will be correctly parsed the way you think it will.
Nevertheless, we could make it work if I assume either of the following:
You simply don't care if it will be parsed incorrectly; or
You are doing this for fun or for learning purposes; or
You have a banner, saying:
If the parsing goes wrong, it's your fault. Don't blame us.
Anyway, the DateTimeFormatterBuilder is able to build a DateTimeFormatter which could be able to parse a lot of different patterns. Since a formatter supports optional parsing, it could be instructed to try to parse a certain value, or skip that part if no valid value could be found.
For instance, this builder is able to parse a fairly wide range of ISO-like dates, with many optional parts:
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder()
.appendPattern("uuuu-M-d")
.optionalStart()
.optionalStart().appendLiteral(' ').optionalEnd()
.optionalStart().appendLiteral('T').optionalEnd()
.appendValue(ChronoField.HOUR_OF_DAY)
.optionalStart()
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR)
.optionalStart()
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 1, 9, true)
.optionalEnd()
.optionalEnd()
.optionalEnd()
.appendPattern("[XXXXX][XXXX][XXX][XX][X]")
.optionalEnd();
DateTimeFormatter formatter = builder.toFormatter(Locale.ROOT);
All of the strings below can be successfully parsed by this formatter.
Stream.of(
"2021-09-28",
"2021-07-04T14",
"2021-07-04T14:06",
"2001-09-11 00:00:15",
"1970-01-01T00:00:15.446-08:00",
"2021-07-04T14:06:15.2017323Z",
"2021-09-20T17:27:00.000+02:00"
).forEach(testcase -> System.out.println(formatter.parse(testcase)));
Als you can see, with optionalStart() and optionalEnd(), you could define optional portions of the format.
There are many more patterns you probably want to parse. You could add those patterns to the abovementioned builder. Alternatively, the appendOptional​(DateTimeFormatter) method could be used to include multiple builders.
The perfect parsing might be impossible because of ambiguous cases but, a solution to parse most of the common dates with some logical might be achievable
Sure, and such wide-ranging guesswork should most definitely not be part of a standard java.* API. I think you're also wildly underestimating the ambiguity. 1234567890? It's just flat out incorrect to say that this can reasonably be parsed.
You are running into many, many problems here:
Java in general prefers throwing an error instead of guessing. This is inherent in the language (java has few optional syntax constructs; semicolons aren't optional, () for method invocations are not optional, java intentionally does not have 'truthy/false', i.e. if (foo) is only valid if foo is an expression of the boolean type, unlike e.g. python where you can stick anything in there and there's a big list of what counts as falsy, with the rest being considering truthy. When in rome, be like the romans: If this tenet annoys you, well, either learn to love it, begrudgingly accept it, or program in another language. This idea is endemic in the entire ecosystem. For what it is worth, given that debugging tends to take far longer than typing the optional constructs, java is objectively correct or at least making rational decisions for being like this.
Either you can't bring in the notion that 'hey, this number is larger than 12, therefore it cannot possibly be the month', or, you have to accept that whether a certain date format parsers properly depends on whether the day-of-month value is above or below 12. I would strongly advocate that you avoid a library that fails this rule like the plague. What possible point is there, in the end? "My app will parse your date correctly, but only for about 3/5ths of all dates?" So, given that you can't/should not take that into account, 1234567890, is that seconds-since-1970? milliseconds-since-1970? Is that the 12th of the 34th month of the year 5678, the 90th hour, and assumed zeroes for minutes, seconds, and millis? If a library guesses, that library is wrong, because you should not guess unless you're 95%+ sure.
The obvious and perennial "do not guess" example is, of course, 101112. Is that November 10th, 2012 (european style)? Is that October 11th, 2012 (American style), or is that November 12th, 2010 (ISO style)? These are all reasonable guesses and therefore guessing is just wrong here. Do. Not. Guess. Unless you're really sure. Given that this is a somewhat common way to enter dates, thus: Guessing at all costs is objectively silly (see above). Guessing only when it's pretty clear and erroring out otherwise is mostly useless, given that ambiguity is so easy to introduce.
The concept of guessing may be defensible but only with a lot more information. For example, if you give me the input '101112100000', there's no way it's correct to guess here. But if you also tell me that a human entered this input, and that human is clearly clued into, say, german locale, then I can see the need to be able to turn that into '10th of november 2012, 10 o'clock in the morning': Interpreting as seconds or millis since some epoch is precluded by the human factor, and the day-month-year order by locale.
You asked:
Are there some easy approach in Java?
This entire question is incorrect. The in Java part needs to be stripped from this question, and then the answer is a simple: No. There is no simple way to parse strings into date/times without a lot more information than just the input string. If another library says they can do that, they are lying, or at least, operating under a list of cultural and source assumptions as long as my leg, and you should not be using that library.
I don't know any standard library with this functionality, but you can always use DateTimeFormatter class and guess the format looping over a list of predefined formats, or using the ones provides by this class.
This is a typichal approximation of what you want to archive.
Here you can see and old implementation https://balusc.omnifaces.org/2007/09/dateutil.html
FTA (https://github.com/tsegall/fta) is designed to solve exactly this problem (among others). It currently parses thousands of formats and does not do it via a predefined set, so typically runs extremely quickly. In this example we explicitly set the DateResolutionMode, however, it will default to something intelligent based on the Locale. Here is an example:
import com.cobber.fta.dates.DateTimeParser;
import com.cobber.fta.dates.DateTimeParser.DateResolutionMode;
public abstract class Simple {
public static void main(final String[] args) {
final String[] samples = { "1970-01-01T00:00:00.00Z", "2021-09-20T17:27:00.000Z+02:00", "08/07/2021" };
final DateTimeParser dtp = new DateTimeParser().withDateResolutionMode(DateResolutionMode.MonthFirst).withLocale(Locale.ENGLISH);
for (final String sample : samples)
System.err.printf("Format is: '%s'%n", dtp.determineFormatString(sample));
}
}
Which will give the following output:
Format is: 'yyyy-MM-dd'T'HH:mm:ss.SSX'
Format is: 'yyyy-MM-dd'T'HH:mm:ss.SSSX'
Format is: 'MM/dd/yyyy'
This question already has answers here:
Time consts in Java?
(12 answers)
Closed 3 years ago.
Working with Java, I'm parsing a integer DAYS to HOURS.
Looks like this:
float hours = myvardays*24;
It works, but constant 24 is a magic number, and best avoided.
Is there any constant on Calendar, Date or any other to get total hours in a day (24)? or maybe a method?
I am interested only in generic 24-hours, ignoring anomalies such as Daylight Saving Time (DST) that result in other day lengths.
Let's not go reinventing stuff, this is all baked into the JDK:
Java 8 and later
Use Duration.ofDays with toDays method.
long hours = Duration.ofDays(myvardays).toHours(); // Java 8+
Java 5, 6, & 7
Use the TimeUnit enum.
long hours = TimeUnit.DAYS.toHours(myvardays); // Java 5+
In JDK 8 you have the Duration class where you can perform conversions between units of time.
Example:
Duration.ofDays(1).toHours() //24hs
Duration.ofHours(1).toMinutes() //60 minutes
I don't know of anything in the Java Standard Libraries that does quite what you are looking for.
However if you have static numbers in your calculations there really is no reason to remove them. Unless you feel that they will change in the future or will need to be updated in many places should the needs of the application change (e.g. on mars where there may be a different number of hours in the day)
One could make an argument that it is unclear exactly what is going on (why 24, oh right...). You may want to make a small class containing your own constants with clear names simply to make the code more readable.
For example:
public final class TimeIntervals {
// ...
public static final int HOURS_IN_DAY = 24;
public static final int DAYS_IN_WEEK = 7;
//...
}
and then use it as
float hours = days * TimeIntervals.HOURS_IN_DAY;
I am looking to calculate the number of minutes given the time of the day.
Eg.: when input is 11:34, the output should be 11*60+34. The date doesn't matter.
I only need it down to the minutes scale. Seconds, milliseconds... don't matter.
Is there a method somewhere in Java doing this the neat way without me calculating it?
Right now, i'm using theTime.split(":"), theTime is a String holding "11:34" here, parsing the integers on each side and doing the calculation.
I saw Time but what I'm doing right now seemed more direct.
Nothing in Systems either.
There is no build in method for it. However here is a one-liner for it:
int timeInMins = Calendar.getInstance().get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance().get(Calendar.MINUTE);
Your approach looks good and sound, however to answer your question it would be simple to say that there is no such build in method which does that. You have to calculate it the way you are doing it right now.
Hi maybe you could use JodaTime? Below example how to get number of minutes from parsed string and from current time. In java 8 there is similar api but I haven't found exactly method like minutesOfDay()
#Test
public void learnHowManyMinutesPassedToday() {
DateTime time = DateTimeFormat.forPattern("HH:mm").parseDateTime("11:34");
System.out.println(time.getMinuteOfDay());
System.out.println(DateTime.now().getMinuteOfDay());
}
If you are looking to have input not from a String, take a look at
Java.util.Calendar.
It has Calendar.HOUR_OF_DAY and Calendar.HOUR and Calendar.MINUTE which could be your input. I'm not sure what the "neat" way of doing this would be. It is a simple calculation.
Calendar rightNow = Calendar.getInstance();
int hour = rightNow.get(Calendar.HOUR);
int min = rightNow.get(Calendar.MINUTE);
System.out.println("TimeMinutes:" + hour * 60 + min);
EDIT:
Except using split use the above.
I am trying to build a sample application which will show a proof of concept for synchronizing the time with an RFC 868 compliant time server.
So far, using the Java Socket API, I am able to connect and query the server and do get the response from the server, but it is not in human readable format.
The response I get is: �)6 I think the response is coming in binary format (not sure though). RFC 868 says that Send the time as a 32 bit binary number.
My questions are:
How do I parse this response?
Apart from this approach of mine, I'd like to know if there is any other recommended approach which I should take to achieve this.
Thanks in advance.
1) How do I parse this response?
Check out the source code of TimeTCPClient from Apache Commons Net library:
public long getTime() throws IOException {
DataInputStream input;
input = new DataInputStream(_input_);
return (input.readInt() & 0xffffffffL);
}
public Date getDate() throws IOException {
return new Date((getTime() - SECONDS_1900_TO_1970)*1000L);
}
2) Apart from this approach of mine, I'd like to know if there is any other recommended approach which I should take to achieve this.
Use Apache Commons Net Library, check out the API of TimeTCPClient.
Apache Commons Net home page, hope this helps.
As stated in the RFC this is the seconds since 1900-01-01T00:00:00. For Java convert it to a Long,change the base date to 1970-01-01T00:00:00, and multiply by 1000 to get the date. Then you can create a new Date using this value.
Wrap your socket input stream to a DataInputStream and read an into rfsOffset (I used a constant). Then you can do something like:
int rfcOffset = -752253627; // Fri Apr 06 11:00:32 EDT 2012
// Current offsets will be negative convert to long positive value
long offsetSecs = rfcOffset + 4294967296L;
System.out.println(offsetSecs);
// Adjust time base from 1900 to 1970 and convert to millis
long offsetMillis = ( offsetSecs - 2208988800L)* 1000L;
System.out.println(offsetMillis);
Date rfcDate = new Date(offsetMillis);
System.out.println(rfcDate.toString());
Note: this only works until 2036 and time will be off by some number of milliseconds.
EDIT: RFC 868 is an old protocol and is no longer considered a good time source for synchronization. A good time source will us NTP and will return the correct second. It may be off a few milliseconds, but is normally accurate withing 10 milliseconds. Many hardware clocks drift significantly, and I have seen significant drift from systems with inaccurate clocks (even with NTP running(). NTP will correct a drifting clock, but needs a few minutes to determine the required shift.
EDIT2: While RFC 868 is old, it may be good enough to set the time on a cell phone to the nearest second without requiring a background process. This shouldn't be necessary if your cell phone can sync to a signal sent by your provider.
I am working with AD via LDAP (using Spring LDAP) and I ran into a odd problem while working with Integer8/LargeInteger being used as timestamps which are outlined here. Namely, my attempts to write to fields of that type have resulted in...
Malformed 'field name here' attribute value
I've tried putting Longs and Strings in hopes that the underlying implementation would do any needed conversions but no luck. Here is how I am doing my math...
/* AD Keeps track of time in 100 NS intervals (UTC) since Jan 1st 1601 */
long winEpocMS = new GregorianCalendar(1601, Calendar.JANUARY, 1).getTimeInMillis();
long nowMS = System.currentTimeMillis();
long winTime100NS = (nowMS - winEpocMS) * 10000;
Is there a easy/elegant way to pack this data correctly? Are there any Java libs prebuilt to handle reading/writing these rather odd time values?
Bonus points to anyone that can explain why we need a 64bit timestamp at the 100NS resolution.
Ok here's the breakdown...
/* time since Jan 1st 1601 00:00:00 UTC */
final long WIN_EPOC_MS = 11644473600000L;
final long now_ms = System.currentTimeMillis();
final long now_win_ns = (now_ms + WIN_EPOC_MS) * 10000L;
The reverse should be obvious from the above code. If you want to double check the convertions use w32tm. For example, the following shows that we have the right convertion time to the Unix epoc (note that I am in CST)
w32tm /ntte 116444736000000000
134774 00:00:00.0000000 - 12/31/1969
06:00:00 PM (local time)
Finally, when working with AD make sure the field accepts any value. Some fields take "-1" to mean "now" and "0" may have special meaning. Also, in some cases it seems to matter if the time attribute modification is bundled with other attribute modifications (such as pwdLastSet and unicodePwd).
One last note, I would avoid GregorianCalendar unless you know you have your timezones right (it's easy to mess up).
I not know any Java library that handle the time with that Microsoft-specific format (100 nanosecond intervals since 1601). I think this ways is correct.
You can define winEpocMS as a constant and use:
long winTime100NS = (System.currentTimeMillis() - winEpocMS) * 10000L;
Why we need 64bit timestamp is simple. With 32bit you got 2^32 values (roughly 4,000,000,000), enough to handle seconds since 1970 until 2038 (know as the 2000-year effect on Unix). If you need microseconds or 100 nanoseconds precision, you use bigger values that have to be managed as 64 bit numbers. Java uses milliseconds since 1970 to represent dates and requires long type that is a signed 64 bit number.