First, your example strings are not consistent: 8:30 pm
lacks a padding zero. I will assume that is a typo, and should have been 08:30 pm
.
Undesirable string formats
By the way, these input string formats are not desirable.
- A much better way is to use standard ISO 8601 formats.
- 12-hour clocks with AM/PM are troublesome. The standard formats use 24-hour clock, with hours 0-23.
- The standard notation for an interval is the pair of date-time strings separated by a slash: 2008-01-01T13:00/2008-01-01T13:56
.
Your input strings have another serious problem: No indication of offset-from-UTC or time zone. Without an offset or time zone, we must fall back to assuming generic 24-hour days. This ignores anomalies such as Daylight Saving Time (DST) that can result in 23 or 25 hour long days.
If you know the time zone intended for the incoming strings, pass that as a second argument to get a correct result.
java.time
This Question is quite old. Since then Java has supplanted the troublesome old date-time classes (Date
, Calendar
, etc.) with modern java.time classes. We use java.time in the example code below.
Example class
Here is a complete class for processing these strings as given in your Question. A Duration
is produced.
package javatimestuff;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
/**
*
* @author Basil Bourque
*/
public class DurationProcessor {
static final int SHORT = 30;
static final int LONG = 41;
static final DateTimeFormatter FORMATTER_LOCALDATETIME = DateTimeFormatter.ofPattern ( "uuuu-MM-dd hh:mm a" );
static final DateTimeFormatter FORMATTER_LOCALTIME = DateTimeFormatter.ofPattern ( "hh:mm a" );
static public Duration process ( String input ) {
return DurationProcessor.process ( input , ZoneOffset.UTC );
}
static public Duration process ( String input , ZoneId zoneId ) {
Duration d = Duration.ZERO; // Or maybe null. To be generated by the bottom of this code.
if ( null == input ) {
// …
System.out.println ( "ERROR - Passed null argument." );
return d;
}
if ( input.length () == 0 ) {
// …
System.out.println ( "ERROR - Passed empty string as argument." );
return d;
}
String inputModified = input.toUpperCase ( Locale.ENGLISH ); // Change `am` `pm` to `AM` `PM` for parsing.
String[] parts = inputModified.split ( " - " );
String inputStart = parts[ 0 ]; // A date-time sting.
String inputStop = parts[ 1 ]; // Either a date-time string or a time-only string (assume the same date).
ZonedDateTime start = null; // To be generated in this block of code.
try {
LocalDateTime ldt = LocalDateTime.parse ( inputStart , DurationProcessor.FORMATTER_LOCALDATETIME );
start = ldt.atZone ( zoneId );
} catch ( DateTimeParseException e ) {
// …
System.out.println ( "ERROR - The start failed to parse. inputStart: " + inputStart );
return d;
}
ZonedDateTime stop = null; // To be generated in this block of code.
switch ( input.length () ) {
case DurationProcessor.SHORT: // Example: "2008-01-01 01:00 pm - 01:56 pm"
try {
LocalTime stopTime = LocalTime.parse ( inputStop , DurationProcessor.FORMATTER_LOCALTIME );
stop = ZonedDateTime.of ( start.toLocalDate () , stopTime , zoneId );
} catch ( DateTimeParseException e ) {
// …
System.out.println ( "ERROR - The stop time failed to parse." );
return d;
}
break;
case DurationProcessor.LONG: // "2008-01-01 8:30 pm - 2008-01-02 09:30 am"
try {
LocalDateTime ldt = LocalDateTime.parse ( inputStop , DurationProcessor.FORMATTER_LOCALDATETIME );
stop = ldt.atZone ( zoneId );
} catch ( DateTimeParseException e ) {
// …
System.out.println ( "ERROR - The stop date-time failed to parse." );
return d;
}
break;
default:
// …
System.out.println ( "ERROR - Input string is of unexpected length: " + input.length () );
break;
}
d = Duration.between ( start , stop );
return d;
}
public static void main ( String[] args ) {
// Run with out time zone (assumes UTC).
Duration dShort = DurationProcessor.process ( "2008-01-01 01:00 pm - 01:56 pm" );
System.out.println ( "dShort: " + dShort );
Duration dLong = DurationProcessor.process ( "2008-01-01 08:30 pm - 2008-01-02 09:30 am" );
System.out.println ( "dLong: " + dLong );
// Run with specified time zone.
ZoneId z = ZoneId.of ( "America/Montreal" );
Duration dShortZoned = DurationProcessor.process ( "2008-01-01 01:00 pm - 01:56 pm" , z );
System.out.println ( "dShortZoned: " + dShortZoned );
Duration dLongZoned = DurationProcessor.process ( "2008-01-01 08:30 pm - 2008-01-02 09:30 am" , z );
System.out.println ( "dLongZoned: " + dLongZoned );
}
}
Note the main
method within the class for example usages.
First a pair of calls without specifying a time zone. So UTC and 24-hour days will be used.
Duration dShort = DurationProcessor.process ( "2008-01-01 01:00 pm - 01:56 pm" );
System.out.println ( "dShort: " + dShort );
Duration dLong = DurationProcessor.process ( "2008-01-01 08:30 pm - 2008-01-02 09:30 am" );
System.out.println ( "dLong: " + dLong );
Another pair of calls where we do specify the intended time zone.
ZoneId z = ZoneId.of ( "America/Montreal" );
Duration dShortZoned = DurationProcessor.process ( "2008-01-01 01:00 pm - 01:56 pm" , z );
System.out.println ( "dShortZoned: " + dShortZoned );
Duration dLongZoned = DurationProcessor.process ( "2008-01-01 08:30 pm - 2008-01-02 09:30 am" , z );
System.out.println ( "dLongZoned: " + dLongZoned );
Live code
See this class run in live code in IdeOne.com.
dShort: PT56M
dLong: PT13H
dShortZoned: PT56M
dLongZoned: PT13H
As noted elsewhere on this page, your output format using time-of-day style such as 00:56
is ambiguous and confusing, and should be avoided. The Duration
class instead uses standard ISO 8601 format for durations. Above, we see results of fifty-six minutes and thirteen minutes.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
- Java SE 8 and SE 9 and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.