【问题标题】:problem on java calendar functionjava日历功能的问题
【发布时间】:2011-08-21 09:13:51
【问题描述】:

我这样声明CalendarSimpleDateFormat

calendar = Calendar.getInstance(TimeZone.getTimeZone("Malaysia"));
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MMMMM.dd hh:mm aaa");

或:

calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+08:00"));

然后我称之为:

sdf.format(calendar.getTime());

但结果不在正确的时区(+8 小时)。可能是什么问题?

【问题讨论】:

  • calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Kuala_Lumpur"));
  • @John,还是一样,ID有问题= =
  • Date 实例返回默认时区的时间字符串。This link will help you
  • @John,我还是不明白如何让它工作= =
  • @newbie:正如我所说,问题是日期是基于格林威治标准时间的。它将始终以默认时区 (TimeZone.getDefault()) 打印,除非您将所需的时区传递给格式化程序对象。

标签: java internationalization calendar timezone date-format


【解决方案1】:

除非您要执行与日期/时间相关的计算,否则使用给定的 TimeZone 实例化日历是没有意义的。调用 Calendar 的 getTime() 方法后,您将收到 Date 对象,无论哪种方式都是无时区的(实际上是基于 GMT)。

您需要做的是为格式化程序设置TimeZone。也不要费心传递你自己的格式,已经有一个内置的:

    // get current time
    // you could just as well use Date now = new Date();
    Calendar now = Calendar.getInstance();

    // Locale for formatter
    Locale malaysianLocale = new Locale("ms", "MY");
    // Default date and time format for Malaysia
    DateFormat defaultMalaysianFormatter = DateFormat.getDateTimeInstance(
            DateFormat.DEFAULT, DateFormat.DEFAULT, malaysianLocale);
    // This step is crucial
    TimeZone malaysianTimeZone = TimeZone.getTimeZone("Asia/Kuala_Lumpur");
    defaultMalaysianFormatter.setTimeZone(malaysianTimeZone);

    System.out.println(defaultMalaysianFormatter.format(now.getTime()));

这会打印出类似10 Mei 2011 2:30:05 AM 的内容,我相信这是您想要的结果。

【讨论】:

  • 我的输出是 2011 05 10 10:37:30 只有我想要 dd/MM/yyyy, hh:mm:ss,可以定制这个吗?
  • 您可以使用 SimpleDateFormat 来做到这一点。所以你可以编写类似SimpleDateFormat formtatter = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss", malaysianLocale); formatter.setTimeZone(malaysianTimeZone); formatter.format(now.getTime()); 的代码。我建议不要使用自定义模式,但如果你真的需要这样做,这就是方法。
【解决方案2】:

时区 ID 应设置为 Asia/Kuala_LumpurDate.toString() 总是使用默认时区返回时间字符串。但是您的默认时区不同。

    Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("Asia/Kuala_Lumpur"));
    Calendar cal = Calendar.getInstance();

    cal.set(Calendar.YEAR, tzCal.get(Calendar.YEAR));
    cal.set(Calendar.MONTH, tzCal.get(Calendar.MONTH));
    cal.set(Calendar.DAY_OF_MONTH, tzCal.get(Calendar.DAY_OF_MONTH));
    cal.set(Calendar.HOUR_OF_DAY, tzCal.get(Calendar.HOUR_OF_DAY));
    cal.set(Calendar.MINUTE, tzCal.get(Calendar.MINUTE));
    cal.set(Calendar.SECOND, tzCal.get(Calendar.SECOND));
    cal.set(Calendar.MILLISECOND, tzCal.get(Calendar.MILLISECOND));
    System.out.println("Current Time = " + sdf.format(cal.getTime()));

【讨论】:

  • @John,所以我需要自定义时间而不是使用默认值?
  • @newbie:是的。你需要自定义它。
  • @John: 和前面一样,正确的假设是 +08:00 小时
  • @newbie:以前的?发布您的时区:System.out.println("Current Timezone=" + TimeZone.getDefault().getDisplayName());
【解决方案3】:

TimeZone.getTimeZone() 调用不正确。您必须传递正确的标识符。

编辑 -- 您可以尝试 getAvailableIDs() 并遍历它们以确保您拥有正确的 id。

【讨论】:

  • 如何获取正确的ID?能给我举个吉隆坡的例子吗?
【解决方案4】:

如果你仔细阅读过TimeZone的javadoc,getTimeZone的使用方法是: TimeZone.getTimeZone("GMT-8") 要么 TimeZone.getTimeZone("GMT+8")

【讨论】:

    【解决方案5】:

    tl;博士

    java.time.ZonedDateTime.now(
        ZoneId.of( "Asia/Kuala_Lumpur" ) 
    ).toString() 
    

    2018-01-23T18:48:32.263+08:00[Asia/Kuala_Lumpur]

    避免遗留类

    问题和其他答案使用麻烦的旧日期时间类,这些类现在是遗留的,被 java.time 类取代。

    java.time

    现代方法使用 java.time 类。忘记所有令人困惑的Calendar 类。

    当前时刻

    首先获取 UTC 中的当前时刻。 Instant 类代表UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

    Instant instant = Instant.now() ;
    

    时区

    调整到另一个时区。

    continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的伪时区,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

    ZoneId z = ZoneId.of( "Asia/Kuala_Lumpur" ) ; // Or "Asia/Kuching", etc.
    

    应用ZoneId 来实例化ZonedDateTime 对象。 ZonedDateTimeInstant 都代表同一时刻,时间轴上的同一点,但通过不同的挂钟时间查看。

    ZonedDateTime zdt = instant.atZone( z ) ;  // Same moment, different wall-clock time.
    

    偏移

    如果您只有一个offset-from-UTC,例如+08:00,而不是已知的time zone,您将使用ZoneOffset 来获得OffsetDateTime,而不是ZoneIdZonedDateTime。但是时区总是比单纯的偏移更可取。区域是特定区域的人们使用的偏移量的历史记录。

    字符串

    要生成标准ISO 8601 格式的字符串,请调用toString 方法。

    ZonedDateTime 类明智地扩展了标准,将时区名称附加在方括号中。

    String output = zdt.toString() ;  // YYYY-MM-DDTHH:MM:SS.SSSSSSSSS[tz]
    

    根据用户的偏好进行本地化。要进行本地化,请指定:

    • FormatStyle 确定字符串的长度或缩写。
    • Locale 确定 (a) 用于翻译日期名称、月份名称等的人类语言,以及 (b) 决定缩写、大写、标点符号、分隔符等问题的文化规范。

      语言环境 l = Locale.CANADA_FRENCH ; DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(l); 字符串输出 = zdt.format( f );

    转储到控制台。

    System.out.println( "instant.toString(): " + instant ) ;
    System.out.println( "output: " + output ) ;
    System.out.println( "outputLocalized (always Locale.US on IdeOne.com): " + outputLocalized ) ;
    

    看到这个code run live at IdeOne.com。请注意,IdeOne.com 会覆盖任何 Locale 设置以始终使用 Locale.US

    instant.toString(): 2018-01-23T10:48:32.263Z

    输出:2018-01-23T18:48:32.263+08:00[Asia/Kuala_Lumpur]

    ooutputLocalized(在 IdeOne.com 上始终为 Locale.US):2018 年 1 月 23 日星期二下午 6:48:32 MYT


    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

      猜你喜欢
      • 2017-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-19
      • 1970-01-01
      • 2021-06-04
      • 2022-09-27
      • 1970-01-01
      相关资源
      最近更新 更多