我正在尝试编写一个泛型方法来返回ZonedDateTime给定日期为String及其格式。

如果String未在日期String中指定,我们如何使ZonedDateTime使用默认ZoneId?

它可以用java.util.Calendar完成,但我想使用Java 8时间API。

这里的问题是使用固定的时区。 我将格式指定为参数。 日期及其格式都是String参数。 更通用。

代码和输出如下:

public class DateUtil {

/** Convert a given String to ZonedDateTime. Use default Zone in string does not have zone.  */

public ZonedDateTime parseToZonedDateTime(String date, String dateFormat) {

//use java.time from java 8

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);

ZonedDateTime zonedDateTime = ZonedDateTime.parse(date, formatter);

return zonedDateTime;

}

public static void main(String args[]) {

DateUtil dateUtil = new DateUtil();

System.out.println(dateUtil.parseToZonedDateTime("2017-09-14 15:00:00+0530","yyyy-MM-dd HH:mm:ssZ"));

System.out.println(dateUtil.parseToZonedDateTime("2017-09-14 15:00:00","yyyy-MM-dd HH:mm:ss"));

}

}

产量

2017-09-14T15:00+05:30

Exception in thread"main" java.time.format.DateTimeParseException: Text '2017-09-14 15:00:00' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO resolved to 2017-09-14T15:00 of type java.time.format.Parsed

at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)

at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)

at java.time.ZonedDateTime.parse(ZonedDateTime.java:597)

at com.nam.sfmerchstorefhs.util.DateUtil.parseToZonedDateTime(DateUtil.java:81)

at com.nam.sfmerchstorefhs.util.DateUtil.main(DateUtil.java:97)

Caused by: java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO resolved to 2017-09-14T15:00 of type java.time.format.Parsed

at java.time.ZonedDateTime.from(ZonedDateTime.java:565)

at java.time.format.Parsed.query(Parsed.java:226)

at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)

... 3 more

Caused by: java.time.DateTimeException: Unable to obtain ZoneId from TemporalAccessor: {},ISO resolved to 2017-09-14T15:00 of type java.time.format.Parsed

at java.time.ZoneId.from(ZoneId.java:466)

at java.time.ZonedDateTime.from(ZonedDateTime.java:553)

... 5 more

如何使用默认区域解析ZonedDateTime可能重复?

谢谢各位的回应。 很有帮助。 不幸的是,我只能接受一个答案。

ZonedDateTime需要构建时区或偏移量,第二个输入不需要它。 (它只包含日期和时间)。

因此,您需要检查是否可以构建ZonedDateTime,如果不是,则必须为其选择任意区域(因为输入没有指示正在使用的时区,您必须选择一个使用)。

一种替代方法是首先尝试创建ZonedDateTime,如果不可能,则创建LocalDateTime并将其转换为时区:

public ZonedDateTime parseToZonedDateTime(String date, String dateFormat) {

// use java.time from java 8

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);

ZonedDateTime zonedDateTime = null;

try {

zonedDateTime = ZonedDateTime.parse(date, formatter);

} catch (DateTimeException e) {

// couldn't parse to a ZoneDateTime, try LocalDateTime

LocalDateTime dt = LocalDateTime.parse(date, formatter);

// convert to a timezone

zonedDateTime = dt.atZone(ZoneId.systemDefault());

}

return zonedDateTime;

}

在上面的代码中,我使用的是ZoneId.systemDefault(),它获取了JVM默认时区,但是即使在运行时也可以在不事先通知的情况下进行更改,因此最好始终明确指出您正在使用的是哪一个。

API使用IANA时区名称(始终采用Region/City格式,如America/Sao_Paulo或Europe/Berlin)。

避免使用3个字母的缩写(如CST或PST),因为它们不明确且不标准。

您可以通过调用ZoneId.getAvailableZoneIds()获取可用时区列表(并选择最适合您系统的时区)。

如果要使用特定时区,只需使用ZoneId.of("America/New_York")(或ZoneId.getAvailableZoneIds()返回的任何其他有效名称,纽约只是一个示例)而不是ZoneId.systemDefault()。

