1

作为某些逻辑的一部分,在我的程序中需要将长 Java 时间戳(包括年、月等)转换为“短”Java 时间。这应该对应于与原始时间完全相同的小时、分钟和秒,但在 1970 年 1 月 1 日的 1 天内(即介于 0 (00:00:00) 和 86400000 (23:59:59) 之间的值)。一个例子是问题中的转换。

为了执行这个,我认为下面的代码可以工作:

public int convertToTime(long fullTimeStamp) {
    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(date);
    c.set(Calendar.DATE, 1);
    c.set(Calendar.MONTH, 0);
    c.set(Calendar.YEAR, 1970);
    return (int) c.getTimeInMillis();
}

我遇到的问题与时区有关。在英国,我们目前在 BST。使用函数设置所有值后,时间保持不变(例如上午 8 点),但时区更改为 GMT!格林威治标准时间上午 8 点当然与英国夏令时上午 8 点不同,而是等于英国夏令时上午 9 点。

向函数添加一些控制台输出说明了这个问题:

public int convertToTime(long fullTimeStamp) {
    System.out.println(new Date(fullTimeStamp)); // correct

    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(fullTimeStamp);

    System.out.println(c.getTime()); // correct

    c.set(Calendar.DATE, 1);
    c.set(Calendar.MONTH, 0);
    c.set(Calendar.YEAR, 1970);

    System.out.println(c.getTime()); // incorrect!

    return (int) c.getTimeInMillis();
}

程序输出:

Wed Jun 19 12:15:00 BST 2013 // ok
Wed Jun 19 12:15:00 BST 2013 // this makes sense
Thu Jan 01 12:15:00 GMT 1970 // Calendar, stahp!

所需的行为是最后一部分阅读:

Thu Jan 01 11:15:00 GMT 1970
or
Thu Jan 01 12:15:00 BST 1970

这是日历的预期行为吗?我的理解是它使所有未修改的“数字”保持不变,因此如果 HOUR_OF_DAY 的值为 8,则即使修改了时区,它也应保持为 8。

我尝试将日历上的时区(在设置任何值之前)设置为 BST 和 GMT,并且发生了完全相同的行为。我也无法手动添加或删除毫秒以删除 1970 年之后的所有年份,因为我将不得不处理闰年。

除了“使用 Joda 时间(或其他时间包)”之外,是否有人对执行此操作有任何其他建议?如果可能的话,在尝试其他软件包之前,我需要快速修复。

谢谢!

4

2 回答 2

5

我认为您违反了关于英国时区的一个鲜为人知的事实:在 Unix 时代,我们实际上处于 UTC+1。Java 的时间正确(在英国时区内),但名称错误 - 它不应该指定 GMT,而是 BST。这不是英国夏令时的 BST。它是英国标准时间的 BST。是的,就是这么疯狂。

相关的维基百科文章

在 1959-60 年冬季进行的一项调查中,咨询了 180 个国家组织,结果显示,他们略微倾向于更改为全年 GMT+1,但夏季时间的长度被延长为试验而非国内使用取消格林威治标准时间。 [8] 1966-67 年间的进一步调查导致哈罗德威尔逊政府引入了英国标准时间实验,英国全年保持 GMT+1。这发生在 1968 年 10 月 27 日至 1971 年 10 月 31 日之间,当时恢复了之前的安排。

值得记住的是,您最初的问题陈述有些模棱两可:您正在接受 a long,这只是自 Unix 时代以来的毫秒 - 但是您试图用一天中的小时来解释它,这立即提出了您需要在哪个时区解释它的问题。您做出这个决定了吗?如果是这样,您应该非常仔细地记录它,并确保您的代码符合它。

最后,我的建议是:

  • 如果您可以使用Joda Time,请这样做。它将为您节省数小时的心痛。
  • 如果您尝试像这样进行日历计算,请考虑在执行任何其他操作之前将日历的时区更改为 UTC;它会为你省去一些心痛
  • 尽可能避免使用Date.toString()- 您可以使用DateFormatter时区设置为 UTC 的 a,然后您会看到预期的结果

正如 user2340612 的回答所述,要获得“UTC 天的毫秒数”,您可以使用简单的算术 - 但与给出的值不完全一样。我会使用:

long timeOfDay = millisecondsSinceUnixEpoch % TimeUnit.DAYS.toMillis(1);

...但这在您对给定瞬间的 UTC 时间感兴趣时才有效。(它也会对负输入给出负结果,但你可能不在乎。)

于 2013-06-19T09:12:10.360 回答
0

如果您需要 0 到 86399999(即 23:59:59.999)之间的时间戳,您可以获取当前时间戳并计算它与 86400000 之间除法的余数:

desired_time = cur_time % 86400000

但如果在场,你会错过夏季时间。

于 2013-06-19T09:14:37.770 回答