我正在尝试从定义为使用 RFC1123 兼容日期时间规范的数据源解析时间戳。我的代码是:
value = Instant.from (DateTimeFormatter.RFC_1123_DATE_TIME.parse (textValue));
这对某些数据工作正常,但我得到包含区域名称的字符串的异常,即使是在 RFC2822 中定义的字符串(它从 RFC1123 间接引用,因为它废弃了 RFC822)。示例:
java.time.format.DateTimeParseException: Text 'Sun, 20 Aug 2017 00:30:00 UT' could not be parsed at index 26
java.time.format.DateTimeParseException: Text 'Mon, 21 Aug 2017 15:00:00 EST' could not be parsed at index 26
如何说服 DateTimeFormatter 接受这种类型的日期?
最佳答案
正如 @shmosel's comment 注意到的那样, javadoc says RFC_1123_DATE_TIME “不处理北美或军区名称,仅处理‘GMT’和偏移量”。
要使其识别像 UT 和 EST 这样的短时区名称,唯一的方法是构建一个自定义格式化程序,其结构类似于 RFC_1123_DATE_TIME 有,但是最后加了短区ID。
此格式使用英语名称表示月份和星期几,因此一种替代方法是使用英语语言环境,但 source code使用具有固定值的自定义 map ,以便在更改时不依赖于语言环境(评论说语言环境数据可以通过应用程序代码更改)。所以我们首先重新创建这些 map :
// custom map for days of week
Map<Long, String> dow = new HashMap<>();
dow.put(1L, "Mon");
dow.put(2L, "Tue");
dow.put(3L, "Wed");
dow.put(4L, "Thu");
dow.put(5L, "Fri");
dow.put(6L, "Sat");
dow.put(7L, "Sun");
// custom map for months
Map<Long, String> moy = new HashMap<>();
moy.put(1L, "Jan");
moy.put(2L, "Feb");
moy.put(3L, "Mar");
moy.put(4L, "Apr");
moy.put(5L, "May");
moy.put(6L, "Jun");
moy.put(7L, "Jul");
moy.put(8L, "Aug");
moy.put(9L, "Sep");
moy.put(10L, "Oct");
moy.put(11L, "Nov");
moy.put(12L, "Dec");
然后我重新创建与 RFC_1123_DATE_TIME 相同的结构,但在最后添加区域 ID:
// create with same format as RFC_1123_DATE_TIME
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseLenient()
.optionalStart()
.appendText(DAY_OF_WEEK, dow)
.appendLiteral(", ")
.optionalEnd()
.appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE)
.appendLiteral(' ')
.appendText(MONTH_OF_YEAR, moy)
.appendLiteral(' ')
.appendValue(YEAR, 4) // 2 digit year not handled
.appendLiteral(' ')
.appendValue(HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.optionalEnd()
.appendLiteral(' ')
// difference from RFC_1123_DATE_TIME: optional offset OR zone ID
.optionalStart()
.appendZoneText(TextStyle.SHORT)
.optionalEnd()
.optionalStart()
.appendOffset("+HHMM", "GMT")
// use the same resolver style and chronology
.toFormatter().withResolverStyle(ResolverStyle.SMART).withChronology(IsoChronology.INSTANCE);
这里的区别是 .appendZoneText(TextStyle.SHORT)(与 optionalStart() 因为它可以有偏移量/GMT 或 一个短区域 ID)。
您还会注意到在 source code 中它使用:
.toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
但是 toFormatter 的重载版本并不公开。所以我不得不使用 with 方法来相应地调整值。
使用这个格式化程序,我可以解析输入:
System.out.println(Instant.from(fmt.parse("Mon, 21 Aug 2017 15:00:00 EST")));
System.out.println(Instant.from(fmt.parse("Sun, 20 Aug 2017 00:30:00 UT")));
输出是:
2017-08-21T19:00:00Z
2017-08-20T00:30:00Z
PS:像 EST 这样的短名称是 ambiguous and not standard .理想的是始终使用 IANA timezones names (始终采用 Region/City 格式,例如 America/New_York 或 Europe/London)。
EST 不明确,因为有 more than one timezone that uses it .一些短名称无法识别,但由于追溯兼容性原因,其中一些短名称被设置为任意默认值。例如,EST 映射到 America/New_York,如果我将它解析为 ZonedDateTime:
System.out.println(ZonedDateTime.from(fmt.parse("Mon, 21 Aug 2017 15:00:00 EST")));
输出是:
2017-08-21T15:00-04:00[America/New_York]
也许这不适用于您的情况,因为您正在将所有内容解析为 Instant,但是如果您想要 ZonedDateTime,可以通过定义来更改这些默认值一组首选区域:
// set of preferred zones
Set<ZoneId> preferredZones = new HashSet<>();
// add my arbitrary choices
preferredZones.add(ZoneId.of("America/Indianapolis"));
America/Indianapolis 是另一个使用 EST 作为短名称的时区,因此我可以将其设置为首选而不是默认的 America/New_York。我只需要在格式化程序中设置它。而不是这个:
.appendZoneText(TextStyle.SHORT)
我称之为:
.appendZoneText(TextStyle.SHORT, preferredZones)
现在将使用我的首选任意区域。同样的代码:
System.out.println(ZonedDateTime.from(fmt.parse("Mon, 21 Aug 2017 15:00:00 EST")));
现在打印:
2017-08-21T15:00-04:00[America/Indianapolis]
另请注意,上面的 ZonedDateTime 的偏移量为 -04:00。那是因为在 8 月,这些区域处于夏令时 (DST),因此实际上各自的简称是 EDT。如果您使用上面相同的格式化程序格式化日期:
System.out.println(ZonedDateTime.now(ZoneId.of("America/New_York")).format(fmt));
输出将是:
Wed, 23 Aug 2017 08:43:52 EDT-0400
请注意,格式化程序使用所有可选部分来打印日期(因此它同时打印区域 ID EDT 和偏移量 -0400)。如果您只想打印其中一个,则必须创建另一个格式化程序(或者只使用 RFC_1123_DATE_TIME)。
除了 appendZoneText 和 appendOffset,您还可以使用:
.appendPattern("[z][x]")
注意可选部分(由 [] 分隔)。这将解析区域 ID (z) 或偏移量 (x)。看docs for more details关于模式。
唯一的区别是使用此模式您不能使用首选区域集。
为了格式化,这也将打印这两个字段(因此输出将类似于 EDT-0400)。
关于java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME 无法解析时区名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45829799/
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问
我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)
我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类