另一种方法是使用parseBest()方法,尝试创建一个合适的日期对象(使用TemporalQuery的列表),直到它创建所需的类型:

public ZonedDateTime parseToZonedDateTime(String date, String dateFormat) {

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);

// try to create a ZonedDateTime, if it fails, try LocalDateTime

TemporalAccessor parsed = formatter.parseBest(date, ZonedDateTime::from, LocalDateTime::from);

// if it's a ZonedDateTime, return it

if (parsed instanceof ZonedDateTime) {

return (ZonedDateTime) parsed;

}

if (parsed instanceof LocalDateTime) {

// convert LocalDateTime to JVM default timezone

LocalDateTime dt = (LocalDateTime) parsed;

return dt.atZone(ZoneId.systemDefault());

}

// if it can't be parsed, return null or throw exception?

return null;

}

在这种情况下,我只使用ZonedDateTime::from和LocalDateTime::from,因此格式化程序将尝试首先创建ZonedDateTime,如果不可能,则尝试创建LocalDateTime。

然后我检查返回的类型是什么,并相应地执行操作。

您可以添加所需的任何类型(所有主要类型,例如LocalDate,LocalTime,OffsetDateTime等),使用from方法与parseBest一起使用 - 您还可以创建自己的自定义TemporalQuery如果你愿意,但我认为内置方法足以满足这种情况)。

夏令时

使用atZone()方法将LocalDateTime转换为ZonedDateTime时,有一些关于夏令时(DST)的棘手案例。

我将使用我所居住的时区(America/Sao_Paulo)作为示例,但这可能发生在使用DST的任何时区。

在S?o Paulo,DST于2016年10月16日开始:在午夜,时钟从午夜向上移动1小时到凌晨1点(偏移从-03:00变为-02:00)。因此,在这个时区中,00:00到00:59之间的所有当地时间都不存在(你也可以认为时钟从23:59:59.999999999直接变为01:00)。如果我在此间隔中创建本地日期,则会将其调整为下一个有效时刻:

ZoneId zone = ZoneId.of("America/Sao_Paulo");

// October 16th 2016 at midnight, DST started in Sao Paulo

LocalDateTime d = LocalDateTime.of(2016, 10, 16, 0, 0, 0, 0);

ZonedDateTime z = d.atZone(zone);

System.out.println(z);// adjusted to 2017-10-15T01:00-02:00[America/Sao_Paulo]

DST结束时:2017年2月19日午夜时钟,时钟从18点的午夜到晚上23点向后移动1小时(偏移量从-02:00变为-03:00)。所以从23:00到23:59的所有当地时间都存在两次(在两个偏移中:-03:00和-02:00),你必须决定你想要哪一个。

默认情况下,它使用DST结束前的偏移量,但您可以使用withLaterOffsetAtOverlap()方法在DST结束后获取偏移量:

// February 19th 2017 at midnight, DST ends in Sao Paulo

// local times from 23:00 to 23:59 at 18th exist twice

LocalDateTime d = LocalDateTime.of(2017, 2, 18, 23, 0, 0, 0);

// by default, it gets the offset before DST ends

ZonedDateTime beforeDST = d.atZone(zone);

System.out.println(beforeDST); // before DST end: 2018-02-17T23:00-02:00[America/Sao_Paulo]

// get the offset after DST ends

ZonedDateTime afterDST = beforeDST.withLaterOffsetAtOverlap();

System.out.println(afterDST); // after DST end: 2018-02-17T23:00-03:00[America/Sao_Paulo]

请注意,DST结束前后的日期具有不同的偏移量(-02:00和-03:00)。如果您正在使用具有DST的时区,请记住这些角落情况可能会发生。

根据Java 8 ZonedDateTime实现,您无法在ZonedDateTime中解析没有区域的日期。

为了满足给定的问题,你必须把try catch放在它将考虑默认时区的任何异常的情况下。

请找到修改后的程序如下:

