带时区的 Strptime

发布于 2024-12-12 00:25:31 字数 236 浏览 0 评论 0原文

我有一个用 DateTime.strptime 解析的字符串。字符串中日期的时区是 CET,但 Ruby 创建了一个 UTC DateTime 对象,当然它有 2 小时的偏移量。

目前我正在使用 DateTime.strptime().change(:offset => "+0020") 解决这个问题,但我很确定这不是它应该工作的方式。

有人可以启发我正确的方法吗?

I have a String which I parse with DateTime.strptime. The Timezone of the Date in the String is CET but Ruby creates an UTC DateTime object which of course has an offset of 2hrs.

Currently I'm working around the issue with DateTime.strptime().change(:offset => "+0020") but I'm pretty sure this is not the way it's meant to work.

Can someone enlighten me on the correct way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

最佳男配角 2024-12-19 00:25:31

我按以下方式使用它:

ruby-1.9.2-head :001 > require 'date'
 => true 
ruby-1.9.2-head :002 > fmt = "%m-%d-%Y %H:%M:%S %Z"
 => "%m-%d-%Y %H:%M:%S %Z" 
ruby-1.9.2-head :003 > DateTime.strptime "10-26-2011 10:16:29 CET", fmt
 => #<DateTime: 2011-10-26T10:16:29+01:00 (212186380589/86400,1/24,2299161)> 
ruby-1.9.2-head :004 > DateTime.strptime "10-26-2011 10:16:29 UTC", fmt
 => #<DateTime: 2011-10-26T10:16:29+00:00 (212186384189/86400,0/1,2299161)> 
ruby-1.9.2-head :005 > DateTime.strptime "10-26-2011 10:16:29 PST", fmt
 => #<DateTime: 2011-10-26T10:16:29-08:00 (212186412989/86400,-1/3,2299161)> 

这是你的意思吗?

I use it the following way:

ruby-1.9.2-head :001 > require 'date'
 => true 
ruby-1.9.2-head :002 > fmt = "%m-%d-%Y %H:%M:%S %Z"
 => "%m-%d-%Y %H:%M:%S %Z" 
ruby-1.9.2-head :003 > DateTime.strptime "10-26-2011 10:16:29 CET", fmt
 => #<DateTime: 2011-10-26T10:16:29+01:00 (212186380589/86400,1/24,2299161)> 
ruby-1.9.2-head :004 > DateTime.strptime "10-26-2011 10:16:29 UTC", fmt
 => #<DateTime: 2011-10-26T10:16:29+00:00 (212186384189/86400,0/1,2299161)> 
ruby-1.9.2-head :005 > DateTime.strptime "10-26-2011 10:16:29 PST", fmt
 => #<DateTime: 2011-10-26T10:16:29-08:00 (212186412989/86400,-1/3,2299161)> 

Is it what you mean?

会发光的星星闪亮亮i 2024-12-19 00:25:31

这适用于 Rails 5:

Time.zone.strptime("2017-05-20 18:20:10", "%Y-%m-%d %H:%M:%S")

返回指定时区的时间。

This works in Rails 5:

Time.zone.strptime("2017-05-20 18:20:10", "%Y-%m-%d %H:%M:%S")

Returns the time in the specified time zone.

猫瑾少女 2024-12-19 00:25:31

至少从 Rails 4.2 开始(可能更早,尚未测试)只要您使用 Time#strptime 而不是 DateTime.strptime,就会自动应用当前时区:

> DateTime.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> Wed, 28 Dec 2016 17:00:00 +0000

> Time.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> 2016-12-28 17:00:00 -0800

