不更改时区的日期时间解析
datetime parsing without changing timezone
我这里有字符串类型的日期和时间值。
- appDate = 2/19/2019
- 开始时间=4:15下午
我想通过 api 在 google 日历中插入一个事件。
当我解析日期字符串时,它会根据我的本地区域设置进行转换。我住在 GMT+03.00 时区。但我想按字符串中的原样插入日期和时间。
输出如下:
{dateTime=2019-01-19T04:15:00.000+03:00, timeZone=America/New_York}
我需要得到这个:
{dateTime=2019-01-19T04:15:00.000-05:00, timeZone=America/New_York}
使用下面的代码块,它将 8:15 pm 插入 google 日历。
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");
SimpleDateFormat
允许您指定要解析的 TimeZone
。
例如:
formatter.setTimeZone(TimeZone.getTimeZone("America/New_York"));
或者如果您只是想要一个自定义的 GMT-5 时区(即:没有任何特定位置的 DST 规则):
formatter.setTimeZone(TimeZone.getTimeZone("GMT-5"));
编辑:有机会查看问题的第二部分,并查看您正在使用的日历 api - 并假设google api class你这里用的是com.google.apis
groupId,google-api-services-calendar
artifactId,那么你还要指定TimeZone
实例化 com.google.api.client.util.DateTime
实例时的偏移量。
使用纽约指定时区的 SimpleDateFormat
将字符串“2/19/2019 4:15 PM”解析为日期,您将得到一个 java.util.Date
换行long 值 1550610900000(不管您实际的本地时区)。请注意,如果您打印 Date
的 toString()
,它将给出本地计算机时区中的日期。例如:对我来说它说 "Wed Feb 20 05:15:00 SGT 2019"。
DateTime
通过 getTime() 从指定的 Date 中提取 long 值并在内部将其存储为 long。
DateTime
(或者至少是 DateTime class 的版本,我很快就抓住它进行了实验 (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"));
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 PM)、正确的偏移量 (-05:00) 和时间创建明确指定的区域 (America/New_York).
如果幸运的话,Google 日历 API 将能够与 java.time
类 一起使用。但是,如果您出于任何原因需要恢复到 java.util.Date
,您始终可以通过调用添加到旧 类 的新方法来进行转换。提取一个Instant
from the ZonedDateTime
(to adjust from zone to UTC), then pass to the new 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 毫秒
我这里有字符串类型的日期和时间值。
- appDate = 2/19/2019
- 开始时间=4:15下午
我想通过 api 在 google 日历中插入一个事件。
当我解析日期字符串时,它会根据我的本地区域设置进行转换。我住在 GMT+03.00 时区。但我想按字符串中的原样插入日期和时间。
输出如下: {dateTime=2019-01-19T04:15:00.000+03:00, timeZone=America/New_York}
我需要得到这个: {dateTime=2019-01-19T04:15:00.000-05:00, timeZone=America/New_York}
使用下面的代码块,它将 8:15 pm 插入 google 日历。
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");
SimpleDateFormat
允许您指定要解析的 TimeZone
。
例如:
formatter.setTimeZone(TimeZone.getTimeZone("America/New_York"));
或者如果您只是想要一个自定义的 GMT-5 时区(即:没有任何特定位置的 DST 规则):
formatter.setTimeZone(TimeZone.getTimeZone("GMT-5"));
编辑:有机会查看问题的第二部分,并查看您正在使用的日历 api - 并假设google api class你这里用的是com.google.apis
groupId,google-api-services-calendar
artifactId,那么你还要指定TimeZone
实例化 com.google.api.client.util.DateTime
实例时的偏移量。
使用纽约指定时区的 SimpleDateFormat
将字符串“2/19/2019 4:15 PM”解析为日期,您将得到一个 java.util.Date
换行long 值 1550610900000(不管您实际的本地时区)。请注意,如果您打印 Date
的 toString()
,它将给出本地计算机时区中的日期。例如:对我来说它说 "Wed Feb 20 05:15:00 SGT 2019"。
DateTime
通过 getTime() 从指定的 Date 中提取 long 值并在内部将其存储为 long。
DateTime
(或者至少是 DateTime class 的版本,我很快就抓住它进行了实验 (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"));
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 PM)、正确的偏移量 (-05:00) 和时间创建明确指定的区域 (America/New_York).
如果幸运的话,Google 日历 API 将能够与 java.time
类 一起使用。但是,如果您出于任何原因需要恢复到 java.util.Date
,您始终可以通过调用添加到旧 类 的新方法来进行转换。提取一个Instant
from the ZonedDateTime
(to adjust from zone to UTC), then pass to the new 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
).