public class DateUtil {

/** Convert a given String to ZonedDateTime. Use default Zone in string does not have zone.  */

public ZonedDateTime parseToZonedDateTime(String date, String dateFormat) {

//use java.time from java 8

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);

ZonedDateTime zonedDateTime = null;

try {

zonedDateTime = ZonedDateTime.parse(date, formatter);

} catch (DateTimeException e) {

// If date doesn't contains Zone then parse with LocalDateTime

LocalDateTime localDateTime = LocalDateTime.parse(date, formatter);

zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());

}

return zonedDateTime;

}

public static void main(String args[]) {

DateUtil dateUtil = new DateUtil();

System.out.println(dateUtil.parseToZonedDateTime("2017-09-14 15:00:00+0530","yyyy-MM-dd HH:mm:ssZ"));

System.out.println(dateUtil.parseToZonedDateTime("2017-09-14 15:00:00","yyyy-MM-dd HH:mm:ss"));

}

}

有关即将推出的Java功能的更多详细信息,请参考http://www.codenuclear.com/java-8-date-time-intro

java.time库中没有默认设置,这是一件好事 - 你所看到的就是你得到的东西,句号。

我建议如果你的日期字符串不包含Zone - 它是LocalDateTime,并且不能是ZonedDateTime,这就是你得到的异常的含义(即使由于过于灵活而导致措辞受到影响代码结构)。

我的主要建议是,如果您知道该模式没有区域信息,则解析为本地日期时间。

但是,如果你真的必须,这是另一种方法来做你想要的(一种不使用异常来控制流的替代解决方案):

TemporalAccessor parsed = f.parse(string);

if (parsed.query(TemporalQueries.zone()) == null) {

parsed = f.withZone(ZoneId.systemDefault()).parse(string);

}

return ZonedDateTime.from(parsed);

这里我们使用中间解析结果来确定字符串是否包含区域信息,如果没有,我们再次解析(使用相同的字符串,但不同的打印机解析器),这次它将包含一个区域。

或者,您可以创建此类,这将使您免于解析第二次,并且应该允许您解析分区日期时间,假设所有其他字段都在那里:

class TemporalWithZone implements TemporalAccessor {

private final ZoneId zone;

private final TemporalAccessor delegate;

public TemporalWithZone(TemporalAccessor delegate, ZoneId zone) {

this.delegate = requireNonNull(delegate);

this.zone = requireNonNull(zone);

}

public R query(TemporalQuery query) {

if (query == TemporalQueries.zone() || query == TemporalQueries.zoneId()) {

return (R) zone;

}

return delegate.query(query);

}

}

如果没有OFFSET_SECOND,您只需在DateTimeFormatterBuilder中添加默认值:

编辑:要获得系统的默认值ZoneOffset,您必须将ZoneRules应用于当前的Instant。结果如下:

class DateUtil {

public ZonedDateTime parseToZonedDateTime(String date, String dateFormat) {

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);

LocalDateTime localDateTime = LocalDateTime.parse(date, formatter);

ZoneOffset defaultOffset =  ZoneId.systemDefault().getRules().getOffset(localDateTime);

DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()

.append(formatter)

.parseDefaulting(ChronoField.OFFSET_SECONDS, defaultOffset.getTotalSeconds())

.toFormatter();

return ZonedDateTime.parse(date, dateTimeFormatter);

}

}

输出:

2017-09-14T15:00+05:30

2017-09-14T15:00+02:00

关于夏令时,使用Instant.now()的偏移量有一个棘手的情况。 示例:在我的JVM中,默认区域为America/Sao_Paulo。 冬季偏移为-03:00,夏令时(10月开始)偏移为-02:00。 如果我用params "2017-11-14 15:00:00","yyyy-MM-dd HH:mm:ss"调用你的方法,它将在11月11日15:00和当前偏移量(-03:00)得到一个日期,但正确的(IMO)应该是当地日期有效的偏移量 对应于输入(在这种情况下,在十一月,当它已经是DST时,因此偏移应该是-02:00)。

然后查看API并选择正确的方法:ZoneRules::getOffset vs. ZoneRules::getStandardOffset。 OP并非那么具体。

可以使用DateTimeFormatter中的withZone方法指定ZoneId:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat).withZone("+0530");

只是从我拥有的项目中复制此解决方案:

