有没有一种快速,低垃圾的方式来做到这一点?我不能只做简单的模数算术,因为这不能解释闰秒和其他日期/时间有趣的业务。如何将Java时代以来的秒数转换为小时/分钟/秒?
回答
这是一个快速,零垃圾的解决方案。在每个调用中不要创建Calendar
的新实例是非常重要的,因为它是一个相当重的对象,需要448个字节的堆并且几乎需要微妙的初始化(Java 6,64位HotSpot,OS X)。
HmsCalculator
旨在用于单个线程(每个线程必须使用不同的实例)。
public class HmsCalculator
{
private final Calendar c = Calendar.getInstance();
public Hms toHms(long t) { return toHms(t, new Hms()); }
public Hms toHms(long t, Hms hms) {
c.setTimeInMillis(t*1000);
return hms.init(c);
}
public static class Hms {
public int h, m, s;
private Hms init(Calendar c) {
h = c.get(HOUR_OF_DAY); m = c.get(MINUTE); s = c.get(SECOND);
return this;
}
public String toString() { return String.format("%02d:%02d:%02d",h,m,s); }
}
public static void main(String[] args) {
System.out.println(new HmsCalculator().toHms(
System.currentTimeMillis()/1000));
}
}
P.S.我没有粘贴所有这些静态导入(无聊)。
我不能只是做简单的模数算术,因为它不占用闰秒和其他日期/时间有趣的业务。
的Java 不占闰秒一般 - 或者更确切地说,正式这是走上讲台,但我不相信这是在任何的共同生产平台上实现。你确定你需要来计算闰秒吗?如果你这样做,你应该能够做一个简单的基于表的查询秒数来添加或删除,这取决于你的数据源是什么以及你希望它反映什么。
至于“其他日期/时间有趣的业务” - 我不认为有是这个特定的计算任何有趣的业务。例如,时区自从时代开始经历的时间是不相关的。
时区与时代以来秒无关,但转换为本地HH:MM:SS时并非无关紧要。不过,这只是一个不变的抵消,所以没有什么大不了的。 –
@ user939259:我认为你的意思是“小时,分钟,秒”,因为这个时代......你的问题很不清楚。如果你的意思是你想将时间戳转换为本地时间,那么你可以使用'java.util.Date'和'java.util.Calendar',或者最好是Joda Time。 –
与假设 “划时代” 你的意思是01-01-1970 00:00:00 GMT:
long secondsSinceEpoch = ...;
// The constructor of Date expects milliseconds
// since 01-01-1970, 00:00:00 GMT
Date date = new Date(secondsSinceEpoch * 1000L);
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
System.out.println(df.format(date));
低垃圾?我想不是。 –
@MarkoTopolnik解释?你创建的唯一的东西是一个Date对象(不考虑用SimpleDateFormat格式化)。这不是很贵。 – Jesper
Date,SimpleDateFormat,两者的内部结构。这并不是那么简单,结果仍然是一个字符串而不是数字元组。加上OP说他只想要HMS,也许他的意思是自从时代以来的几个小时?目前尚不清楚。 –
Calendar = Calendar.getInstance();
calendar.setTimeInMillis(secondsSinceTheEpoch*1000);
我已经想出了如何处理整数算术中的闰年,并实现了从时代到日期/时间(尽管它永远不会超过59秒)的转换器。下面的C代码应该很容易移植到Java。
#include <string.h>
#include <time.h>
typedef unsigned uint;
typedef unsigned long long uint64;
struct tm* SecondsSinceEpochToDateTime(struct tm* pTm, uint64 SecondsSinceEpoch)
{
uint64 sec;
uint quadricentennials, centennials, quadrennials, annuals/*1-ennial?*/;
uint year, leap;
uint yday, hour, min;
uint month, mday, wday;
static const uint daysSinceJan1st[2][13]=
{
{0,31,59,90,120,151,181,212,243,273,304,334,365}, // 365 days, non-leap
{0,31,60,91,121,152,182,213,244,274,305,335,366} // 366 days, leap
};
/*
400 years:
1st hundred, starting immediately after a leap year that's a multiple of 400:
n n n l \
n n n l } 24 times
... /
n n n l/
n n n n
2nd hundred:
n n n l \
n n n l } 24 times
... /
n n n l/
n n n n
3rd hundred:
n n n l \
n n n l } 24 times
... /
n n n l/
n n n n
4th hundred:
n n n l \
n n n l } 24 times
... /
n n n l/
n n n L <- 97'th leap year every 400 years
*/
// Re-bias from 1970 to 1601:
// 1970 - 1601 = 369 = 3*100 + 17*4 + 1 years (incl. 89 leap days) =
// (3*100*(365+24/100) + 17*4*(365+1/4) + 1*365)*24*3600 seconds
sec = SecondsSinceEpoch + 11644473600LL;
wday = (uint)((sec/86400 + 1) % 7); // day of week
// Remove multiples of 400 years (incl. 97 leap days)
quadricentennials = (uint)(sec/12622780800ULL); // 400*365.2425*24*3600
sec %= 12622780800ULL;
// Remove multiples of 100 years (incl. 24 leap days), can't be more than 3
// (because multiples of 4*100=400 years (incl. leap days) have been removed)
centennials = (uint)(sec/3155673600ULL); // 100*(365+24/100)*24*3600
if (centennials > 3)
{
centennials = 3;
}
sec -= centennials * 3155673600ULL;
// Remove multiples of 4 years (incl. 1 leap day), can't be more than 24
// (because multiples of 25*4=100 years (incl. leap days) have been removed)
quadrennials = (uint)(sec/126230400); // 4*(365+1/4)*24*3600
if (quadrennials > 24)
{
quadrennials = 24;
}
sec -= quadrennials * 126230400ULL;
// Remove multiples of years (incl. 0 leap days), can't be more than 3
// (because multiples of 4 years (incl. leap days) have been removed)
annuals = (uint)(sec/31536000); // 365*24*3600
if (annuals > 3)
{
annuals = 3;
}
sec -= annuals * 31536000ULL;
// Calculate the year and find out if it's leap
year = 1601 + quadricentennials * 400 + centennials * 100 + quadrennials * 4 + annuals;
leap = !(year % 4) && (year % 100 || !(year % 400));
// Calculate the day of the year and the time
yday = sec/86400;
sec %= 86400;
hour = sec/3600;
sec %= 3600;
min = sec/60;
sec %= 60;
// Calculate the month
for (mday = month = 1; month < 13; month++)
{
if (yday < daysSinceJan1st[leap][month])
{
mday += yday - daysSinceJan1st[leap][month - 1];
break;
}
}
// Fill in C's "struct tm"
memset(pTm, 0, sizeof(*pTm));
pTm->tm_sec = sec; // [0,59]
pTm->tm_min = min; // [0,59]
pTm->tm_hour = hour; // [0,23]
pTm->tm_mday = mday; // [1,31] (day of month)
pTm->tm_mon = month - 1; // [0,11] (month)
pTm->tm_year = year - 1900; // 70+ (year since 1900)
pTm->tm_wday = wday; // [0,6] (day since Sunday AKA day of week)
pTm->tm_yday = yday; // [0,365] (day since January 1st AKA day of year)
pTm->tm_isdst = -1; // daylight saving time flag
return pTm;
}
不错的工作!这正是我需要的。为了确认,夹具百岁/四足动物/年度检查只是为了您在开发期间的正确性?它在数学上看起来不会发生。同样,在你每次做'sec - = duration * secs',这相当于使用'%' - 你使用'quadricentennials',只是一个小小的不一致。我会为他们选择' - ='或'%='。 – David
@Dave他们是为了理智,是的,但最重要的是正确性。 :)尝试删除它们并重新运行ideone上的小测试代码。 978307199 =“Sun Dec 31 23:59:59 2000”变为978307199 =“Sun Jan 1 23:59:59 2001”,但是978307199 + 1 =“Mon Jan 1 00:00:00 2001”保持不变。 2000年的最后一秒距离160年1月1日不到400年(对吗?只是比较几年),但距离1/1/1601(即365.24天长的年份)超过4 * 100年, 。通过移除第一个夹具,您将无法正确地解释每隔400年的第97个闰年,这里是我们的案例。 –
在我的32位版本,我不得不改变一行。这一行:'sec = SecondsSinceEpoch + 11644473600;'必须是'sec = SecondsSinceEpoch + 11644473600LL;'。注意''LL',因为它会在32位版本上失败。如果“long long”类型是64位宽,肯定会起作用。 –
java.time
从Java 8及更高版本,内置类使用的是Instant
从java.time框架。
Instant instant = Instant.ofEpochSecond (1_469_168_058L);
转储到控制台。
System.out.println ("instant: " + instant);
瞬间:2016-07-22T06:14:18Z
性能
我不知道究竟在速度的执行中或方面如何java.time.Instant
执行垃圾生产。但是你应该对这个班级进行考试。在我细读the source code in Java 9时,它看起来非常简单和快速。 (a)来自历元(64位long
)的秒数和(b)作为秒的分数(a)的秒数(b) 32位int
),在做了几次快速检查之后:
首先查找零值,在这种情况下,它会为纪元本身返回一个静态实例。
if ((seconds | nanoOfSecond) == 0) {
return EPOCH;
}
其次对与最小/最大常量对的秒数进行完整性检查。
if (seconds < MIN_SECOND || seconds > MAX_SECOND) {
throw new DateTimeException("Instant exceeds minimum or maximum instant");
}
然后调用构造,其对整数值指派给一对的成员变量(long
和int
原语分别地)的。
this.seconds = epochSecond;
this.nanos = nanos;
当然,这只是施工。询问诸如时间之类的部分意味着更多的工作。正如通过toString
方法生成一个字符串涉及另一个类,DateTimeFormatter
。 toString
源代码是一行。
return DateTimeFormatter.ISO_INSTANT.format(this);
请记住,如果你想要的部分,如年,月,日的日,小时,等的不是UTC以外的时区,这意味着涉及ZoneId
和ZonedDateTime
类更多的工作。例如:
ZoneId zoneId = ZoneId.of("America/Montreal");
ZonedDateTime zdt = instant.atZone(zoneId);
- 1. 将秒转换为小时和分钟
- 2. 如何将秒转换为小时分钟和秒?
- 3. 如何将小时,分钟和秒转换为秒
- 4. 如何将秒转换为小时:分钟:秒在php
- 5. 将秒转换为分钟,小时和天的Java代码
- 6. C++转换小时,分钟,秒到秒
- 7. php - 转换小时:分钟:秒。秒
- 8. 将负秒转换为小时:分:秒
- 9. 将秒转换为天:小时:分钟:秒
- 10. 将毫秒转换为小时,分钟和秒python
- 11. 将秒转换为小时,分钟,seconds.hundreths第二秒
- 12. 如何将毫秒,秒,分钟,小时转换为SQL Server 2005中的天数?
- 13. 如何在JavaScript中将时间毫秒转换为小时,分钟,秒格式?
- 14. 如何将秒分别转换为年,月,日,小时,分钟?
- 15. 以小时,分钟,秒钟(以秒为单位)获取时间
- 16. 将分钟转换为小时,分钟和秒
- 17. 将秒数转换为总时数:分钟:秒
- 18. Java/Android:以毫秒为单位转换小时,分钟和秒的本机API
- 19. 将小时,分钟,秒转换为小时字符串
- 20. SQL将秒数转换为分钟数到小时数
- 21. 如何将270921sec转换为天+小时+分钟+秒? (红宝石)
- 22. 如何在SQL中将分钟转换为小时分钟和秒钟?
- 23. Java将秒转换为年日小时分秒
- 24. 将十进制表示时间转换为小时,分钟,秒
- 25. 如何将秒数转换成Bash中的分钟和秒钟?
- 26. 将工作秒数转换为周,天,小时和分钟
- 27. 将分钟转换为毫秒Java/android
- 28. 将ISO8601(我认为)转换为小时:分钟:Powershell中的秒
- 29. NSString如何将小时转换为秒
- 30. 自Unix时代以来,将时间戳记转换为秒数
该解决方案是非线程安全的。 –
@ChristofferHammarström现在我们都知道你没有读过最后一句答案:) –
哦,对。这显然不明显,所以我解决了它,我希望你不介意。 –