当前位置:  开发笔记 > 编程语言 > 正文

如何使用Java处理日历时区?

如何解决《如何使用Java处理日历时区?》经验,为你挑选了7个好方法。

我有一个来自我的应用程序的Timestamp值.用户可以在任何给定的本地TimeZone中.

由于此日期用于假定给定时间始终为GMT的WebService,因此我需要将用户的参数从say(EST)转换为(GMT).这是踢球者:用户不知道他的TZ.他进入了他想要发送给WS的创建日期,所以我需要的是:

用户输入: 2008年5月1日下午6:12(美国东部时间)
WS的参数必须是:2008年5月1日下午6:12(格林威治标准时间)

我知道默认情况下TimeStamps总是应该是GMT,但是在发送参数时,即使我从TS创建我的日历(应该是GMT),除非用户使用GMT,否则小时总是关闭.我错过了什么?

Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
...
private static java.util.Calendar convertTimestampToJavaCalendar(Timestamp ts_) {
  java.util.Calendar cal = java.util.Calendar.getInstance(
      GMT_TIMEZONE, EN_US_LOCALE);
  cal.setTimeInMillis(ts_.getTime());
  return cal;
}

使用前面的代码,这就是我得到的结果(简单格式,便于阅读):

[2008年5月1日下午11:12]



1> matt b..:
public static Calendar convertToGmt(Calendar cal) {

    Date date = cal.getTime();
    TimeZone tz = cal.getTimeZone();

    log.debug("input calendar has date [" + date + "]");

    //Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT 
    long msFromEpochGmt = date.getTime();

    //gives you the current offset in ms from GMT at the current date
    int offsetFromUTC = tz.getOffset(msFromEpochGmt);
    log.debug("offset is " + offsetFromUTC);

    //create a new calendar in GMT timezone, set to this date and add the offset
    Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    gmtCal.setTime(date);
    gmtCal.add(Calendar.MILLISECOND, offsetFromUTC);

    log.debug("Created GMT cal with date [" + gmtCal.getTime() + "]");

    return gmtCal;
}

如果我通过当前时间("EDT 12:09:05" Calendar.getInstance()),这是输出:

DEBUG - 输入日历有日期[Thu Oct 23 12:09:05 2008 EDT]
DEBUG - offset是-14400000
DEBUG - Created GMT cal with date [Thu Oct 23 08:09:05 EDT 2008]

格林威治标准时间12:09:05是美国东部夏令时间8:09:05.

这里令人困惑的部分是在您当前的时区中Calendar.getTime()返回一个Date,并且没有方法可以修改日历的时区并且还会滚动基础日期.根据您的Web服务所采用的参数类型,您可能只希望以纪元为单位的毫秒数进行WS处理.


你不应该减去`offsetFromUTC`而不是添加它吗?使用你的例子,如果格林尼治标准时间12:09是美国东部时间8:09(这是真的),并且用户输入"12:09 EDT",算法应输出"16:09 GMT",在我看来.

2> Jorge Valois..:

谢谢大家的回复.经过进一步调查后,我得到了正确的答案.正如Skip Head所提到的,我从我的应用程序中获取的TimeStamped正在调整为用户的TimeZone.因此,如果用户在下午6:12(美国东部时间)进入,我将在下午2:12(GMT).我需要的是撤消转换的方法,以便用户输入的时间是我发送到WebServer请求的时间.这是我如何完成这个:

// Get TimeZone of user
TimeZone currentTimeZone = sc_.getTimeZone();
Calendar currentDt = new GregorianCalendar(currentTimeZone, EN_US_LOCALE);
// Get the Offset from GMT taking DST into account
int gmtOffset = currentTimeZone.getOffset(
    currentDt.get(Calendar.ERA), 
    currentDt.get(Calendar.YEAR), 
    currentDt.get(Calendar.MONTH), 
    currentDt.get(Calendar.DAY_OF_MONTH), 
    currentDt.get(Calendar.DAY_OF_WEEK), 
    currentDt.get(Calendar.MILLISECOND));
