不更改时区的日期时间解析



这里有字符串类型的日期和时间值。

  • appDate=2/19/2019
  • 开始时间=下午4:15

我想通过api在谷歌日历中插入一个事件。

当我解析日期字符串时,它会根据我的本地区域设置进行转换。我住在GMT+03:00时区。但我想在字符串中按原样插入日期和时间。

按原样输出:{dateTime=2019-01-19T04:15:00.000+03:00,时区=美国/纽约}

我需要得到这个:{dateTime=2019-01-19T04:15:00.000-05:00,时区=美国/纽约}

使用下面的代码块,它将晚上8:15插入谷歌日历。

SimpleDateFormat formatter = new SimpleDateFormat("mm/dd/yyyy HH:mm a", Locale.US);
String dateInString = appDate + " " + startTime;
Date date = formatter.parse(dateInString);
DateTime startDateTime = new DateTime(date);
EventDateTime start = new EventDateTime().setDateTime(startDateTime).setTimeZone("America/New_York");

java.time

您在遗留java.util.Date和相关类周围遇到了非常常见的混淆源。您应该使用Java 8:中引入的较新的java.time

System.out.printf("INFO - System default timezone: %s%n", ZoneId.systemDefault().getId());
// INFO - System default timezone: Europe/Moscow
// test data
String appDate = "2/19/2019";
String startTime = "4:15 PM";
String targetTimezone = "America/New_York";
String dateInString = appDate + " " + startTime;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy h:mm a");
LocalDateTime ldt = LocalDateTime.parse(dateInString, formatter);
ZonedDateTime zdt = ldt.atZone(ZoneId.of(targetTimezone));
System.out.println(zdt);  // 2019-02-19T16:15-05:00[America/New_York]

正如您所看到的,ZonedDateTime是使用正确的本地时间(16:15=下午4:15)、正确的偏移量(-05:00)和明确指定的时区(美国/纽约)创建的。

如果幸运的话,Google日历API将能够使用java.time类。但是,无论出于何种原因,如果您需要恢复到java.util.Date,您总是可以通过调用添加到旧类中的新方法来进行转换。从ZonedDateTime中提取一个Instant(从区域调整为UTC),然后传递到新的Date.from方法。

java.util.Date date = java.util.Date.from( zdt.toInstant() );
System.out.println(date);  // Wed Feb 20 00:15:00 MSK 2019
System.out.println(date.getTime());  // 1550610900000

请注意,java.util.Date是使用JVM的当前默认时区Europe/Moscow打印的,因此日期和时间已相应调整。然而,两个值(2019-02-19T16:15-05:00[America/New_York]Wed Feb 20 00:15:00 MSK 2019)表示相同的时刻:历元(1970-01-01 00:00:00 UTC)之后的1550610900000毫秒。

SimpleDateFormat允许您指定要从中解析的TimeZone

例如:formatter.setTimeZone(TimeZone.getTimeZone("America/New_York"));

或者,如果您只是想要一个自定义的GMT-5时区(即:没有任何特定位置的夏令时规则):formatter.setTimeZone(TimeZone.getTimeZone("GMT-5"));

编辑:有机会查看问题的第二部分,并查看您正在使用的日历api-假设您在这里使用的google api类是com.google.apisgroupId、google-api-services-calendarartifactId中的类,那么您还需要在实例化com.google.api.client.util.DateTime实例时指定偏移量的TimeZone

使用具有指定纽约时区的SimpleDateFormat将字符串"2/19/2019下午4:15"解析为日期,将获得一个包含长值1550610900000的java.util.Date(无论您的实际本地时区如何)。请注意,如果您打印该DatetoString(),它将在本地机器的时区中给出日期。例如:对我来说,上面写着"2019年2月20日星期三05:15:00 SGT"。

DateTime通过getTime()从指定的Date中提取该长值,并在内部将其存储为长值。

DateTime(或者至少是我快速尝试的DateTime类的版本(v3-rev364-1.25.0)也有一个构造函数,它采用TimeZone,通过getOffset()从UTC提取偏移量。如果你不通过它,它将在内部使用TimeZone.getDefault().getOffset(value)。稍后,当调用它的toString()时,它将使用它存储的偏移量(从时区获得)来渲染它。

示例:

SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm a", Locale.US);
formatter.setTimeZone(TimeZone.getTimeZone("America/New_York"));
Date date = formatter.parse("2/19/2019 4:15 PM");
DateTime startDateTimeNY = new DateTime(date,TimeZone.getTimeZone("America/New_York")); 
DateTime startDateTimeSG = new DateTime(date,TimeZone.getTimeZone("Asia/Singapore"));   
DateTime startDateTimeNBO = new DateTime(date,TimeZone.getTimeZone("Africa/Nairobi"));  
System.out.println(startDateTimeNY); //prints 2019-02-19T16:15:00.000-05:00
System.out.println(startDateTimeSG); //prints 2019-02-20T05:15:00.000+08:00
System.out.println(startDateTimeNBO); //prints 2019-02-20T00:15:00.000+03:00

(您可以在输出中看到不同的本地时间)

我还没有时间确认,但看起来EventDateTime只是使用DateTime中的toString()作为dateTime值(如果您没有设置JsonFactory)。(它为另一个目的存储的时区?)

TLDR:在SimpleDateFormat上指定TimeZone可以让您从其源时区正确读取日期,并且要根据需要格式化输出,您还需要更改对DateTime构造函数的调用,以便使用所需时区:

DateTime startDateTime = new DateTime(date,TimeZone.getTimeZone("America/New_York"));

相关内容

  • 没有找到相关文章

最新更新