I'm developing an application where the user sends a time duration in this format "YY : MM : DD : HH : mm : ss" ex . 1yr 2months 3days 4hrs 5mins 6sec will be specified as
1:2:3:4:5:6
From this value , i have to convert the duration into seconds. I want to know whether there is any inbuilt java class to specify time duration in this format?
The ISO 8601 standard defines a string representation for a span of time as PnYnMnDTnHnMnS where P marks the beginning and T separates the date portion from the time portion.
For example, "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".
An hour and a half would be PT1H30M.
The Joda-Time library has the Period class that both parses and generates that format by default.
Search StackOverflow for more.
Java-8 introduced java.time.Duration and java.time.Period as part of JSR-310 implementation but there has been a long wait for a type combining period and duration as specified at ISO_8601#Durations.
However, javax.xml.datatype.Duration has been there since Java-6 and we can use this to achieve what you want to. The assumption is that your text is always in the format, y:M:d:H:m:s e.g. 1:2:3:4:5:6.
Demo:
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
public class Main {
public static void main(String[] args) throws DatatypeConfigurationException {
String[] durationParts = "1:2:3:4:5:6".split(":");
char[] symbols = "YMDHMS".toCharArray();
StringBuilder sb = new StringBuilder("P");
for (int i = 0; i < durationParts.length; i++) {
sb.append(durationParts[i]).append(symbols[i]);
if (i == 2) {
sb.append("T");
}
}
String strIso8601Duration = sb.toString();
System.out.println(strIso8601Duration);
Duration duration = DatatypeFactory.newInstance().newDuration(strIso8601Duration);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
long seconds = TimeUnit.MILLISECONDS.toSeconds(duration.getTimeInMillis(calendar));
System.out.println(seconds);
}
}
Output:
P1Y2M3DT4H5M6S
36907506
Related
my method accepts - hours, minutes, seconds and milliseconds separated by sign / as a string parameter
how can I add to the current date the parameters that come to the method.
Example 1: today, 02/10/2021, the method receives metnode data (10/10/10/10) - output - 02/10/2021 10:10:10
Example 2: today, 02/10/2021, the method receives metnode data (55/10/10/10) - output - 02/12/2021 07:10:10
That is, you need to add 55 hours 10 seconds 10 seconds and 10 milliseconds to the current date.
you cannot use the Calendar and StringTokenizer classes.
public void method(String s) {
s = s.replaceAll("/", "-");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
final LocalDateTime now = LocalDateTime.parse(s, formatter.withResolverStyle(ResolverStyle.LENIENT));
System.out.println(now);
}
i found the withResolverStyle (ResolverStyle.LENIENT) method
but did not understand how to use it.
A lenient DateTimeFormatter is enough
I don’t know if it’s the best solution. That probably depends on taste. It does use the ResolverStyle.LENIENT that you mentioned and generally works along the lines of the code in your question, only fixed and slightly simplified.
My formatter includes both date and time. This is necessary for surplus hours to be converted to days.
private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd H/m/s/")
.appendValue(ChronoField.MILLI_OF_SECOND)
.toFormatter()
.withResolverStyle(ResolverStyle.LENIENT);
Next thing we need a string that matches the formatter. So let’s prepend the date to the time string that we already have got:
String timeString = "55/10/10/10";
LocalDate today = LocalDate.now(ZoneId.of("America/Regina"));
String dateTimeString = "" + today + ' ' + timeString;
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, formatter);
System.out.println(dateTime);
The output from my code when I ran it today (February 10) was:
2021-02-12T07:10:10.010
A different idea: use Duration
Edit: An alternative is to use the Duration class. A reason for doing that would be that it really appears that you are adding a duration rather than setting the time of day. A liability is that parsing your string into a Duration is a bit tricky. The Duration.parse method that we want to use only accepts ISO 8601 format. It goes like PT55H10M10.010S for a period of time of 55 hours 10 minutes 10.010 seconds. And yes, milliseconds need to be given as a fraction of the seconds.
String isoTimeString = timeString.replaceFirst("(/)(\\d+)$", "$100$2")
.replaceFirst("(\\d+)/(\\d+)/(\\d+)/0*(\\d{3})", "PT$1H$2M$3.$4S");
Duration dur = Duration.parse(isoTimeString);
LocalDateTime dateTime = LocalDate.now(ZoneId.of("Asia/Kathmandu"))
.atStartOfDay()
.plus(dur);
When I ran it just now — already February 11 in Kathmandu, Nepal — the output was:
2021-02-13T07:10:10.010
I am using two calls to replaceFirst(), each time using a regular expression. The first call simply adds some leading zeroes to the milliseconds. $1 and $2 in the replacement string give us what was matched by the first and the second group denoted with round brackets in the regular expression.
The second replaceFirst() call established the ISO 8601 format, which includes making sure that the milliseconds are exactly three digits so they work as a decimal fraction of the seconds.
Link: ISO 8601
Try this:
public void method(String s) {
String[] arr = s.split("/");
LocalDateTime now = LocalDateTime.of(
LocalDate.now(), LocalTime.of(0, 0))
.plusHours(Integer.parseInt(arr[0]))
.plusMinutes(Integer.parseInt(arr[1]))
.plusSeconds(Integer.parseInt(arr[2]))
.plusNanos(Integer.parseInt(arr[3]) * 1_000_000L);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
System.out.println(now.format(formatter));
}
Look into the LocalDateTime documentation. It offers various means for combining dates. Such as:
plus(amount, unit)
plusDays(days)
plusHours(hours)
plusMinutes(minutes)
just for simplicity , you can your LocalDateTime class. it is easy to understand. please refer to below code is used to add the hours, minuts, second and nanos to current Date Time.
this Date Time then can easy formatted by any format pattern as required.
public void addDateTime(int hours, int minuts, int seconds, int nanos) {
LocalDateTime adt = LocalDateTime.now();
System.out.println(adt);
adt = adt.plusHours(hours);
adt = adt.plusMinutes(minuts);
adt = adt.plusSeconds(seconds);
adt = adt.plusNanos(nanos);
System.out.println(adt);
}
I know there are similar questions but they don't answer my problem. I want to format the current time into integer, but only the minutes or seconds.
So for example
LocalTime d = LocalTime.now(ZoneId.of("GMT"));
gives me the current GMT and with "withNano(0)" I can cut off the nanoseconds. Since I have it in the format 12:15:45 now I want to be able to save 15 (Minutes) into my Integer or 45 (Seconds). How can I convert it?
You can call specific methods on the LocalTime such as getMinute() and getSecond(), or you can use a DateTimeFormatter with a pattern that you’re looking for, like:
d.format(DateTimeFormatter.of(“mm:ss”);
If you’re doing that, you don’t need to zero out the nano first.
You can use built in methods for getting minutes and seconds, they both return integers:
d.getMinute();
d.getSecond();
Simply use the getter methods of LocalTime.
import java.time.LocalTime;
import java.time.ZoneOffset;
public class Main {
public static void main(String[] args) {
LocalTime now = LocalTime.now(ZoneOffset.UTC);
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
System.out.printf("%d hour, %d minute, %d second", hour, minute, second);
}
}
Output:
21 hour, 37 minute, 47 second
Also, I suggest you use ZoneOffset.UTC for UTC instead of the 3-letter name for timezone. You can also use ZoneId.of("Etc/UTC"). The general naming convention for timezone is Region/City e.g. Europe/London.
I am making an application just for learning purpose. And I tried to calculate the difference between two dates
LocalDate today = LocalDate.now();
LocalDate localHoudbaarheid = houdbaarheidsDatum;
Period period = Period.between(today, localHoudbaarheid);
The calculation works, but the output is strange.
Output of the code:
Dagen tot over de datum: P9D
The only thing that should be shown is the 9 without the P and D. This is where I call the name period in my code to print it out:
"Dagen tot over de datum: " + period;
There is nothing whatsoever strange about the output, it is exactly what the documentation, i.e. the javadoc of Period.toString() says it is:
Outputs this period as a String, such as P6Y3M1D.
The output will be in the ISO-8601 period format. A zero period will be represented as zero days, 'P0D'.
As documentation says, the output is following the ISO-8601 standard for durations, as also explained on Wikipedia:
Durations define the amount of intervening time in a time interval and are represented by the format P[n]Y[n]M[n]DT[n]H[n]M[n]S ...
P is the duration designator (for period) placed at the start of the duration representation.
Y is the year designator that follows the value for the number of years.
M is the month designator that follows the value for the number of months.
W is the week designator that follows the value for the number of weeks.
D is the day designator that follows the value for the number of days.
P9D means a Period of 9 Days.
import java.time.LocalDate;
import java.time.Period;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate after9Days = today.plusDays(9);
Period period = Period.between(today, after9Days);
System.out.println(period);
System.out.printf("Years: %d, Months: %d, Days: %d", period.getYears(), period.getMonths(), period.getDays());
}
}
Output:
P9D
Years: 0, Months: 0, Days: 9
Learn more about it at https://en.wikipedia.org/wiki/ISO_8601#Durations
The toString() method of Period outputs something like:
P(nbYears)Y(nbMonths)M(nbDays)D
P9D means a period of 9 days. P4Y3M9D means a period of 4 years, 3 months, and 9 days.
The Period class has utility methods to get this information: getDays(), getMonths(), and getYears().
If you just want to obtain the difference in the unit you choose, prefer using the until() method on the Temporal interface.
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate after3Months9Days = today.plusMonths(3).plusDays(9);
System.out.println(today.until(after3Months9Days, ChronoUnit.DAYS));
}
}
This outputs:
101
This question already has answers here:
Calculate Difference between two times in Android
(7 answers)
Closed 9 years ago.
I have two times, a start and a stop time, in the format of 05:00 (HH:MM). I need the difference between the two times.Suppose if start time is 05:00 and end time is 15:20, then how do I calculate the time difference between two which will be 10 Hours 20 minutes. Should I convert them into datetime object and use the milliseconds to get the time difference or is there any better approach to do this?
Use Joda Time. You want the LocalTime type to represent your start and stop times, then create a Period between them.
I don't know whether there's a cut-down version of Joda Time available for Android (it may be a little big otherwise, if your app is otherwise small) but it will make things much simpler than using the plain JDK libraries. You can do that, of course - converting both into milliseconds, finding the difference and then doing the arithmetic. It would just be relatively painful :(
Sample code:
import org.joda.time.*;
public class Test {
public static void main(String args[]) {
LocalTime start = new LocalTime(5, 0);
LocalTime end = new LocalTime(15, 20);
Period period = new Period(start, end, PeriodType.time());
System.out.println(period.getHours()); // 10
System.out.println(period.getMinutes()); // 20
}
}
And just using JDK classes:
import java.util.*;
import java.util.concurrent.*;
import java.text.*;
public class Test {
public static void main(String args[]) throws ParseException {
DateFormat format = new SimpleDateFormat("HH:mm", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date start = format.parse("05:00");
Date end = format.parse("15:20");
long difference = end.getTime() - start.getTime();
long hours = TimeUnit.MILLISECONDS.toHours(difference);
long minutes = TimeUnit.MILLISECONDS.toMinutes(difference) % 60;
System.out.println("Hours: " + hours);
System.out.println("Minutes: " + minutes);
}
}
Note that this assumes that end is after start - you'd need to work out the desired results for negative times.
In a android form , i am accepting a GMT value(offset) from user such a +5:30 , +3:00.
and from this value , i want to calculate the timeZone that is "India/Delhi".
Any ideas on how to do it ......Plzz
If you already have a specific instant in time at which that offset is valid, you could do something like this:
import java.util.*;
public class Test {
public static void main(String [] args) throws Exception {
// Five and a half hours
int offsetMilliseconds = (5 * 60 + 30) * 60 * 1000;
for (String id : findTimeZones(System.currentTimeMillis(),
offsetMilliseconds)) {
System.out.println(id);
}
}
public static List<String> findTimeZones(long instant,
int offsetMilliseconds) {
List<String> ret = new ArrayList<String>();
for (String id : TimeZone.getAvailableIDs()) {
TimeZone zone = TimeZone.getTimeZone(id);
if (zone.getOffset(instant) == offsetMilliseconds) {
ret.add(id);
}
}
return ret;
}
}
On my box that prints:
Asia/Calcutta
Asia/Colombo
Asia/Kolkata
IST
(As far as I'm aware, India/Delhi isn't a valid zoneinfo ID.)
If you don't know an instant at which the offset is valid, this becomes rather harder to really do properly. Here's one version:
public static List<String> findTimeZones(int offsetMilliseconds) {
List<String> ret = new ArrayList<String>();
for (String id : TimeZone.getAvailableIDs()) {
TimeZone zone = TimeZone.getTimeZone(id);
if (zone.getRawOffset() == offsetMilliseconds ||
zone.getRawOffset() + zone.getDSTSavings() == offsetMilliseconds) {
ret.add(id);
}
}
return ret;
}
... but that assumes that there are only ever two offsets per time zone, when in fact time zones can change considerably over history. It also gives you a much wider range of IDs, of course. For example, an offset of one hour would include both Europe/London and Europe/Paris, because in summer time London is at UTC+1, whereas in winter Paris is at UTC+1.
Many timezone IDs can have the same timezone offset
Normally, the relation between timezone ID and timezone offset is many to one i.e. many timezone IDs can have the same timezone offset. In fact, on account of DST, a timezone ID can have two timezone offsets e.g. the timezone offsets for the timezone ID, "Europe/London" are "+00:00" and "+01:00" in the summer and in the winter respectively.
Apart from this, there have been instances when the timezone offset of states has been changed by their rulers/politicians many times as also mentioned by Ole V.V. in the following comment:
The relation between timezone ID and timezone offset is many to one …
True if you are considering one point in time. If looking at history,
it’s really many to many.
So, taking DST and these historical events into account, we can say that the relation between timezone ID and timezone offset is many to many.
Solution using java.time, the modern Date-Time API:
You can traverse ZoneId.getAvailableZoneIds() to filter and collect the ZoneId whose ZoneOffset is equal to the ZoneOffset created using the input offset string.
Demo:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getTimeZoneId("+5:30"));
System.out.println(getTimeZoneId("-5:00"));
}
static List<String> getTimeZoneId(String input) {
List<String> list = new ArrayList<>();
// Convert +5:30 to +05:30; similarly, -5:00 to -05:00
String[] arr = input.split(":");
if (arr.length == 2) {
input = arr[0].substring(0, 1) + String.format("%02d", Integer.parseInt(arr[0].replaceAll("\\D", ""))) + ":"
+ arr[1];
ZoneOffset offset = ZoneOffset.of(input);
Instant now = Instant.now();
list = ZoneId.getAvailableZoneIds()
.stream()
.filter(tzId -> ZoneId.of(tzId).getRules().getOffset(now).equals(offset))
.collect(Collectors.toList());
}
return list;
}
}
Output:
[Asia/Kolkata, Asia/Colombo, Asia/Calcutta]
[America/Panama, America/Chicago, America/Eirunepe, Etc/GMT+5, Mexico/General, America/Porto_Acre, America/Guayaquil, America/Rankin_Inlet, US/Central, America/Rainy_River, America/Indiana/Knox, America/North_Dakota/Beulah, America/Monterrey, America/Jamaica, America/Atikokan, America/Coral_Harbour, America/North_Dakota/Center, America/Cayman, America/Indiana/Tell_City, America/Mexico_City, America/Matamoros, CST6CDT, America/Knox_IN, America/Bogota, America/Menominee, America/Resolute, SystemV/EST5, Canada/Central, Brazil/Acre, America/Cancun, America/Lima, America/Bahia_Banderas, US/Indiana-Starke, America/Rio_Branco, SystemV/CST6CDT, Jamaica, America/Merida, America/North_Dakota/New_Salem, America/Winnipeg]
ONLINE DEMO
Note: The regex pattern, \D specifies a non-digit character.
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
If I have correctly interpreted your question then try this,
final SimpleDateFormat date=
new SimpleDateFormat("EEE, MMM d, yyyy hh:mm:ss a z");
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("GMT time: " + date.format(currentTime));
In this you can add your offset. see if this helps you.