【问题标题】:Format calendar date to dd-MM-yyyy affected by timezone将日历日期格式化为受时区影响的 dd-MM-yyyy
【发布时间】:2016-01-30 14:50:30
【问题描述】:

我在将日历对象转换为可读字符串时遇到了一个大问题。

实际上我使用 df.format(cal.getTime()) 来获取格式化的字符串,这不是很好,因为我从 cal.getTime() 获得的 Date 对象不受时区的影响。

请不要像“使用joda time”这样的cmets...

我正在寻找一种将日历对象直接转换为字符串的解决方案。

这些是我的格式化程序:

  private DateFormat df = new SimpleDateFormat("HH:mm", Locale.GERMANY); // 13:42 Uhr
  private DateFormat df2 = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMANY); // 14.04.2012

如果你们试一试这段代码,你会发现 Date 对象不受时区影响。

    //  this date is at wintertime
long milli = 1445945400000l;    //  CET  - central european time  

Calendar cal = Calendar.getInstance();

cal.setTimeInMillis(milli);
System.out.println("  ");
System.out.println("Kalender setTimeInMillis(" + milli + ");");
System.out.println("Daylight Time ? = " + cal.getTimeZone().useDaylightTime());
System.out.println("Date Time = " + cal.getTime());
System.out.println("Kalender Tag = " + cal.get(Calendar.DATE) + "  Monat = " + (cal.get(Calendar.MONTH) + 1) + "  Jahr = " + cal.get(Calendar.YEAR));
System.out.println("Kalender Uhrzeit = " + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND));

cal.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
System.out.println("  ");
System.out.println("Kalender setTimeZone(TimeZone.getTimeZone(\"Europe/Berlin\");");
System.out.println("Daylight Time ? = " + cal.getTimeZone().useDaylightTime());
System.out.println("Date Time = " + cal.getTime());
System.out.println("Kalender Tag = " + cal.get(Calendar.DATE) + "  Monat = " + (cal.get(Calendar.MONTH) + 1) + "  Jahr = " + cal.get(Calendar.YEAR));
System.out.println("Kalender Uhrzeit = " + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND));

    //  this date is at summertime
long milliS = 1445609700000l;   //  CEST - central european summertime

Calendar calS = Calendar.getInstance();

calS.setTimeInMillis(milliS);
System.out.println("  ");
System.out.println("Kalender setTimeInMillis(" + milliS + ");");
System.out.println("Daylight Time ? = " + calS.getTimeZone().useDaylightTime());
System.out.println("Date Time = " + calS.getTime());
System.out.println("Kalender Tag = " + calS.get(Calendar.DATE) + "  Monat = " + (calS.get(Calendar.MONTH) + 1) + "  Jahr = " + calS.get(Calendar.YEAR));
System.out.println("Kalender Uhrzeit = " + calS.get(Calendar.HOUR_OF_DAY) + ":" + calS.get(Calendar.MINUTE) + ":" + calS.get(Calendar.SECOND));

calS.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
System.out.println("  ");
System.out.println("Kalender setTimeZone(TimeZone.getTimeZone(\"Europe/Berlin\");");
System.out.println("Daylight Time ? = " + calS.getTimeZone().useDaylightTime());
System.out.println("Date Time = " + calS.getTime());
System.out.println("Kalender Tag = " + calS.get(Calendar.DATE) + "  Monat = " + (calS.get(Calendar.MONTH) + 1) + "  Jahr = " + calS.get(Calendar.YEAR));
System.out.println("Kalender Uhrzeit = " + calS.get(Calendar.HOUR_OF_DAY) + ":" + calS.get(Calendar.MINUTE) + ":" + calS.get(Calendar.SECOND));

输出

Kalender setTimeInMillis(1445945400000);  
Daylight Time ? = false  
Date Time** = Tue Oct 27 11:30:00 GMT 2015  
Kalender Tag = 27  Monat = 10  Jahr = 2015  
Kalender Uhrzeit = 11:30:0  

