使用基于时区的时间戳创建日期UTC

时间:2011-12-01 12:29:44

标签: java facebook date timezone

奇怪的问题,但你必须首先知道Facebook API定义了所有带有时间戳的日期(长= 第二个 )从01/01/1970 00开始:00:00位于 PDT时区(Pacifica时间) 。 这个秒数不是UTC时间戳,而是基于非标准位置的假时间戳。

在java中有一种简单的方法可以将这个长时间戳转换为我可以使用的普通Date对象(并使用标准日期格式化器以法语格式打印)?

PS:这不仅仅是一个+7小时的问题,此时间戳中还包含夏令时。此外,我们在法国也有夏令时,但不是同样的......

由于

更新: 仅仅修复三角洲就更复杂了。 我认为Facebook记录了我作为PSD日期提供的日期。如果我记录星期四26/10/2011 16H00(巴黎时区),Facebook记录26/10/2011 16H00(旧金山时区)并将其转换为自1970年以来的第二个UTC的适当数量。问题是此转换考虑到了旧金山的夏令时。 我做了以下基准来演示它:

  • (31/12/2011 16:00 - France Time)FB Timestamp = 1325376000而不是1325343600(时间戳UTC) - >达美:-32400
  • (31/07/2012 16:00 - France Time)FB Timestamp = 1343775600而不是1343743200 - >达美:-32400
  • (03/10/2012 16:00 - France Time)FB Timestamp = 1349305200而不是1349272800 - >达美:-32400
  • (28/10/2012 08:00 - France Time)FB Timestamp = 1351436400而不是1351407600 - >达美:-28800
  • (25/03/2012 08:00 - France Time)FB Timestamp = 1332687600而不是1332655200 - >达美:-32400
  • (24/03/2012 23:30 - France Time)FB Timestamp = 1332657000而不是1332628200 - >达美:-28800
  • (27/10/2012 23:30 - France Time)FB Timestamp = 1351405800而不是1351373400 - >达美:-32400

事实上我需要一种方法将31/10/2011 16H00(PDT)转换为31/10/2011 16H00(巴黎TZ)......

2 个答案:

答案 0 :(得分:0)

创建SimpleDateFormat时,您可以指定时区。它产生的日期是GMT + 0。您可以使用另一个SimpleDateFormat和您的时区在当地时区显示它。 (或者你可以使用JodaTime做同样的事情)

如果您需要自PST时区自1970年1月1日以来的毫秒数,您可以

public static final long PST_1970; static {
    try {
        final SimpleDateFormat MM_DD_YYYY = new SimpleDateFormat("MM/dd/yyyy");
        MM_DD_YYYY.setTimeZone(TimeZone.getTimeZone("PST"));
        PST_1970 = MM_DD_YYYY.parse("01/01/1970").getTime();
    } catch (ParseException e) {
        throw new AssertionError(e);
    }
}

public static void main(String... args) throws InterruptedException {
    long now = System.currentTimeMillis();
    long timeSincePST = now - PST_1970;
    System.out.println("now since 1970 GMT " + now);
    System.out.println("millis since 1970 PST " + timeSincePST);
}

由于GMT没有夏令时变化,因此通常是一段时间。

答案 1 :(得分:0)

因此,与标准时代相比,Facebook的固定偏移量为+7小时?解析时间戳时,你不能只减去该偏移吗?例如:

@Test
public void testFacebook() throws Exception {
  long SEVEN_HRS_IN_MILLIS = 25200000;
  DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
  TimeZone cet = TimeZone.getTimeZone("Europe/Paris");
  df.setTimeZone(cet);
  long facebookTimestamp = 1322769308471L;
  Date then = new Date();
  then.setTime(facebookTimestamp - SEVEN_HRS_IN_MILLIS);
  assertEquals("2011-12-01 13:55:08 +0100", df.format(then));
}

请注意,时间戳通常定义为“自引用以来的(毫秒)秒数”,这永远不会包括夏令时。如果您按时钟移动,则1970-01-01 00:00:00 UTC以来的秒数不会改变。

更新:所以你给facebook一个存储日期,而你真正的问题是你不能给它一个合适的时区,所以它存储在旧金山的任何时间?您可以在存储之前将时间转换为“America / Los_Angeles”时区。或者,您可以在检索之后将其转换回来,如下所示:

private DateFormat getDateFormat(String timezone) {
  DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  TimeZone tz = TimeZone.getTimeZone(timezone);
  df.setTimeZone(tz);
  return df;
}

private Date getDateWithCorrectedOffset(long timestamp, DateFormat source, DateFormat target) throws ParseException {
  Date d = new Date(timestamp);
  return target.parse(source.format(d));
}

@Test
public void testFacebook() throws ParseException {
  DateFormat parisTime = getDateFormat("Europe/Paris");
  DateFormat sfTime = getDateFormat("America/Los_Angeles");
  assertEquals("2011-12-31 16:00:00", parisTime.format(getDateWithCorrectedOffset(1325376000000L, sfTime, parisTime)));
  assertEquals("2012-07-31 16:00:00", parisTime.format(getDateWithCorrectedOffset(1343775600000L, sfTime, parisTime)));
  assertEquals("2012-10-03 16:00:00", parisTime.format(getDateWithCorrectedOffset(1349305200000L, sfTime, parisTime)));
  assertEquals("2012-10-28 08:00:00", parisTime.format(getDateWithCorrectedOffset(1351436400000L, sfTime, parisTime)));
  assertEquals("2012-03-25 08:00:00", parisTime.format(getDateWithCorrectedOffset(1332687600000L, sfTime, parisTime)));
  assertEquals("2012-03-24 23:30:00", parisTime.format(getDateWithCorrectedOffset(1332657000000L, sfTime, parisTime)));
  assertEquals("2012-10-27 23:30:00", parisTime.format(getDateWithCorrectedOffset(1351405800000L, sfTime, parisTime)));    
}