我想拍两次(自纪元以来几秒钟),并以两种格式显示两者之间的差异:
2分钟
1小时15分钟
3小时9分钟
1分钟前
1小时,2分钟前
我该怎么做到这一点?
因为每个人都喊"YOODAA !!!" 但没有人发布一个具体的例子,这是我的贡献.
你也可以用Joda-Time做到这一点.使用Period
代表一个时期.要格式化所需人类表示中的句点,请使用PeriodFormatter
您可以构建的句点PeriodFormatterBuilder
.
这是一个启动示例:
DateTime myBirthDate = new DateTime(1978, 3, 26, 12, 35, 0, 0); DateTime now = new DateTime(); Period period = new Period(myBirthDate, now); PeriodFormatter formatter = new PeriodFormatterBuilder() .appendYears().appendSuffix(" year, ", " years, ") .appendMonths().appendSuffix(" month, ", " months, ") .appendWeeks().appendSuffix(" week, ", " weeks, ") .appendDays().appendSuffix(" day, ", " days, ") .appendHours().appendSuffix(" hour, ", " hours, ") .appendMinutes().appendSuffix(" minute, ", " minutes, ") .appendSeconds().appendSuffix(" second", " seconds") .printZeroNever() .toFormatter(); String elapsed = formatter.print(period); System.out.println(elapsed + " ago");
更清晰简洁,不是吗?
这打印到现在
32 years, 1 month, 1 week, 5 days, 6 hours, 56 minutes, 24 seconds ago
(咳嗽,老,咳)
Date start = new Date(1167627600000L); // JANUARY_1_2007 Date end = new Date(1175400000000L); // APRIL_1_2007 long diffInSeconds = (end.getTime() - start.getTime()) / 1000; long diff[] = new long[] { 0, 0, 0, 0 }; /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24)); System.out.println(String.format( "%d day%s, %d hour%s, %d minute%s, %d second%s ago", diff[0], diff[0] > 1 ? "s" : "", diff[1], diff[1] > 1 ? "s" : "", diff[2], diff[2] > 1 ? "s" : "", diff[3], diff[3] > 1 ? "s" : ""));
Yup唤醒了我的死者,但这里是基于@mtim发布的代码的改进实现,因为这个线程几乎在搜索之上,所以我正在弄乱困的空洞,
public static String getFriendlyTime(Date dateTime) { StringBuffer sb = new StringBuffer(); Date current = Calendar.getInstance().getTime(); long diffInSeconds = (current.getTime() - dateTime.getTime()) / 1000; /*long diff[] = new long[]{0, 0, 0, 0}; /* sec * diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); /* min * diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; /* hours * diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; /* days * diff[0] = (diffInSeconds = (diffInSeconds / 24)); */ long sec = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); long min = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; long hrs = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; long days = (diffInSeconds = (diffInSeconds / 24)) >= 30 ? diffInSeconds % 30 : diffInSeconds; long months = (diffInSeconds = (diffInSeconds / 30)) >= 12 ? diffInSeconds % 12 : diffInSeconds; long years = (diffInSeconds = (diffInSeconds / 12)); if (years > 0) { if (years == 1) { sb.append("a year"); } else { sb.append(years + " years"); } if (years <= 6 && months > 0) { if (months == 1) { sb.append(" and a month"); } else { sb.append(" and " + months + " months"); } } } else if (months > 0) { if (months == 1) { sb.append("a month"); } else { sb.append(months + " months"); } if (months <= 6 && days > 0) { if (days == 1) { sb.append(" and a day"); } else { sb.append(" and " + days + " days"); } } } else if (days > 0) { if (days == 1) { sb.append("a day"); } else { sb.append(days + " days"); } if (days <= 3 && hrs > 0) { if (hrs == 1) { sb.append(" and an hour"); } else { sb.append(" and " + hrs + " hours"); } } } else if (hrs > 0) { if (hrs == 1) { sb.append("an hour"); } else { sb.append(hrs + " hours"); } if (min > 1) { sb.append(" and " + min + " minutes"); } } else if (min > 0) { if (min == 1) { sb.append("a minute"); } else { sb.append(min + " minutes"); } if (sec > 1) { sb.append(" and " + sec + " seconds"); } } else { if (sec <= 1) { sb.append("about a second"); } else { sb.append("about " + sec + " seconds"); } } sb.append(" ago"); /*String result = new String(String.format( "%d day%s, %d hour%s, %d minute%s, %d second%s ago", diff[0], diff[0] > 1 ? "s" : "", diff[1], diff[1] > 1 ? "s" : "", diff[2], diff[2] > 1 ? "s" : "", diff[3], diff[3] > 1 ? "s" : ""));*/ return sb.toString(); }
它显然可以改善.基本上它试图让时间跨度更友好,但有一些限制,即如果时间过去(参数)将来会出现奇怪的行为,并且它仅限于几天,几小时和几秒(几个月和几年没有处理,以便其他人可以;-).
样本输出是:
大约一秒钟前
8分34秒前
一小时四分钟前
一天前
29天前
一年零三个月前
,干杯:D
编辑:现在支持数月和数年:P
我建议你看看HumanTime
其他答案可能是正确的,但已过时.Java中令人烦恼的旧日期时间类现在已经遗留下来,取而代之的是java.time类.
同样,现在处于维护模式的Joda-Time项目建议迁移到java.time类.
使用java.timeInstant
两次(自纪元以来的秒数)
在java.time中,我们用UTC表示时间轴上的时刻Instant
.我将假设您的纪元与java.time相同,这是UTC(1970-01-01T00:00:00Z
)1970年的第一个时刻.请注意,Instant
a的分辨率为纳秒.Instant
如问题中所述,便利工厂方法从整秒开始构造.
Instant start = Instant.ofEpochSecond( … ); Instant stop = Instant.ofEpochSecond( … );
这里我们使用当前时刻和几分钟后.
Instant start = Instant.now() ; Instant stop = start.plusSeconds( TimeUnit.MINUTES.toSeconds( 7L ) ) ; // Seven minutes as a number of seconds.
Duration
在java.time中,未附加到时间轴的时间跨度以两种方式表示.几年 - 月 - 天,我们有Period
.我们有几小时 - 几分钟Duration
.
Duration duration = Duration.between( start , stop );
使用半开放方法计算经过的时间.在这种方法中,开头是包容性的,而结尾是独占的.这种方法通常用于日期时间工作.我相信在您的代码库中始终如一地使用这种方法将有助于消除由于含糊不清而导致的错误和误解,并且可以减轻编程的认知负担.
在ISO 8601标准定义表示日期时间值作为文本许多实际的格式.这些格式旨在避免歧义,易于通过机器解析,并且可以直观地跨文化阅读.
在解析和生成字符串时,java.time类默认使用这些格式.
对于时间没有附加到时间轴上的跨度,该标准定义的格式的PnYnMnDTnHnMnS
地方P
标志着开始和T
分离任何年-月-日从任何小时,分钟,秒.所以一个半小时PT1H30M
.
在我们的示例代码中使用七分钟:
String outputStandard = duration.toString();
PT7M
请参阅IdeOne.com上运行的上述示例代码.
我建议尽可能坚持使用这些格式,当然在交换或序列化日期时间数据时,还要考虑在适当的用户界面中使用,并且可以训练用户使用它们.
我建议永远不要使用时钟格式(例如:01:30为一小时),因为该格式与时间完全不一致.
如果您必须拼出问题中所示的时间范围,则需要自己构建文本.
用于Period
,调用getYears
,getMonths
以及getDays
检索每个部分.
奇怪的是,Duration
类缺乏这样干将的Java 8,但在获得了他们的Java 9及更高版本:toDaysPart
,toHoursPart
,toMinutesPart
,toSecondsPart
,和toNanosPart
.
一些示例代码,简单和基本,以帮助您入门.
int days = duration.toDaysPart() ; int hours = duration.toHoursPart() ; int minutes = duration.toMinutesPart() ; int seconds = duration.toSecondsPart() ; int nanos = duration.toNanosPart() ; StringBuilder sb = new StringBuilder( 100 ); if( days != 0 ) { sb.append( days + " days" ) ; }; if( hours != 0 ) { sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text. sb.append( hours + " hours" ) ; }; if( minutes != 0 ) { sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text. sb.append( minutes + " minutes" ) ; }; if( seconds != 0 ) { sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text. sb.append( seconds + " seconds" ) ; }; if( nanos != 0 ) { sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text. sb.append( nanos + " nanos" ) ; }; String output = sb.toString();
或者也许您可以DateTimeFormatterBuilder
按照Balus C的答案中使用Joda-Time显示的方式编写更流畅的代码.
该java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date
,Calendar
,和SimpleDateFormat
.
现在处于维护模式的Joda-Time项目建议迁移到java.time类.
要了解更多信息,请参阅Oracle教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.
从哪里获取java.time类?
Java SE 8和 SE 9及更高版本
内置.
带有捆绑实现的标准Java API的一部分.
Java 9增加了一些小功能和修复.
Java SE 6和 SE 7
许多java.time功能都被反向移植到ThreeTen-Backport中的 Java 6和7 .
Android的
所述ThreeTenABP项目适应ThreeTen-反向移植为Android(上面提到的)特异性.
请参阅如何使用ThreeTenABP ....
该ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在这里找到一些有用的类,例如Interval
,YearWeek
和YearQuarter
,以及更多.