I gets following strings from FE:
1m
5M
3D
30m
2h
1Y
3W
It corresponds to 1 minute, 5 months,3 days, 30 minutes, 2 hours, 1 year, 3 weeks.
Is there mean in java to parse it?
I want to manipulate(add/minus) with Instant(or LocalDatetTime). Is there way to do it in java?
Period
& Duration
I consider the following solution simple and pretty general (not fully general).
public static TemporalAmount parse(String feString) {
if (Character.isUpperCase(feString.charAt(feString.length() - 1))) {
return Period.parse("P" + feString);
} else {
return Duration.parse("PT" + feString);
}
}
It seems that your date-based units (year, month, week, day) are denoted with uppercase abbreviations (Y
, M
, W
and D
) while the time-based ones (hour and minute) are lowercase (h
and m
). So I test the case of the last character of the string to decide whether to parse into a Period
or a Duration
. I exploit the fact that both of Period.parse
and Duration.parse
accept the letters in either case.
You wanted to add or subtract the durations to and from Instant
or LocalDateTime
. This works in most cases. Let’s see:
String[] timeAmountStrings = { "1m", "5M", "3D", "30m", "2h", "1Y", "3W" };
LocalDateTime base = LocalDateTime.of(2019, Month.MARCH, 1, 0, 0);
for (String tas : timeAmountStrings) {
TemporalAmount amount = parse(tas);
System.out.println("String: " + tas + " parsed: " + amount + " added: " + base.plus(amount));
try {
System.out.println("Added to Instant: " + Instant.EPOCH.plus(amount));
} catch (DateTimeException dte) {
System.out.println("Adding to Instant didn’t work: " + tas + ' ' + dte);
}
System.out.println();
}
Output:
String: 1m parsed: PT1M added: 2019-03-01T00:01 Added to Instant: 1970-01-01T00:01:00Z String: 5M parsed: P5M added: 2019-08-01T00:00 Adding to Instant didn’t work: 5M java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Months String: 3D parsed: P3D added: 2019-03-04T00:00 Added to Instant: 1970-01-04T00:00:00Z String: 30m parsed: PT30M added: 2019-03-01T00:30 Added to Instant: 1970-01-01T00:30:00Z String: 2h parsed: PT2H added: 2019-03-01T02:00 Added to Instant: 1970-01-01T02:00:00Z String: 1Y parsed: P1Y added: 2020-03-01T00:00 Adding to Instant didn’t work: 1Y java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Years String: 3W parsed: P21D added: 2019-03-22T00:00 Added to Instant: 1970-01-22T00:00:00Z
We see that adding to LocalDateTime
works in all cases. Adding to Instant
works in most cases, only we cannot add a period of months or years to it.
The Answer by Ole V.V. is correct, clever, and well-done. I would take it one step further.
PeriodDuration
The ThreeTen-Extra project adds functionality to the java.time classes built into Java 8 and later. Among its offerings is the PeriodDuration
class, combining a Period
(years-month-days) with a Duration
(hours-minutes-seconds-nanos).
By the way, let me caution you about combining the two concepts. While that may seem fine intuitively, if you ponder a bit you may see it as problematic depending on your business logic.
Anyways, let’s adapt the code seen in the other Answer.
Period
, adding that result to our PeriodDuration
object.Duration
, and add the result to our PeriodDuration
object.Code:
List < String > inputs = List.of( "1m" , "5M" , "3D" , "30m" , "2h" , "1Y" , "3W" );
PeriodDuration pd = PeriodDuration.ZERO;
for ( String input : inputs )
{
String s = input.trim();
String lastLetter = s.substring( s.length() - 1 );
int codepoint = Character.codePointAt( lastLetter , 0 );
if ( Character.isUpperCase( codepoint ) )
{
String x = "P" + s;
Period p = Period.parse( x );
pd = pd.plus( p );
} else
{ // Else, lowercase.
String x = "PT".concat( s ).toUpperCase();
Duration d = Duration.parse(x );
pd = pd.plus( d );
}
}
System.out.println( "pd.toString(): " + pd );
P1Y5M24DT2H31M
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With