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

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

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

用户输入:5/1/2008 6:12 PM(EST)

WS的参数必须是:5/1/2008 6:12 PM(GMT)

我知道默认情况下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]

9个解决方案

60 votes

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;

}

如果我通过当前时间(" 12:09:05 EDT"来自Calendar.getTime()),输出如下:

DEBUG - 输入日历有日期[Thu Oct 23 12:09:05 2008 EDT]

DEBUG - 偏移量为-14400000

DEBUG - 创建GMT cal与日期[Thu Oct 23 08:09:05 EDT 2008]

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

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

matt b answered 2019-08-12T00:00:05Z

29 votes

谢谢大家的回复。 经过进一步调查后,我得到了正确的答案。 正如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)

当前用户的TimeZone:EST

GMT当前偏差(小时): - 4(通常为-5,除了经过DST调整)

来自ACP的TS:2008-05-01 14:12:00.0

使用GMT和US_EN转换自TS的日历日期区域设置:5/1/08 6:12 PM(GMT)

Jorge Valois answered 2019-08-12T00:01:06Z

20 votes

您说日期与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());

Henrik Aasted Sørensen answered 2019-08-12T00:01:44Z

12 votes

你可以用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"));

Vitalii Fedorenko answered 2019-08-12T00:02:10Z

8 votes

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

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

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

不推荐的方式是使用

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

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

Skip Head answered 2019-08-12T00:02:55Z

7 votes

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