At least as of Rails 4.2 (maybe earlier, haven't tested) as long as you use Time#strptime instead of DateTime.strptime, the current time zone is automatically applied:

> DateTime.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> Wed, 28 Dec 2016 17:00:00 +0000

> Time.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> 2016-12-28 17:00:00 -0800
触ぅ动初心 2024-12-19 00:25:31

我正在“strptiming”这个字符串:

19/05/2014 8:13:26 a.m.

本地时间戳,在我的例子中是奥克兰新西兰,字符串中没有时区时间戳,如图所示。

据我所知 Time.strptime 使用服务器时区作为基础。

在我的情况和一般的良好实践中,我的服务器在 UTC 时区运行,因此字符串的每次解析最终都会创建一个时间对象,即 +0000 (UTC) 的时间:

2014-05-19 08:13:26 +0000

然后转换为 in_time_zone(Time.zone)< /code> 给出:

Mon, 19 May 2014 20:13:26 NZST +12:00

可以看出,这比我想要的实际时间晚了 12 小时(UTC 偏移量)。

我尝试按照上面的方式使用 +' Oakland', '...%Z' 技巧,无需任何更改。
然后我按照上面的方法使用了 + '+1200', '...%Z' 技巧,它工作正常。

然而,我担心夏天的时间,那么解析会花费一个小时,所以这就是我完成的结果:

Time.strptime(call_data[:datetime].gsub(/\./, "").gsub(/am/, "AM").gsub(/pm/, "PM") + (Time.zone.now.time_zone.utc_offset/3600).to_s.ljust(4,'0').rjust(6,' +'), '%d/%m/%Y %I:%M:%S %p %Z').in_time_zone(Time.zone)

结果:

Mon, 19 May 2014 08:13:26 NZST +12:00

它不是特别优雅,但它有效。

I was "strptiming" this string:

19/05/2014 8:13:26 a.m.

A local timestamp, which is in my case is Auckland NZ without a timezone stamp in the string as can be seen.

As best I can tell Time.strptime uses the server timezone as the base.

In my situation, and general good practice, my servers run in UTC timezone so every parse of the string ended up creating a time object, the time to +0000 (UTC):

2014-05-19 08:13:26 +0000

Then converting to in_time_zone(Time.zone) gave:

Mon, 19 May 2014 20:13:26 NZST +12:00

Which as can be seen is 12 hours (the UTC offset) later than the actual time I wanted.

I tried to use the +' Auckland', '...%Z' trick as per above without any change.
I then used the + '+1200', '...%Z' trick as per above which worked correctly.

However I was concerned about summer time, then the parsing would be out by an hour, so this is what I've finshed with:

Time.strptime(call_data[:datetime].gsub(/\./, "").gsub(/am/, "AM").gsub(/pm/, "PM") + (Time.zone.now.time_zone.utc_offset/3600).to_s.ljust(4,'0').rjust(6,' +'), '%d/%m/%Y %I:%M:%S %p %Z').in_time_zone(Time.zone)

Result:

Mon, 19 May 2014 08:13:26 NZST +12:00

It's not particularly elegant but it works.

又怨 2024-12-19 00:25:31

您可以使用 to_time_in_current_zone 将日期转换为时区。例如:

Date.strptime('04/07/1988', '%m/%d/%Y').to_time_in_current_zone

You can convert date to timezone with to_time_in_current_zone. For example:

Date.strptime('04/07/1988', '%m/%d/%Y').to_time_in_current_zone
夜清冷一曲。 2024-12-19 00:25:31

我一直在努力解决同样的问题,试图从表单中解析日期字符串并独立于服务器时间保存它。我遵循的过程就是这样。
我保证 RoR 和 Ruby 时区设置为 UTC。如果服务器也采用 UTC 时间,事情会变得更容易。

我使用 ActiveSupport:TimeZone 格式存储用户区域设置,例如 US/Eastern
我有一个解释日期函数,它可以解释本身不包含时区或偏移量的日期字符串,

# date_str looks something like this `12/31/2014 6:22 PM`
# tz is a string containing an ActiveSupport::TimeZone name like `US/Eastern`
def interpret_date(date_str, tz)
  Time.use_zone tz do
    parsed_dt = DateTime.strptime(date_str, '%m/%d/%Y %H:%M %p')
    offset = parsed_dt.in_time_zone(tz).utc_offset
    parsed_dt.advance(seconds: -(offset)).in_time_zone(tz)
  end
end

这当然感觉不是一个完美的解决方案,但它有效。
确保时区正确的步骤是:

  1. 根据我们的格式解析日期字符串 根据
  2. 该时区的时间提取当前 utc 偏移量(如果您正在解析的日期恰好是 dst 而您的本地时间,我们必须这样做不是东部时间的夏令时,这将确保夏令时是解析时间的本地时间)
  3. 将时间转换为我们的目标区域设置,并允许时间随着添加的正确偏移量而变化

I have been battling this same issue trying to parse a date string from a form and save it independently of the servers time. The process I have followed is as such.
I assure the RoR and Ruby timezones are set to UTC. It makes it easier if the server is on UTC time as well.

I am storing the users locale using the ActiveSupport:TimeZone format like US/Eastern
I have an interpret date function which can account for a date string that doesn't natively contain a timezone or offset

# date_str looks something like this `12/31/2014 6:22 PM`
# tz is a string containing an ActiveSupport::TimeZone name like `US/Eastern`
def interpret_date(date_str, tz)
  Time.use_zone tz do
    parsed_dt = DateTime.strptime(date_str, '%m/%d/%Y %H:%M %p')
    offset = parsed_dt.in_time_zone(tz).utc_offset
    parsed_dt.advance(seconds: -(offset)).in_time_zone(tz)
  end
end

This of course doesn't feel like a perfect solution but it works.
The steps to assure the correct timezone are:

  1. Parse the date string according to our format
  2. Extract the current utc offset based upon the time in that timezone (We have to do this if the date you are parsing happens to be in dst while your local time is not dst for eastern time this will assure that the dst is local to the parsed time)
  3. Convert the time to our target locale and allow the time to shift with the correct offset added
深巷少女 2024-12-19 00:25:31

对于 Rails 5 之前的版本,以下内容将起作用:

t0 = Time.strptime("2018-05-01", "%Y-%m-%d") # Or whatever
t1 = Time.zone.now.change(year: t0.year, month: t0.month, day: t0.day, hour: t0.hour, min: t0.min, sec: t0.sec, usec: t0.usec)

For pre Rails 5, the following will work:

t0 = Time.strptime("2018-05-01", "%Y-%m-%d") # Or whatever
t1 = Time.zone.now.change(year: t0.year, month: t0.month, day: t0.day, hour: t0.hour, min: t0.min, sec: t0.sec, usec: t0.usec)
向地狱狂奔 2024-12-19 00:25:31

尝试一下

(date + Rational(5,24)).new_offset(-Rational(5,24))

你在这里所做的事情:
假设您想更改为时区 5,

date + Rational(5,24)

我将在您的日期时间上添加 5 小时,保持时区不变。

之后,如何调整偏移量以恢复原始数据并获得您想要的时区。

try this

(date + Rational(5,24)).new_offset(-Rational(5,24))

what u are doing here:
suppose that u want to change to timezone 5

date + Rational(5,24)

i'll add 5 hour to your datetime, maintain the time zone.

after, how adjust the offset to recover the original data and get the timezone that u want.

情栀口红 2024-12-19 00:25:31

我无法删除已接受的答案

正如 @LeeJarvis 在下面的评论部分指出的那样,Chronic.parse 不接受 :time_class 选项。所以这个答案是有缺陷的,虽然看起来可行,但实际上并没有(除非 Chronic 很快允许传递 :time_class 选项。)


Chronic gem 确实很强大。

我这样使用它:

Chronic.parse("next 5:00 pm", 
:time_class => ActiveSupport::TimeZone.new(User.first.time_zone)).utc

在上面的示例中,User.first.time_zone 是“太平洋时间(美国和加拿大)”。

Chronic 支持多种格式,因此请查看
https://github.com/mojombo/chronic

确保传递 :time_class 选项并转换为 UTC(在文档中,Chronic 在调用解析之前设置 :time_class 。我避免使用这种方法,因为它可能会导致应用程序中的其他部分无法工作)

TimeZone 的文档位于
http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html

I can't delete an accepted answer

As @LeeJarvis pointed out in the comment section below, Chronic.parse does not accept a :time_class option. So this answer is buggy and while it looks like it works, it doesn't (unless Chronic allows passing a :time_class option soon.)


The Chronic gem is really powerful.

I use it like this:

Chronic.parse("next 5:00 pm", 
:time_class => ActiveSupport::TimeZone.new(User.first.time_zone)).utc

In my example above, User.first.time_zone is "Pacific Time (US & Canada)".

Chronic supports a lot of formats so check it out at
https://github.com/mojombo/chronic

Make sure to pass the :time_class option and to convert to UTC (in the documentation, Chronic sets :time_class before calling parse. I avoid this approach because it might cause other parts across the application not to work)

TimeZone's documentation is at
http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文