【问题标题】:Convert unix timestamp between different timezones and different DST in Java在Java中不同时区和不同DST之间转换unix时间戳
【发布时间】:2013-04-15 10:03:38
【问题描述】:

问题已解决 外部设备正在计算和发送非标准的 2 小时偏移时间戳,这让我非常困惑并开始了这个线程。 时间戳本身不受时区影响,时区仅在转换为人类可读形式时适用。


我在 UTC 时区有时间戳(距 unix 纪元的秒数​​) - 没有 DST(夏令时)。

我想要使用 DST 的“欧洲/布拉格”时区的时间戳(距 unix 纪元的秒数​​)。

我曾经认为 unix 时间戳不受时区约束,时区仅影响将时间戳转换为人类可读格式的过程。但它看起来不像那样。我越是尝试转换它(使用 Calendar 和 TimeZone 类),我就越困惑和迷失。

此代码无法按预期工作:

Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(ts*1000);
cal.setTimeZone(TimeZone.getTimeZone("Europe/Prague"));
return cal.getTimeInMillis()/1000;

【问题讨论】:

  • 它有什么作用?打印出每行代码之间的 cal 会发生什么?
  • 您或许应该说明您是否对Joda-Time 解决方案感兴趣,因为我怀疑您会开始收到它们。
  • @Peter 对于最近的时间戳 '1366642620' 它返回了相同的时间戳 - 没有发生转换。如果我尝试在 UTC 和欧洲/布拉格时区的 PHP 中打印该时间戳,我会得到不同的时间:14:57 和 16:57
  • 当您 getTimeInMillis() 时,您将丢弃刚刚添加的 TimeZone。请参阅我的答案中的示例。

标签: java timezone dst java.util.date


【解决方案1】:

没有办法“转换”时间戳,它始终是从纪元开始的毫秒数。

您可以使用 DateFormat 将时间戳格式化为应用了时区的格式,或者使用 Calendar 来查看应用了时区的小时、分钟和秒。

getTimeInMillis() 获取与您输入的时间戳相同的时间戳,即从纪元开始的毫秒数: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#getTimeInMillis%28%29

【讨论】:

    【解决方案2】:

    这是在时区之间转换纪元的示例代码。

    public static long convertTimeZone(long lngDate, String fromTimeZone,
            String toTimeZone) {        
        Calendar fromTime = Calendar.getInstance();
        fromTime.setTimeZone(TimeZone.getTimeZone(fromTimeZone));
        fromTime.setTimeInMillis(lngDate);
        Calendar toTime = new GregorianCalendar(
                TimeZone.getTimeZone(toTimeZone));
        toTime.set(Calendar.DATE, fromTime.get(Calendar.DATE));
        toTime.set(Calendar.MONTH, fromTime.get(Calendar.MONTH));
        toTime.set(Calendar.YEAR, fromTime.get(Calendar.YEAR));
        toTime.set(Calendar.HOUR_OF_DAY, fromTime.get(Calendar.HOUR_OF_DAY));
        toTime.set(Calendar.MINUTE, fromTime.get(Calendar.MINUTE));
        toTime.set(Calendar.SECOND, fromTime.get(Calendar.SECOND));
        toTime.set(Calendar.MILLISECOND, fromTime.get(Calendar.MILLISECOND));
        LOG.debug("Converted " + fromTime.getTimeInMillis() + " to "
                + toTime.getTimeInMillis());
        SimpleDateFormat sdf = new SimpleDateFormat(
                "dd-MMM-yyyy HH:mm:ss.SSS z");      
        sdf.setTimeZone(TimeZone.getTimeZone(fromTimeZone));        
        SimpleDateFormat sdf1 = new SimpleDateFormat(
                "dd-MMM-yyyy HH:mm:ss.SSS z");      
        sdf1.setTimeZone(TimeZone.getTimeZone(toTimeZone));
        LOG.debug("Converted " + sdf.format(fromTime.getTime()) + " to " + sdf1.format(toTime.getTime()));
        return toTime.getTimeInMillis();
    }
    

    输出:

    System.out.println(convertTimeZone(new Date().getTime(),"America/New_York","Asia/Singapore"));
    Converted 1384514879944 to 1384468079944
    Converted 15-Nov-2013 06:27:59.944 EST to 15-Nov-2013 06:27:59.944 SGT
    

    【讨论】:

    • 我已经这样做了超过 4 个小时。我终于得到了正确的结果。这似乎是 java 中的错误或您添加的行,它向 toTime 对象添加了毫秒,这导致从 UTC 到本地时区将近 3 小时。
    【解决方案3】:

    它的行为符合我的预期

    public static void main(String... ignored) {
        long ts = System.currentTimeMillis() / 1000;
        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));
        printCalendar(cal);
        cal.setTimeInMillis(ts * 1000);
        printCalendar(cal);
        cal.setTimeZone(TimeZone.getTimeZone("Europe/Prague"));
        printCalendar(cal);
    }
    
    public static void printCalendar(Calendar calendar) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS ZZZ");
        sdf.setTimeZone(calendar.getTimeZone());
        System.out.println(sdf.format(calendar.getTime()));
    }
    

    打印

    2013/04/22 13:28:06.451 +0000
    2013/04/22 13:28:06.000 +0000
    2013/04/22 15:28:06.000 +0200
    

    【讨论】:

      【解决方案4】:

      您可以像这样在两个时区之间轻松转换:

      1.假设这是 EST 时区的日期和时间

      String value = "2006-11-28 09:45:12";  
      DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
      df1.setTimeZone(TimeZone.getTimeZone("EST"));  
      

      2.解析该值并假设它代表 EST 时区中的日期和时间

      Date d = df1.parse(value);     
      DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
      df2.setTimeZone(TimeZone.getTimeZone("CET")); 
      

      3.格式化CET时区的日期

      System.out.println(df2.format(d)); 
      

      【讨论】:

      • 我见过类似的例子,但它的输入是(小时,分钟,秒)格式,而不是 unix 时间戳。我的问题的关键是我不知道如何从不同的时区加载“unix 时间戳”。 Calendar.setTimeinMilis() 的行为就像它在系统时区而不是在 Calendar 对象中设置的时区一样工作。
      • 你如何获得实际的日期而不是字符串?
      猜你喜欢
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 2019-02-22
      • 1970-01-01
      • 2020-10-17
      相关资源
      最近更新 更多