Kalender setTimeZone(TimeZone.getTimeZone("Europe/Berlin");  
Daylight Time ? = true  
Date Time = Tue Oct 27 11:30:00 GMT 2015  
Kalender Tag = 27  Monat = 10  Jahr = 2015  
Kalender Uhrzeit = 12:30:0  

Kalender setTimeInMillis(1445609700000);  
Daylight Time ? = false  
Date Time = Fri Oct 23 14:15:00 GMT 2015  
Kalender Tag = 23  Monat = 10  Jahr = 2015  
Kalender Uhrzeit = 14:15:0  

Kalender setTimeZone(TimeZone.getTimeZone("Europe/Berlin");  
Daylight Time ? = true  
Date Time = Fri Oct 23 14:15:00 GMT 2015  
Kalender Tag = 23  Monat = 10  Jahr = 2015  
Kalender Uhrzeit = 16:15:0

【问题讨论】:

  • 问题出在哪里或问题是什么?调用 df.format(calS.getTime()) 对我来说效果很好(两次都正确)。
  • 为什么不“使用jodatime”?

标签: java date datetime calendar converter


【解决方案1】:

你需要设置格式化程序的时区,一个简单的例子:

SimpleDateFormat df = new SimpleDateFormat();

Calendar cal1 = Calendar.getInstance(TimeZone.getTimeZone("GMT+4:00"));

df.setTimeZone(cal1.getTimeZone());
System.out.println(df.format(cal1.getTime()));

Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT-3:00"));

df.setTimeZone(cal2.getTimeZone());
System.out.println(df.format(cal2.getTime()));

输出:

10/30/15 1:02 PM
10/30/15 6:02 AM

【讨论】:

  • 完美!!非常感谢!
【解决方案2】:

请注意,java.util.Date 对象本身不包含任何时区信息 - 您不能在 Date 对象上设置时区。 Date 对象包含的唯一内容是自“纪元” - 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数。

https://stackoverflow.com/a/2892156/5445351

【讨论】:

    【解决方案3】:

    日期有自己的时区

    令人困惑的是,java.util.Date 使用 JVM 当前的默认时区分配了一个内部时区。您无法获取或设置该区域。将 java.util.Calendar 类添加到 Java 以处理时区和其他此类问题。

    从纪元开始计数

    长毫 = 1445945400000l; // CET - 中欧时间

    通常这样的数字是UTC (GMT) 中的一个时代计数,而不是任何特定时区。从该数字创建日期时间对象后,您可以分配要应用的时区。

    提示:在整数文字上使用大写的 L 以避免在许多字体中看起来像 1

    java.time

    这些类现在已被 Java 8 及更高版本中内置的 java.time 框架所取代。新的类更合理,更易于使用。

    时区

    时区不仅仅是offset-from-UTC。时区是一个偏移量加上一组过去、现在和将来的处理异常的规则,例如夏令时。使用proper time zone,例如Europe/Berlin。避免使用甚至考虑使用 3-4 个字母的代码,例如 CETCEST;它们既不标准化也不独特。

    示例代码

    首先,我们得到一个Instant,它是UTC 时间线上的一个时刻,来自从纪元开始计数。

    long milliSecondsFromEpochInUtc = 1445945400000L;
    Instant instant = Instant.ofEpochMilli ( milliSecondsFromEpochInUtc );
    

    然后我们分配所需的时区以获取ZonedDateTime

    ZoneId zoneId = ZoneId.of ( "Europe/Berlin" );
    ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
    

    对于输出,格式化程序默认使用 ZonedDateTime 对象的指定时区。

    DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.MEDIUM ).withLocale ( Locale.GERMANY );
    String output1 = zdt.format ( formatter );
    

    如果指定,格式化程序可以选择应用不同的时区。

    String output2 = zdt.format ( formatter.withZone ( ZoneId.of ( "America/Montreal" ) ) );
    

    转储到控制台。

    System.out.println ( "instant (UTC): " + instant );
    System.out.println ( "zdt: " + zdt );
    System.out.println ( "Berlin time zone: " + output1 );
    System.out.println ( "Montréal time zone: " + output2 );
    

    运行时。请注意,所有这些都代表时间轴上的同一时刻。它们的呈现方式各不相同,但它们都意味着同一时刻。

    instant (UTC): 2015-10-27T11:30:00Z
    zdt: 2015-10-27T12:30+01:00[Europe/Berlin]
    Berlin time zone: 27.10.2015 12:30:00
    Montréal time zone: 27.10.2015 07:30:00
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-18
      • 1970-01-01
      • 2018-09-01
      • 2012-09-16
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 2013-11-01
      相关资源
      最近更新 更多