// convert to hours
gmtOffset = gmtOffset / (60*60*1000);
System.out.println("Current User's TimeZone: " + currentTimeZone.getID());
System.out.println("Current Offset from GMT (in hrs):" + gmtOffset);
// Get TS from User Input
Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
System.out.println("TS from ACP: " + issuedDate);
// Set TS into Calendar
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
// Adjust for GMT (note the offset negation)
issueDate.add(Calendar.HOUR_OF_DAY, -gmtOffset);
System.out.println("Calendar Date converted from TS using GMT and US_EN Locale: "
    + DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
    .format(issueDate.getTime()));

代码的输出是:(用户输入5/1/2008 6:12 PM(EST)

当前用户的时区:
从GMT的EST 当前偏移(以小时为单位): - 4(通常为-5,除了经过DST调整)
来自ACP的TS:2008-05-01 14:12:
00.0日历使用GMT和US_EN区域设置从TS转换的日期:5/1/08 6:12 PM(格林威治标准时间)



3> Henrik Aaste..:

您说日期与Web服务一起使用,因此我假设在某些时候将其序列化为字符串.

如果是这种情况,您应该看一下DateFormat类的setTimeZone方法.这决定了打印时间戳时将使用的时区.

一个简单的例子:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

Calendar cal = Calendar.getInstance();
String timestamp = formatter.format(cal.getTime());


没有依赖SDF它有自己的时区,想知道为什么改变Calendar TimeZone似乎没有效果!
使用setTimeZone()方法很棒的想法.你为我节省了很多麻烦,非常感谢!

4> Vitalii Fedo..:

你可以用Joda Time解决它:

Date utcDate = new Date(timezoneFrom.convertLocalToUTC(date.getTime(), false));
Date localDate = new Date(timezoneTo.convertUTCToLocal(utcDate.getTime()));

Java 8:

LocalDateTime localDateTime = LocalDateTime.parse("2007-12-03T10:15:30");
ZonedDateTime fromDateTime = localDateTime.atZone(
    ZoneId.of("America/Toronto"));
ZonedDateTime toDateTime = fromDateTime.withZoneSameInstant(
    ZoneId.of("Canada/Newfoundland"));



5> Skip Head..:

看起来您的TimeStamp被设置为原始系统的时区.

这已被弃用,但它应该有效:

cal.setTimeInMillis(ts_.getTime() - ts_.getTimezoneOffset());

不推荐的方式是使用

Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)

但这需要在客户端完成,因为该系统知道它所在的时区.



6> 小智..:

从一个时区转换到另一个时区的方法(可能它工作:)).

/**
 * Adapt calendar to client time zone.
 * @param calendar - adapting calendar
 * @param timeZone - client time zone
 * @return adapt calendar to client time zone
 */
public static Calendar convertCalendar(final Calendar calendar, final TimeZone timeZone) {
    Calendar ret = new GregorianCalendar(timeZone);
    ret.setTimeInMillis(calendar.getTimeInMillis() +
            timeZone.getOffset(calendar.getTimeInMillis()) -
            TimeZone.getDefault().getOffset(calendar.getTimeInMillis()));
    ret.getTime();
    return ret;
}



7> 小智..:

日期时间戳对象是时区遗忘的:它们表示自纪元以来的特定秒数,而不是将该瞬间的特定解释作为小时和天.时区仅在GregorianCalendar(此任务不直接需要)和SimpleDateFormat中输入图片,这需要时区偏移以在单独的字段和日期(或)值之间进行转换.

OP的问题恰好在他的处理开始时:用户输入的时间不明确,并且在本地非GMT时区进行解释; 此时,该值为"6:12 EST",可轻松打印为"11.12 GMT"或任何其他时区,但永远不会更改"6.12 GMT".

没有办法使SimpleDateFormat"06:12"解析为"HH:MM"(默认为本地时区)默认为UTC; SimpleDateFormat对自己的好处有点太聪明了.

但是,如果你明确地将它放在输入中,你可以说服任何SimpleDateFormat实例使用正确的时区:只需将一个固定的字符串附加到接收的(并且经过充分验证的)"06:12"以解析"06:12 GMT""HH:MM z".

无需显式设置GregorianCalendar字段,也无需检索和使用时区和夏令时偏移.

真正的问题是将默认为本地时区的输入,默认为UTC的输入以及真正需要显式时区指示的输入进行隔离.

推荐阅读
Life一切安好
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有