将完整的Java日期(例如,2013-06-19上午8.00)转换为一个时间(即1970-01-01上午8点)

时间:2013-06-19 09:06:35

标签: java datetime time timezone

作为某种逻辑的一部分,我的程序中必须将长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点与BST早上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时间(或其他时间包)',是否有人有任何其他建议来执行此操作?如果可能的话,我需要在尝试其他软件包之前快速修复。

谢谢!

2 个答案:

答案 0 :(得分:5)

我认为你在英国时区犯了一个鲜为人知的事实:在Unix时代,我们实际上是在UTC + 1。 Java正在获取正确的时间(在英国时区内),但名称错误 - 它不应该指定GMT,而是BST。这不是英国夏天时间的BST;它的BST与英国标准时间一样。是的,它很疯狂。

来自relevant wikipedia article

  

1959年至1960年冬季进行了一次调查,其中咨询了180个国家组织,显示出对全年GMT + 1的改变略有偏好,但是夏令时的长度作为试验延长而不是国内使用格林威治标准时间废除。[8] 1966年至1967年期间的进一步调查导致哈罗德威尔逊政府引入英国标准时间实验,英国全年保持GMT + 1。这发生在1968年10月27日至1971年10月31日之间,当时有一种情况回归到先前的安排。

值得记住的是,你原来的问题陈述有些含糊不清:你正在考虑long,这是自Unix时代以来的毫无疑问 - 然而你&#39重新尝试用一天中的小时来解释它,这会立即引出你需要解释它的时区的问题。你做出了这个决定吗?如果是这样,您应该非常仔细地记录它,并确保您的代码符合它。

最终,我的建议是:

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

当用户2340612回答说明时,只需获得UTC时间的"毫秒"你可以使用简单的算术 - 但不能完全给出给定的值。我会用:

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

...但如果您对给定时刻的UTC时间感兴趣,则此有效。 (它也会给负面输入带来负面结果,但你可能不在乎。)

答案 1 :(得分:0)

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

desired_time = cur_time % 86400000

但如果有的话,你会错过夏令时。