Ruby 将RFC3339格式化为URL的日期时间问题

Ruby 将RFC3339格式化为URL的日期时间问题,ruby,datetime,Ruby,Datetime,我试图将RFC3339格式的DateTime传递给API,但由于格式不正确而不断被拒绝。是否有其他方法转换为正确的格式 require 'cgi' require 'date' require 'uri' startTime=CGI.escape(DateTime.new(2016, 6, 6, 15, 47, 40).strftime("%Y-%m-%dT%H:%M:%SZ")) endTime=CGI.escape(DateTime.now.strftime("%Y-%m-%dT%H:%M

我试图将RFC3339格式的DateTime传递给API,但由于格式不正确而不断被拒绝。是否有其他方法转换为正确的格式

require 'cgi'
require 'date'
require 'uri'

startTime=CGI.escape(DateTime.new(2016, 6, 6, 15, 47, 40).strftime("%Y-%m-%dT%H:%M:%SZ"))
endTime=CGI.escape(DateTime.now.strftime("%Y-%m-%dT%H:%M:%SZ"))
puts startTime #start=2014-06-19T15%3A47%3A40Z   me:2016-05-19T16%3A47%3A04-04%3A00
puts endTime
hist_data=getData(startTime,endTime)

def getData(startTime,endTime)
  base="https://api-fxtrade.oanda.com/v1/candles?instrument="
  curr="EUR_USD"
  granularity="H1"
  #https://api-fxtrade.oanda.com/v1/candles?instrument=EUR_USD&start=2014-06-19T15%3A47%3A40Z&end=2014-06-19T15%3A47%3A50Z
  myurl = "#{ base }#{ curr }&candleFormat=bidask&granularity=#{ granularity }&dailyAlignment=0&alignmentTimezone=America%2FNew_York&start=#{startTime}&end=#{endTime}"
  puts myurl
  response =HTTParty.get(URI::encode(myurl))
  #{"time"=>"2016-06-03T20:00:00.000000Z", "openBid"=>1.1355, "openAsk"=>1.13564, "highBid"=>1.13727, "highAsk"=>1.13752, "lowBid"=>1.13541, "lowAsk"=>1.13554, "closeBid"=>1.13651, "closeAsk"=>1.13684, "volume"=>2523, "complete"=>true}
  response
end
但是,当我使用此代码时,结尾的网站url是有效的。我的代码的完整输出提供了以下内容:

https://api-fxtrade.oanda.com/v1/candles?instrument=EUR_USD&candleFormat=bidask&granularity=H1&dailyAlignment=0&alignmentTimezone=America%2FNew_York&start=2016-06-06T15%3A47%3A40Z&end=2016-06-08T21%3A53%3A44Z

你知道为什么在运行这个方法的时候它不起作用,但是在我粘贴URL的时候它就起作用了吗?我认为这是一个编码问题,但我肯定是在方法中编码URL

正如我在上面的评论中所说的,您自己尝试对查询参数进行编码,并使用插值/连接来构建URL,这让事情变得非常困难

我猜问题是您正在使用
CGI.escape
单独编码查询参数,然后第二次使用
URI.encode
。换句话说,你是在对它们进行双重编码

顺便说一句,
CGI.escape
URI.encode
或多或少做同样的事情(前者是)。不清楚为什么要同时使用这两种方法,但这是没有意义的,因为你不应该同时使用这两种方法。你应该让HTTParty为你做这件事

HTTParty.get
一个基本URL,并使用
:query
选项将您的(原始的,即未编码的)查询参数的散列传递给它,它将正确地为您进行所有编码。作为一种副作用,它使编写更干净的代码成为可能:

require "httparty"
require "date"

DATETIME_FMT = "%FT%TZ" # RFC 3339
BASE_URI = "https://api-fxtrade.oanda.com/v1/candles"

DEFAULT_PARAMS = {
  instrument: "EUR_USD",
  candleFormat: "bidask",
  granularity: "H1",
  dailyAlignment: 0,
  alignmentTimezone: "America/New_York",
}.freeze

def get_data(start_time, end_time)
  params = DEFAULT_PARAMS.merge(
    start: start_time.strftime(DATETIME_FMT),
    end: end_time.strftime(DATETIME_FMT)
  )

  HTTParty.get(BASE_URI, query: params)
end

start_time = DateTime.new(2016, 6, 6, 15, 47, 40)
end_time = DateTime.now

hist_data = get_data(start_time, end_time)

我真的不知道,但是因为它很容易尝试,我建议不要调用
URI::encode
,看看会发生什么。不要用字符串插值/串联构造URI查询参数。那样的话,只有绝望和疯狂。因为您使用的是HTTParty,所以不需要也不应该进行任何手动编码/转义。将您的查询参数传递给
HTTParty。使用
:query
选项以散列形式获取
。感谢您提供了非常全面的答案,它工作得非常好。