关于时区的日期转换混淆

时间:2013-05-20 15:34:07

标签: java date

我正在使用Java 6.我们的服务器在东部标准时间(GMT-5),我正在尝试存储一个应该被解释为这样的值,但我对如何转换它感到困惑。我有

    String dateStr = "1368921600000";       // This is 5/19/2013 00:00:00
    final Calendar cal = Calendar.getInstance();
    cal.setTimeZone(TimeZone.getTimeZone("GMT-5"));
    cal.setTimeInMillis(Long.parseLong(dateStr));
    final java.util.Date dateObj = cal.getTime();
    System.out.println(dateObj.toString());

但是现在这打印出“5月18日星期六19:00:00 CDT 2013”​​(因为我的本地机器在CDT上)但是我希望结果是“Sat May 18 24:00:00 CDT 2013”​​。如何将日期字符串“1368921600000”解释为EST日期?谢谢, - 戴夫

4 个答案:

答案 0 :(得分:2)

1368921600000是一个瞬间,同一时刻,世界各地。要将其转换为日期和时间,您必须在世界中指定 where ,以了解 instant 的日期/时间。事实上,时间戳是相对于UTC的,并且 Sun,2013年5月19日00:00:00 GMT

如果你想在世界其他地方的这个瞬间(同一时刻)的时间,你可以像你一样使用日历并提取单个字段值(例如HOUR_OF_DAY)。如果您只关心获取文本字符串,则使用DateFormat实例,例如SimpleDateFormat:

DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
df.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String timeOnUSEastCoast = df.format(new Date(1368921600000L));
// will be GMT-5 or GMT-4 depending on DST

在这个例子中,输出将是GMT-4:星期六,2013年5月18日20:00:00美国东部时间(不仅时间已经改变,但它仍然是前一天在美国东海岸。)

如果你想输出UTC时间但只是想假装它的EST那么就更容易告诉DateFormat在文本中省略时区字段(删除“z”)输出并随意调用它,但要了解时间戳值始终为UTC。

答案 1 :(得分:1)

通常没有必要使用Joda Time库来获得历史上准确的时区和日光节省感知的本地时间映射,尽管这是许多人常见的响应。

如果你有一个需要本地时间转换的时间戳数据库,那么这里有一些很好的原则:

  • 以UTC时间存储日期/时间(用Joda说明的Instants;用Java Calendar API说明的日期)。 UTC不关心DST。它不关心时区。 UTC简单地代表了一个具有普遍代表性的时刻。仅此步骤可以节省大量日期/时间的麻烦。

  • 数据库记录应包含TimeZone和/或Locale字段,以便可以执行UTC的映射。想想你的数据。数据库中的每个时间戳都不需要与之关联的时区信息。而是将时区数据与提供适当粒度的数据模型的一部分相关联。如果您的应用只会在一个时区进行本地化,那么您根本不需要存储此信息。在我最近的项目中,我创建了一个Locale表,其中包含我的Encounters表中时间戳的TZ ID。所有其他时间戳都从属于这些记录,因此将其关联在那里是有意义的。

  • 使用Java API GregorianCalendar将UTC日期映射到本地时间。这就是我用过的所有东西。我几乎从不使用GregorianCalendars进行日期算术或其他日期操作。以下是我一直在使用的范例:

    public static void main(String[] args) {
    
    m_GregorianCalendar = new GregorianCalendar(TimeZone.getTimeZone(
        "America/Chicago"));
     Date d = new Date();
     String fmt = "dd-MMM-yyyy @ HH:mm";
     :
     :
     String myDate = mapToLocalTime(d, fmt, gc);
     :
     :
     }
    
     public String mapToLocalTime(Date utc, String format, GregorianCalendar gc) {
    
     gc.setTime(utc);  // this calendar is already timezone aware (constructed
                       // with time zone id (DST too))
    
     SimpleDateFormat sdf = new SimpleDateFormat();
     sdf.setCalendar(gc);               // formatter uses conventions of calendar
     sdf.applyPattern(fmt);             // pattern for formatter
    
     return sdf.format(utc);
     }
    
  • 考虑以数字格式(longs,double)在内部表示时间戳。这大大简化了日期比较和日期算术。唯一的缺点是必须进行转换才能将数据格式化为人类可识别的形式,但如果您使用函数进行这些转换,则根本不需要做大事。

答案 2 :(得分:0)

使用new java.util.SimpleDateFormat(format)java.util.DateFormat.getDateTimeInstance(int,int),然后使用#setTimeZone(timezone)

答案 3 :(得分:0)

当您打印Date.toString()时,根本不考虑日历的时区。执行cal.getTime()后,在Calendar中设置的内容不再相关。

TimeZone的默认时区是什么。

因此,在打印日期之前,将默认时区设置为您要打印的时区,例如:

String dateStr = "1368921600000";       // This is 5/19/2013 00:00:00
final Calendar cal = Calendar.getInstance();
TimeZone gmtZero = TimeZone.getTimeZone("GMT");
cal.setTimeInMillis(Long.parseLong(dateStr));
final java.util.Date dateObj = cal.getTime();
TimeZone.setDefault(gmtZero);
System.out.println(dateObj.toString());

无论您的系统时区如何,都会以GMT格式打印日期。

请记住之后恢复原来的默认TimeZone!