如何计算“时间之前”在Java中?
在 Ruby on Rails 中,有一个功能允许您获取任何日期并打印出它是“多久以前”的。
例如:
8 minutes ago
8 hours ago
8 days ago
8 months ago
8 years ago
在 Java 中是否有一种简单的方法可以做到这一点?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
查看 PrettyTime 库。
使用起来非常简单:
您还可以传入国际化消息的区域设置:
正如注释中所述,Android 将此功能内置到
android.text.format.DateUtils
类。Take a look at the PrettyTime library.
It's quite simple to use:
You can also pass in a locale for internationalized messages:
As noted in the comments, Android has this functionality built into the
android.text.format.DateUtils
class.您是否考虑过 TimeUnit 枚举?它对于这种事情非常有用
Have you considered the TimeUnit enum? It can be pretty useful for this kind of thing
我采用 RealHowTo 和 Ben J 的答案并制作我自己的版本:
它将打印以下内容
I take RealHowTo and Ben J answers and make my own version:
which will print the following
这是基于 RealHowTo 的回答,所以如果你喜欢它,也给他/她一些爱。
这个清理版本允许您指定您可能感兴趣的时间范围。
它对“和”部分的处理也略有不同。我经常发现,当使用分隔符连接字符串时,跳过复杂的逻辑并在完成后删除最后一个分隔符通常会更容易。
尝试一下的小代码:
它将输出以下内容:
如果有人需要它,这里有一个类可以转换任何像上面这样的字符串 回到毫秒。它对于允许人们在可读文本中指定各种事物的超时非常有用。
This is based on RealHowTo's answer so if you like it, give him/her some love too.
This cleaned up version allows you to specify the range of time you might be interested in.
It also handles the " and " part a little differently. I often find when joining strings with a delimiter it's ofter easier to skip the complicated logic and just delete the last delimiter when you're done.
Little code to give it a whirl:
Which will output the following:
And in case anyone ever needs it, here's a class that will convert any string like the above back into milliseconds. It's pretty useful for allowing people to specify timeouts of various things in readable text.
有一个简单的方法可以做到这一点:
假设您想要 20 分钟前的时间:
就是这样..
there's a simple way to do this:
let's say you want the time 20 minutes ago:
that's it..
关于内置解决方案:
Java 没有任何对格式化相对时间的内置支持,Java-8 及其新包
java.time< /代码>。如果您只需要英语而不需要其他任何东西,那么手工解决方案可能是可以接受的 - 请参阅@RealHowTo的答案(尽管它有一个很大的缺点,即不考虑将即时增量转换为本地时间的时区)单位!)。无论如何,如果您想避免本地开发的复杂解决方法,特别是对于其他语言环境,那么您需要一个外部库。
在后一种情况下,我建议使用我的库 Time4J (或 Android 上的 Time4A)。它提供最大的灵活性和最国际化的功能。 net.time4j.PrettyTime 类有七个方法
printRelativeTime ...(...)
为此目的。使用测试时钟作为时间源的示例:另一个使用
java.time.Instant
作为输入的示例:该库通过其最新版本 (v4.17) 支持 80 种语言一些特定国家/地区的语言环境(特别是西班牙语、英语、阿拉伯语、法语)。 i18n-data 主要基于最新的 CLDR 版本 v29。使用此库的其他重要原因包括对复数规则的良好支持(这些规则通常与其他语言环境中的英语不同)、缩写格式样式(例如:“1 sec”前”)以及考虑时区的表达方式。 Time4J 甚至在相对时间的计算中意识到诸如闰秒之类的奇特细节(不是很重要,但它形成了与期望范围相关的消息)。 与 Java-8 的兼容性的存在是由于
java.time.Instant
或java.time.Period
等类型易于使用的转换方法。有什么缺点吗?只有两个。
(紧凑)替代方案:
如果您正在寻找更小的解决方案并且不需要那么多功能并且愿意容忍与 i18n-data 相关的可能的质量问题,那么:
我会推荐ocpsoft/PrettyTime (支持实际上 32 种语言(很快 34 种?),仅适用于
java.util.Date
- 请参阅 @ataylor 的答案)。不幸的是,具有庞大社区背景的行业标准 CLDR(来自 Unicode 联盟)并不是 i18n 数据的基础,因此数据的进一步增强或改进可能需要一段时间......如果您使用的是 Android,则帮助程序类android.text.format.DateUtils 是一个精简的内置替代方案(请参阅此处的其他评论和答案,其缺点是它不支持数年和数月。而且我确信只有极少数人们喜欢这个辅助类的 API 风格。
如果您是 Joda-Time 的粉丝,那么您可以看看它的类PeriodFormat (在 v2.9.4 版本中支持 14 种语言,另一方面:Joda-Time 肯定也不紧凑,所以我在这里提到它只是为了完整性)这个库不是真正的答案,因为不支持相对时间。您至少需要附加文字“前”(并手动从生成的列表格式中删除所有较低的单位 - 与 Time4J 或 Android-DateUtils 不同,它没有对缩写或从相对时间自动切换的特殊支持。到绝对时间表示。与 PrettyTime 一样,它完全依赖于 Java 社区私人成员对其 i18n 数据未经证实的贡献。
About built-in solutions:
Java does not have any built-in support for formatting relative times, also not Java-8 and its new package
java.time
. If you only need English and nothing else then and only then a hand-made solution might be acceptable - see the answer of @RealHowTo (although it has the strong disadvantage to not take into account the timezone for the translation of instant deltas to local time units!). Anyway, if you want to avoid home-grown complex workarounds especially for other locales then you need an external library.In latter case, I recommend to use my library Time4J (or Time4A on Android). It offers greatest flexibility and most i18n-power. The class net.time4j.PrettyTime has seven methods
printRelativeTime...(...)
for this purpose. Example using a test clock as time source:Another example using
java.time.Instant
as input:This library supports via its latest version (v4.17) 80 languages and also some country-specific locales (especially for Spanish, English, Arabic, French). The i18n-data is mainly based on the newest CLDR-version v29. Other important reasons why to use this library are good support for plural rules (which are often different from English in other locales), abbreviated format style (for example: "1 sec ago") and expressive ways for taking into account timezones. Time4J is even aware of such exotic details like leap seconds in calculations of relative times (not really important but it forms a message related to the expectation horizon). The compatibility with Java-8 exists due to easily available conversion methods for types like
java.time.Instant
orjava.time.Period
.Are there any drawbacks? Only two.
(Compact) alternatives:
If you look for a smaller solution and don't need so many features and are willing to tolerate possible quality issues related to i18n-data then:
I would recommend ocpsoft/PrettyTime (support for actually 32 languages (soon 34?) suitable for work with
java.util.Date
only - see the answer of @ataylor). The industry standard CLDR (from Unicode consortium) with its big community background is unfortunately not a base of the i18n-data so further enhancements or improvements of data can take a while...If you are on Android then the helper class android.text.format.DateUtils is a slim built-in alternative (see other comments and answers here, with the disadvantage that it has no support for years and months. And I am sure that only very few people like the API-style of this helper class.
If you are a fan of Joda-Time then you can look at its class PeriodFormat (support for 14 languages in release v2.9.4, on the other side: Joda-Time is surely not compact, too, so I mention it here just for completeness). This library is not a real answer because relative times are not supported at all. You will need to append the literal " ago" at least (and manually stripping off all lower units from generated list formats - awkward). Unlike Time4J or Android-DateUtils, it has no special support for abbreviations or automatic switching from relative times to absolute time representations. Like PrettyTime, it is totally dependent on the unconfirmed contributions of private members of the Java-community to its i18n-data.
java.time
Habsq 的回答有正确的想法,但方法错误。
对于不附加到年-月-日时间线的时间跨度,请使用
期间
。对于表示与日历和小时-分钟-秒无关的 24 小时时间段的日期,请使用持续时间
。混合这两种尺度几乎没有任何意义。Duration
首先使用 UTC 获取当前时刻,使用
即时< /code>
类。
生成小时、分钟和秒的文本。
转储到控制台。
Period
首先获取当前日期。
时区对于确定日期至关重要。对于任何特定时刻,全球各地的日期都会因地区而异。例如,法国巴黎午夜过后几分钟是新的一天,但仍然是“昨天” ”在魁北克省蒙特利尔。
如果未指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能在运行时随时更改(!),因此您的结果可能会有所不同。最好明确指定您想要/预期的时区作为参数。如果重要,请与您的用户确认该区域。
以
大陆/地区
格式指定正确的时区名称,例如美洲/蒙特利尔
、非洲/卡萨布兰卡
或太平洋/奥克兰
。切勿使用 2-4 个字母的缩写,例如EST
或IST
,因为它们不是真实时区,不是标准化的,甚至不是唯一的(!)。重新创建八天、八月和几年前的日期。
计算经过的时间。
搭建一串“很久以前”的作品。
转储到控制台。
关于 java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧遗留日期时间类,例如
java.util.Date
,日历
,&SimpleDateFormat
。要了解更多信息,请参阅 Oracle 教程 。并在 Stack Overflow 上搜索许多示例和解释。规范为 JSR 310。
Joda-Time 项目,现已在 维护模式,建议迁移到 java.time 类。
您可以直接与数据库交换java.time对象。使用符合 JDBC 驱动程序 jeps/170" rel="noreferrer">JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 类。
从哪里获取 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是 java.time 未来可能添加的内容的试验场。您可能会在这里找到一些有用的类,例如
Interval
,YearWeek
,YearQuarter
,以及更多。java.time
The Answer by Habsq has the right idea but the wrong methods.
For a span-of-time unattached to the timeline on the scale of years-months-days, use
Period
. For days meaning 24-hour chunks of time unrelated to calendar and hours-minutes-seconds, useDuration
. Mixing the two scales rarely makes any sense.Duration
Start by fetching the current moment as seen in UTC, using the
Instant
class.Generate text for hours, minutes, and seconds.
Dump to console.
Period
Start by getting the current date.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument. If critical, confirm the zone with your user.
Specify a proper time zone name in the format of
Continent/Region
, such asAmerica/Montreal
,Africa/Casablanca
, orPacific/Auckland
. Never use the 2-4 letter abbreviation such asEST
orIST
as they are not true-time zones, not standardized, and not even unique(!).Recreate a date eight days, months, and years ago.
Calculate elapsed time.
Build the string of "time ago" pieces.
Dump to console.
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
.To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for
java.sql.*
classes.Where to obtain the java.time classes?
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.java.time
使用 java.time Java 8 及更高版本中内置的框架。
java.time
Using the java.time framework built into Java 8 and later.
根据这里的一堆答案,我为我的用例创建了以下内容。
用法示例:
Based on a bunch of answers here, I created the following for my use case.
Example usage:
如果您正在寻找简单的“今天”、“昨天”或“x 天前”。
If you looking for a simple "Today", "Yesterday" or "x days ago".
对于安卓:
For Android:
我创建了一个简单的 Java timeago 端口 jquery-timeago 插件可以满足您的要求。
I created a simple Java timeago port of the jquery-timeago plug-in that does what you are asking for.
如果您正在开发 Android 应用程序,它会提供实用程序类 DateUtils 满足所有此类要求。看一下 DateUtils #getRelativeTimeSpanString() 实用方法。
的文档
来自CharSequence getRelativeTimeSpanString (long time, long now, long minResolution)
您将把
timestamp
作为 time 传递,将System.currentTimeMillis()
作为 now 传递。minResolution
允许您指定要报告的最小时间跨度。In case you're developing an app for Android, it provides the utility class DateUtils for all such requirements. Take a look at the DateUtils#getRelativeTimeSpanString() utility method.
From the docs for
CharSequence getRelativeTimeSpanString (long time, long now, long minResolution)
You'll be passing your
timestamp
as time andSystem.currentTimeMillis()
as now. TheminResolution
lets you specify the minimum timespan to report.joda-time 包具有 期间。您可以使用周期和日期时间进行算术运算。
来自文档:
The joda-time package, has the notion of Periods. You can do arithmetic with Periods and DateTimes.
From the docs:
您可以使用此函数来计算 time ago
1) 这里 time_ago 的单位是微秒
You Can use this function to calculate time ago
1) Here time_ago is in microsecond
在 Kotlin 中调用
来
val String = timeAgo(unixTimeStamp)
获取之前的时间
}
Call
val String = timeAgo(unixTimeStamp)
to get the time ago in Kotlin
它并不漂亮......但我能想到的最接近的是使用 Joda-Time (如这篇文章中所述:如何使用 Joda Time 计算从现在开始经过的时间?
It's not pretty...but the closest I can think of is using Joda-Time (as described in this post: How to calculate elapsed time from now with Joda Time?
如果我们考虑性能,这是一个更好的代码。它减少了计算次数。
原因
仅当秒数大于 60 时才计算分钟,仅当分钟数大于 60 时才计算小时,依此类推...
This is a better code if we consider performance.It reduces the number of calculations.
Reason
Minutes are calculated only if the number of seconds is greater than 60 and Hours are calculated only if the number of minutes is greater than 60 and so on...
java.time
您可以使用
java.time.Duration
和java.time.Period
仿照 ISO-8601 标准,并作为 JSR-310 实现。 Java-9 引入了一些更方便的方法。Duration
计算基于时间的数量或时间量。可以使用基于持续时间的单位来访问它,例如纳秒、秒、分钟和小时。此外,DAYS 可以使用单位并被视为恰好等于 24 小时,从而忽略夏令时影响。Period
计算基于日期的时间量。可以使用基于时间段的单位(例如天、月和年)来访问它。演示:
输出:
如果您在
UTC
处有两个时刻,则可以使用Instant
而不是LocalDateTime
例如输出:
演示
Period
:输出:
了解现代日期时间 API 跟踪:日期时间。
java.time
You can use
java.time.Duration
andjava.time.Period
which are modelled on ISO-8601 standards and were introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.Duration
to calculate a time-based quantity or amount of time. It can be accessed using duration-based units, such as nanoseconds, seconds, minutes and hours. In addition, the DAYS unit can be used and is treated as exactly equal to 24 hours, thus ignoring daylight savings effects.Period
to calculate a date-based amount of time. It can be accessed using period-based units, such as days, months and years.Demo:
Output:
If you have two moments at
UTC
, you can useInstant
instead ofLocalDateTime
e.g.Output:
Demo on
Period
:Output:
Learn about the modern date-time API from Trail: Date Time.
经过长时间的研究我发现了这一点。
After long research i found this.
您可以使用Java的库RelativeDateTimeFormatter,它正是这样做的:
You can use Java's Library RelativeDateTimeFormatter, it does exactly that:
SQL 时间戳到当前已用时间。设置您自己的时区。
注意1:这将处理单数/复数。
注2:这是使用 Joda 时间
SQL timestamp to now elapsed time. Set your own timezone.
NOTE1: This will handle singular/plural.
NOTE2: This is using Joda time
适用于 Android
正如拉维所说,但由于很多人想要只是复制粘贴这里的东西。
对有更多时间的人的解释
前任。我从服务器获取以下格式的数据
2016 年 1 月 27 日星期三 09:32:35 GMT [这可能不是你的情况]
这被翻译成
SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
我怎么知道呢?阅读 此处的文档。
然后在解析它之后我得到一个日期。我在 getRelativeTimeSpanString 中输入的日期(没有任何附加参数对我来说很好,默认为分钟)
如果您没有找出正确的解析字符串,您将得到一个异常 strong>,类似字符 5 的异常。 查看字符 5,并更正您的初始解析字符串。。您可能会遇到另一个异常,请重复这些步骤,直到获得正确的公式。
For Android
Exactly like Ravi said, but since lots of people want to just copy-paste the thing here it is.
Explanation for people that have more time
Ex. I get the data from a server in the format
Wed, 27 Jan 2016 09:32:35 GMT [this is probably NOT your case]
this is translated into
SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
how do I know it? Read the documentation here.
Then after I parse it I get a date. that date I put in the getRelativeTimeSpanString (without any additional parameters is fine by me, to default to minutes)
You WILL get an exception if you didn't figure out the correct parsing String, Something like exception at character 5. Look at character 5, and correct your initial parsing string.. You might get another exception, repeat these steps until you have the correct formula.
这是我的 Java 实现
Here is my Java Implementation of this
这对我有用
it works for me
这是非常基本的脚本。它很容易即兴创作。
结果:(XXX 小时前),或(XX 天前/昨天/今天)
This is the very basic script. its easy to improvized.
Result : (XXX Hours Ago), or (XX Days Ago/Yesterday/Today)
为此,我已经完成了
刚刚、几秒前、几分钟前、几小时前、几天前、几周前、几个月前、几年前
,在此示例中,您可以像2018-09 一样解析日期-05T06:40:46.183Z
这个或任何其他类似的中添加以下值尝试下面
在 string.xml java 代码
for this I've done
Just Now, seconds ago, min ago, hrs ago, days ago, weeks ago, months ago, years ago
in this example you can parse date like2018-09-05T06:40:46.183Z
this or any other like belowadd below value in string.xml
java code try below
我正在使用 Instant、Date 和 DateTimeUtils。
将数据(日期)以String类型存储在数据库中,然后转换为Instant。
I'm using the Instant, Date and DateTimeUtils.
The data (date) which is stored in the database in type of String and then convert to become Instant.
以下解决方案均采用纯 Java:
选项 1:不舍入,仅显示最大时间容器
以下函数将仅显示最大时间容器,例如,如果真实的经过时间为
“1 个月 14 天前”< /code>,该函数只会显示
“1个月前”
。此函数也将始终向下舍入,因此相当于“50 天前”
的时间将显示为“1 个月”
选项 2:使用舍入
只需将您的时间容器包装起来即可想要使用 Math.round(...) 语句进行舍入,因此如果您想将
50 天
舍入为2 个月
,请修改long Months =天 / 30
到长月 = Math.round(days / 30.0)
The following solutions are all in pure Java:
Option 1: No rounding and only largest time container
The following function will only display the largest time container, for example, if the true elapsed time is
"1 month 14 days ago"
, this function will only display"1 month ago"
. This function will also always round down, so a time equivalent to"50 days ago"
will display as"1 month"
Option 2: With rounding
Simply wrap the time container you'd like to round with a Math.round(...) statement, so if you wanted to round
50 days
to2 months
, modifylong months = days / 30
tolong months = Math.round(days / 30.0)