Java:计算持续时间
我创建了以下代码来计算两个时间戳之间的持续时间,这两个时间戳可以有两种不同的格式:Java:计算持续时间,java,datetime,duration,Java,Datetime,Duration,我创建了以下代码来计算两个时间戳之间的持续时间,这两个时间戳可以有两种不同的格式: public class dummyTime { public static void main(String[] args) { try { convertDuration("2008-01-01 01:00 pm - 01:56 pm"); convertDuration("2008-01-01 8:30 pm - 2008-01-02 09:30 am");
public class dummyTime {
public static void main(String[] args) {
try {
convertDuration("2008-01-01 01:00 pm - 01:56 pm");
convertDuration("2008-01-01 8:30 pm - 2008-01-02 09:30 am");
} catch (Exception e) {
e.printStackTrace();
}
}
private static String convertDuration(String time) throws Exception {
String ts[] = time.split(" - ");
SimpleDateFormat formatNew = new SimpleDateFormat("HH:mm");
Date beg, end;
String duration = null;
beg = getDateTime(ts[0]);
end = getDateTime(ts[1], beg);
duration = formatNew.format(end.getTime() - beg.getTime());
System.out.println(duration + " /// " + time + " /// " + beg + " /// "
+ end);
return duration;
}
private static Date getDateTime(String dateTime) throws ParseException {
DateFormat formatOldDateTime = new SimpleDateFormat(
"yyyy-MM-dd hh:mm aa");
DateFormat formatOldTimeOnly = new SimpleDateFormat("hh:mm aa");
Date date = null;
try {
date = formatOldDateTime.parse(dateTime);
} catch (ParseException e) {
date = formatOldTimeOnly.parse(dateTime);
}
return date;
}
private static Date getDateTime(String dateTime, Date orig)
throws ParseException {
Date end = getDateTime(dateTime);
if (end.getYear() == 70) {
end.setYear(orig.getYear());
end.setMonth(orig.getMonth());
end.setDate(orig.getDate());
}
return end;
}
}
它生成的输出是:
01:56 /// 2008-01-01 01:00 pm - 01:56 pm /// Tue Jan 01 13:00:00 CET 2008 /// Tue Jan 01 13:56:00 CET 2008
14:00 /// 2008-01-01 8:30 pm - 2008-01-02 09:30 am /// Tue Jan 01 20:30:00 CET 2008 /// Wed Jan 02 09:30:00 CET 2008
我的问题是:
为什么结果总是错的
总是+1小时?
什么是更好的方法
一种无需修改即可识别时间戳的方法
一天70号看起来不太好
getDay和setDay函数是
我也不赞成。
非常感谢,这个问题已经让我疯狂了好几个小时。您正在格式化一天中的时间,而不是小时数和分钟数。由于您在冬季处于CET时区[中欧时间],因此与UTC GMT相差一小时
您可能希望使用日历而不是日期。或者。您正在格式化一天中的时间,而不是小时数和分钟数。由于您在冬季处于CET时区[中欧时间],因此与UTC GMT相差一小时 您可能希望使用日历而不是日期。或者 在我的电脑上,这是关闭了2个小时,因为我在GMT+2,而你可能在GMT+1。注意formatNew.formatend.getTime-beg.getTime;接收日期,即将您的56分钟视为1970-01-01-00:56:00 GMT+1。要快速解决此问题,请调用formatNew.setTimeZone TimeZone.getTimeZone GMT 对于第二项,您可以检查格式yyyy-MM-dd是否未能捕获解析错误,这就是您知道没有年份的原因 在我的电脑上,这是关闭了2个小时,因为我在GMT+2,而你可能在GMT+1。注意formatNew.formatend.getTime-beg.getTime;接收日期,即将您的56分钟视为1970-01-01-00:56:00 GMT+1。要快速解决此问题,请调用formatNew.setTimeZone TimeZone.getTimeZone GMT 对于第二项,您可以检查格式yyyy-MM-dd是否未能捕获解析错误,这就是您知道没有年份的原因
简单回答:使用SimpleDataFormat来格式化表示一天中没有日期的时间的值是不合适的 更详细的回答:Java时间值是从1970年1月1日午夜UTC开始的毫秒计数 SimpleDataFormat假定您给它一个有效的时间戳,并对日期和时间应用本地化转换。我怀疑您所在的地区距离欧洲大陆GMT还有一个小时,所以这就是为什么您看到的结果距离GMT还有一个小时 虽然您可以通过设置时区GMT愚弄SimpleDateFormat,但使用显式数学显示持续时间可能会更好:
int duration = 90;
System.out.printf("%02d:%02d", duration / 60, duration % 60);
简单回答:使用SimpleDataFormat来格式化表示一天中没有日期的时间的值是不合适的 更详细的回答:Java时间值是从1970年1月1日午夜UTC开始的毫秒计数 SimpleDataFormat假定您给它一个有效的时间戳,并对日期和时间应用本地化转换。我怀疑您所在的地区距离欧洲大陆GMT还有一个小时,所以这就是为什么您看到的结果距离GMT还有一个小时 虽然您可以通过设置时区GMT愚弄SimpleDateFormat,但使用显式数学显示持续时间可能会更好:
int duration = 90;
System.out.printf("%02d:%02d", duration / 60, duration % 60);
首先,示例字符串不一致:晚上8:30缺少填充零。我假设这是一个打字错误,应该是晚上8:30 不需要的字符串格式 顺便说一下,这些输入字符串格式是不可取的。 -更好的方法是使用标准格式。 -带有AM/PM的12小时时钟很麻烦。标准格式使用24小时时钟,0-23小时。 -间隔的标准表示法是由斜杠分隔的一对日期时间字符串:2008-01-01T13:00/2008-01-01T13:56 您的输入字符串还有另一个严重的问题:没有时间或时区的指示。如果没有偏移量或时区,我们必须退回到一般的24小时工作制。这忽略了异常情况,如夏令时DST,可能导致23或25小时长的一天 如果知道传入字符串的时区,请将其作为第二个参数传递,以获得正确的结果 java.time 这个问题很老了。从那时起,Java已经用现代的Java.time类取代了麻烦的旧日期时间类date、Calendar等。我们在下面的示例代码中使用java.time 示例类 下面是一个完整的类,用于处理问题中给出的这些字符串。产生了一种新的方法
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 );
}
}
注意类中的main方法,例如usages
首先是一对没有指定时区的呼叫。因此,将使用UTC和24小时工作制
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 );
另一对调用,其中我们指定了预期的时区
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 );
实时代码
看这个班的排练
dShort:PT56M
dLong:PT13H
Dshortzone:PT56M
分区名称:PT13H
如本页其他地方所述,使用时间样式(如00:56)的输出格式不明确且容易混淆,应避免使用。Duration类改为使用standard。上面,我们看到了56分13秒的结果
分钟
关于java.time
该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&
该项目现已启动,建议迁移到类
要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是
从哪里获得java.time类
后来
内置的。
标准JavaAPI的一部分,带有捆绑实现。
Java9添加了一些次要功能和修复。
和
大部分java.time功能都在中向后移植到Java6和Java7。
该项目特别针对Android采用了上述Three-Ten Backport。
看见
该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。您可以在这里找到一些有用的类,例如、、和。首先,您的示例字符串不一致:8:30 pm缺少填充零。我假设这是一个打字错误,应该是晚上8:30 不需要的字符串格式 顺便说一下,这些输入字符串格式是不可取的。 -更好的方法是使用标准格式。 -带有AM/PM的12小时时钟很麻烦。标准格式使用24小时时钟,0-23小时。 -间隔的标准表示法是由斜杠分隔的一对日期时间字符串:2008-01-01T13:00/2008-01-01T13:56 您的输入字符串还有另一个严重的问题:没有时间或时区的指示。如果没有偏移量或时区,我们必须退回到一般的24小时工作制。这忽略了异常情况,如夏令时DST,可能导致23或25小时长的一天 如果知道传入字符串的时区,请将其作为第二个参数传递,以获得正确的结果 java.time 这个问题很老了。从那时起,Java已经用现代的Java.time类取代了麻烦的旧日期时间类date、Calendar等。我们在下面的示例代码中使用java.time 示例类 下面是一个完整的类,用于处理问题中给出的这些字符串。产生了一种新的方法
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 );
}
}
注意类中的main方法,例如usages
首先是一对没有指定时区的呼叫。因此,将使用UTC和24小时工作制
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 );
另一对调用,其中我们指定了预期的时区
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 );
实时代码
看这个班的排练
dShort:PT56M
dLong:PT13H
Dshortzone:PT56M
分区名称:PT13H
如本页其他地方所述,使用时间样式(如00:56)的输出格式不明确且容易混淆,应避免使用。Duration类改为使用standard。上面,我们看到了56分钟和13分钟的结果
关于java.time
该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&
该项目现已启动,建议迁移到类
要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是
从哪里获得java.time类
后来
内置的。
标准JavaAPI的一部分,带有捆绑实现。
Java9添加了一些次要功能和修复。
和
大部分java.time功能都在中向后移植到Java6和Java7。
该项目特别针对Android采用了上述Three-Ten Backport。
看见
该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。您可以在这里找到一些有用的类,如、、和。输入不一致。一天中的大多数时间值都有一个填充零,但8:30 pm忽略了它。输入不一致。一天中的大多数时间值都有填充零,但8:30 pm忽略了这一点。