formatter = DateTimeFormatter.ofPattern(dateFormat).withZone(ZONE_UTC);

编译格式化程序后,可以调用withZone(ZoneId)创建具有设置时区的新格式化程序。

这将忽略第一个输入中的偏移+0530

然后尝试OffsetDateTime,因为Zoned需要知道区域规则。

好吧,OP要求ZonedDateTime和默认时区(不是UTC)。

java zoneid 中国_关于时区:Java 8 Time API – ZonedDateTime – 在解析时指定默认的ZoneId...相关推荐

  1. java yyyy-mm-dd 毫秒_如何在Java中以YYYY-MM-DD HH:MI:秒毫秒格式获取当前时间?

    下面的代码为我提供了当前时间. 但这并不能说明毫秒. public static String getCurrentTimeStamp() { SimpleDateFormat sdfDate = n ...

  2. macbook配置java环境变量_如何安装Java和配置环境变量

    本文是Java下载.安装.环境变量配置的具体步骤,关于环境变量的原理参阅: Java轻松入门经典教程-环境变量配置​ke.qq.com Java年构架师技术栈/微服务/源码分析/分布式/高并发/性能优 ...

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

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

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

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

  5. 哈尔滨java开发工资_给哈尔滨Java开发初学者的几个学习建议

    对于初学者应该如何学习Java开发技术,纵观中国目前整体行业来说,互联网IT行业成为了拔尖的行业,IT互联网程序开发成了靠自己能力可以多挣一点钱,所以各个行业都在转行,其实互联网不存在饱和,只不过大多 ...

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

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

  7. futuretask java 并发请求_图文并茂理解 Java 多线程

    优质文章,及时送达 线程 线程的概念,百度是这样解释的: 线程(英语:Thread)是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的 ...

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

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

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

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

最新文章

  1. python 图像分割_Python怎么实现图片分割?
  2. htc在ubuntu上找不到devieces,提示权限不够的解决方法
  3. 上传图片到linux返回url,Springboot 将前端传递的图片上传至Linux服务器并返回图片的url(附源码)...
  4. matlab 蜂窝网格,blender怎么制作蜂巢网格 蜂窝式网格画法
  5. java 执行html里的js_如何用java执行指定页面中的js代码
  6. 关于c++的一些案例
  7. micropython编译原理_C语言嵌入式Linux高级编程第9期:CPU和操作系统入门视频课程...
  8. 单机 搭建kafka集群 本地_10分钟搭建单机Kafka集群
  9. 苹果手机长截屏_iPhone终于自带长截屏了?苹果手机这些截图方式,你用过几种?...
  10. 简书网页劫持分析,网站劫持,利用 CSP 预防劫持
  11. bandicom录屏音画不同步_bandicam录屏工具
  12. 助过网:一个月时间怎么科学有效复习公务员考试?
  13. 一篇论文的正确格式是什么?
  14. 移动端适配时对meta name=“viewport“ content=“width=device-width,initial-scale=1.0“的理解
  15. w3cshool 的一些学习笔记
  16. Android集成小米华为推送以及收不到离线消息的坑
  17. geoserver的api接口_geoserver api
  18. WordPress多站点发布文章同步,API实现一篇文章发布多个平台(同栏目)
  19. matlab直接扩频序列,直接序列扩频系统matlab仿真.doc
  20. 京东2016笔试题【分苹果】-简单的公式法

热门文章

  1. python javascript区别_Python,Java和JavaScript这3个编程语言未来哪个更有前景?
  2. RAKsmart韩国服务器与日本服务器的差异
  3. Quartus-ii的LPT1编程硬件配置问题
  4. 一键模拟登陆华师大公共数据库!ver2.0
  5. 七张图总结了我的2021年,心依然热,情依然真----感谢2021年的自己,感谢CSDN
  6. 读文献——《Very Deep Convolutional Networks for Large-scale Image Recognition》
  7. MCU裸系统下快速平方根实现
  8. 【EE】案例分享-如何设计继电器电路?
  9. 运筹学--线性目标规划
  10. 黑灰白箱测试+Ubuntu wireshark wifibluetooth