/**

* 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;

}

Helpa answered 2019-08-12T00:03:19Z

6 votes

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

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

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

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

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

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

user412090 answered 2019-08-12T00:04:21Z

4 votes

过去对我有用的东西是确定用户时区和GMT之间的偏差(以毫秒为单位)。 获得偏移后,您可以简单地添加/减去(取决于转换的方式)以在任一时区获得适当的时间。 我通常会通过设置Calendar对象的毫秒字段来完成此操作,但我确信您可以轻松地将其应用于时间戳对象。 这是我用来获取偏移量的代码

int offset = TimeZone.getTimeZone(timezoneId).getRawOffset();

timezoneId是用户时区的ID(例如EST)。

Adam answered 2019-08-12T00:04:54Z

1 votes

java.time

现代方法使用java.time类,这些类取代了与最早版本的Java捆绑在一起的麻烦的遗留日期时间类。

YearQuarter类是其中一个遗留类。 不再需要。 而是使用JDBC 4.2及更高版本直接在数据库中使用ZoneOffset.UTC或其他java.time类。

YearQuarter类表示UTC时间轴上的一个时刻,分辨率为纳秒(小数部分最多九(9)位)。

Instant instant = myResultSet.getObject( … , Instant.class ) ;

如果必须与现有的YearQuarter进行互操作,请通过添加到旧类的新转换方法立即转换为java.time。

Instant instant = myTimestamp.toInstant() ;

要调整到另一个时区,请将时区指定为YearQuarter对象。 以ZoneOffset.UTC格式指定正确的时区名称,例如YearQuarter,YearQuarter或Pacific/Auckland.切勿使用3-4个字母的伪区域,如EST或IST,因为它们不是真正的时区,不是标准化的,甚至不是 独特(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;

适用于YearQuarter以生成ZoneOffset.UTC对象。

ZonedDateTime zdt = instant.atZone( z ) ;

要生成一个字符串以显示给用户,请搜索Stack Overflow for YearQuarter以查找许多讨论和示例。

您的问题实际上是关于从用户数据输入到日期时间对象的另一个方向。 通常最好将您的数据输入分为两个部分,一个日期和一个时间。

LocalDate ld = LocalDate.parse( dateInput , DateTimeFormatter.ofPattern( "M/d/uuuu" , Locale.US ) ) ;

LocalTime lt = LocalTime.parse( timeInput , DateTimeFormatter.ofPattern( "H:m a" , Locale.US ) ) ;

你的问题不明确。 是否要将用户输入的日期和时间解释为UTC? 还是在另一个时区?

如果您的意思是UTC,请使用UTC的常量ZoneOffset.UTC创建一个带偏移量的YearQuarter。

OffsetDateTime odt = OffsetDateTime.of( ld , lt , ZoneOffset.UTC ) ;

如果您的意思是另一个时区,请与时区对象一起使用,即YearQuarter.但是哪个时区? 您可能会检测到默认时区。 或者,如果关键,您必须与用户确认他们的意图。

ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

要获得一个始终按UTC定义的更简单的对象,请提取YearQuarter。

Instant instant = odt.toInstant() ;

…要么…

Instant instant = zdt.toInstant() ;

发送到您的数据库。

myPreparedStatement.setObject( … , instant ) ;

关于java.time

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

现在处于维护模式的Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310。

从哪里获取java.time类?

Java SE 8,Java SE 9及更高版本内置。

带有捆绑实现的标准Java API的一部分。

Java 9增加了一些小功能和修复。

Java SE 6和Java SE 7许多java.time功能都被反向移植到Java 6& 7在ThreeTen-Backport。

Android的更高版本的Android捆绑java.time类的实现。

对于早期的Android,ThreeTenABP项目采用ThreeTen-Backport(如上所述)。 请参见如何使用ThreeTenABP ....

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

Basil Bourque answered 2019-08-12T00:07:26Z

java 时区处理_如何使用Java处理日历时区?相关推荐

  1. java 时区 列表_浅解 JAVA与时区

    时区转换 主要介绍一下 Java 时区转换相关的一些概念,和转换示例. 由于夏令时的存在,应该通过Java 或者 DB 提供的方法来转换. JAVA 时间的时区转换 Java Date 支持 UTC ...

  2. 马士兵 java 学习笔记_马士兵java教程笔记1

    ---恢复内容开始--- 前记 虽然已经是个研究生了,但是会的东西还是特别的少 甚至连java都不能说是很会 所以准备从现在开始能好好的学习java 变成java master 标识符 标识符是由字母 ...

  3. java 02-cf_cf活动如何设置java环境变量_如何设置java环境变量

    cf助手怎么连接wifi_连接无线网设置 对于刚刚学习java的win7用户来说,首先要学会安装jdk和配置java环境变量,这是学习java的唯一途径,否则编写的代码运行时会出现bug.关于这一点, ...

  4. java 字符串乱码_这份Java面试题含答案解析竟然真的让你不用在面试上“如履薄冰”...

    面试题集共分为以下十部分: 一.Core Java: 1 - 95 题1 - 24 页 基础及语法: 1 - 61 题1 - 13 页 异常: 62 - 69 题13 - 15 页 集合: 70 - ...

  5. java console 交互_实例讲解java中Console类的用法

    java的Console类的使用方法及实例 java的Console类的使用方法及实例 JDK 6中提供了java.io.Console类专用来访问基于字符的控制台设备.如果你的Java程序要与Win ...

  6. java for循环_愉快地学Java语言:第五章 循环

    导读 本文适合Java入门,不太适合Java中高级软件工程师.本文以<Java程序设计基础篇>第10版为蓝本,采用不断提出问题,然后解答问题的方式来讲述.本篇文章只是这个系列中的一篇,如果 ...

  7. java 内存空间_怎样用java实现存储空间动态分配

    1.java是如何管理内存的 Java的内存管理就是对象的分配和释放问题.(两部分) 分配 :内存的分配是由程序完成的,程序员需要通过关键字new 为每个对象申请内存空间 (基本类型除外),所有的对象 ...

  8. linux java远程调试_[转]JPDA:Java平台调试架构(常用的远程调试方法)

    原文出处:http://www.javaeye.com/topic/75128 最近使用WTP的Server功能很不爽,连tomcat服务器时java类中的任何改动都要重启服务器,一怒之下就改用JPD ...

  9. java在线编译器_什么是Java内存模型

    在知识星球中,有个小伙伴提了一个问题:有一个关于JVM名词定义的问题,说"JVM内存模型",有人会说是关于JVM内存分布(堆栈,方法区等)这些介绍,也有地方说(深入理解JVM虚拟机 ...

最新文章

  1. PFLD:简单、快速、超高精度人脸特征点检测算法
  2. Xstudio+Bugzilla
  3. 操作系统对比和未来展望
  4. 记一次mogodb占用cpu高问题
  5. 【转】Android 带checkbox的listView 实现多选,全选,反选 -- 不错
  6. 对象在内存中的存储布局
  7. Linux磁盘分区详解(parted)
  8. AMD深度学习库MIOpen更新,支持CNN加速
  9. jQuery 图表插件 jqChart 使用
  10. 清理oracle残留注册表,Oracle 卸载注册表残余文件清理
  11. ibm澳州业务_通过集体学习使业务用户能够使用IBM Blueworks Live和IBM Industry Models进行业务建模
  12. C++Windows连点器制作
  13. 警告: Establishing SSL connection without server
  14. Marshmallow详解
  15. 【玩转ElasticSearch】横向对比ElasticSearch与Sphinx
  16. faker造假数据的使用
  17. 博途v15模拟量转换_通过实例玩转博途之信号模块参数设置及模拟量输入转换举例...
  18. 香农编码C程序及演示结果
  19. scal开发环境搭建
  20. NASA绘制黑洞图像 高清版NASA绘制黑洞图像来了 这次终于看清了

热门文章

  1. 手把手系列—风控模型的调参方法和实际应用
  2. 反欺诈之设备指纹(下篇)
  3. last-child 选取不到指定元素,失去效果
  4. 20140213-面向对象技术概论
  5. hdu 1708 (字符串,Fibonacci )
  6. 深度学习的最新研究进展(二)
  7. 使用xadmin覆盖Django的admin
  8. 使用C#创建Windows服务 并发布Windows 服务
  9. 牛客网多校第9场 E Music Game 【思维+数学期望】
  10. Codevs 1205 单词反转(Vector以及如何输出string)