루비 / 레일즈 - 값을 변경하지 않고 시간의 표준시를 변경합니다.
나는 기록이 있습니다.foo
할 수 있습니다.:start_time
그리고.:timezone
특성.
그:start_time
UTC - 는 UTC - 시니다입간으로 입니다.2001-01-01 14:20:00
를 들면 를들면예면. 그:timezone
- 문입니다입니다.America/New_York
를 들면 를들면예면.
▁with다▁the▁time▁a의 값으로 새로운 Time 객체를 만들고 싶습니다.:start_time
가 하만시지사정된으로 된 사람.:timezone
로드하고 싶지 않습니다.:start_time
에 다으로변니다환합음다▁to니▁and변환합으로 변환합니다.:timezone
왜냐하면 레일즈는 영리하고 UTC의 시간을 해당 시간대와 일치하도록 업데이트하기 때문입니다.
현재의,
t = foo.start_time
=> 2000-01-01 14:20:00 UTC
t.zone
=> "UTC"
t.in_time_zone("America/New_York")
=> Sat, 01 Jan 2000 09:20:00 EST -05:00
대신에, 나는 보고 싶습니다.
=> Sat, 01 Jan 2000 14:20:00 EST -05:00
i. 다음 작업을 수행합니다.
t
=> 2000-01-01 14:20:00 UTC
t.zone = "America/New_York"
=> "America/New_York"
t
=> 2000-01-01 14:20:00 EST
당신이 원하는 것처럼 들리는군요.
ActiveSupport::TimeZone.new('America/New_York').local_to_utc(t)
이 로컬 시간(영역 사용)을 utc로 변환합니다.가지고 계신다면,Time.zone
설정할 수 .
Time.zone.local_to_utc(t)
이렇게 하면 t에 연결된 표준 시간대가 사용되지 않습니다. t는 변환하려는 표준 시간대에 로컬이라고 가정합니다.
여기서 보호해야 할 한 가지 에지 케이스는 DST 전환입니다. 즉, 지정한 로컬 시간이 존재하지 않거나 모호할 수 있습니다.
저는 방금 같은 문제에 직면했습니다. 다음은 제가 할 일입니다.
t = t.asctime.in_time_zone("America/New_York")
Rails를 사용하는 경우 Eric Walsh의 답변에 따라 다음과 같은 다른 방법이 있습니다.
def set_in_timezone(time, zone)
Time.use_zone(zone) { time.to_datetime.change(offset: Time.zone.now.strftime("%z")) }
end
시간 오프셋을 변환한 후 시간에 시간 오프셋을 추가해야 합니다.
가장 쉬운 방법은 다음과 같습니다.
t = Foo.start_time.in_time_zone("America/New_York")
t -= t.utc_offset
당신이 왜 이것을 하고 싶어하는지는 모르겠지만, 실제로 그것들이 만들어지는 방식으로 일하는 것이 가장 좋을 것입니다.왜 시간대와 시간대를 바꿔야 하는지에 대한 배경이 도움이 될 것 같습니다.
실제로 다음과 같이 변환한 후 오프셋을 빼야 할 것 같습니다.
1.9.3p194 :042 > utc_time = Time.now.utc
=> 2013-05-29 16:37:36 UTC
1.9.3p194 :043 > local_time = utc_time.in_time_zone('America/New_York')
=> Wed, 29 May 2013 12:37:36 EDT -04:00
1.9.3p194 :044 > desired_time = local_time-local_time.utc_offset
=> Wed, 29 May 2013 16:37:36 EDT -04:00
이 시간을 사용할 위치에 따라 다릅니다.
당신의 시간이 속성일 때
시간을 속성으로 사용하는 경우 동일한 date_time_attribute gem을 사용할 수 있습니다.
class Task
include DateTimeAttribute
date_time_attribute :due_at
end
task = Task.new
task.due_at_time_zone = 'Moscow'
task.due_at # => Mon, 03 Feb 2013 22:00:00 MSK +04:00
task.due_at_time_zone = 'London'
task.due_at # => Mon, 03 Feb 2013 22:00:00 GMT +00:00
별도의 변수를 설정하는 경우
동일한 date_time_attribute gem 사용:
my_date_time = DateTimeAttribute::Container.new(Time.zone.now)
my_date_time.date_time # => 2001-02-03 22:00:00 KRAT +0700
my_date_time.time_zone = 'Moscow'
my_date_time.date_time # => 2001-02-03 22:00:00 MSK +0400
다음은 현재 답변보다 더 효과적인 버전입니다.
now = Time.now
# => 2020-04-15 12:07:10 +0200
now.strftime("%F %T.%N").in_time_zone("Europe/London")
# => Wed, 15 Apr 2020 12:07:10 BST +01:00
%N을 사용하여 나노초 단위로 전송됩니다.다른 정밀도를 원하는 경우 이 strftime 참조를 참조하십시오.
이 질문은 Rails에 대한 것이지만, 저와 마찬가지로 여기에 있는 모든 사람이 ActiveSupport 열차에 타고 있는 것은 아닌 것 같습니다. 따라서 또 다른 옵션이 있습니다.
irb(main):001:0> require "time"
=> true
irb(main):003:0> require "tzinfo"
=> true
irb(main):004:0> t = Time.parse("2000-01-01 14:20:00 UTC")
=> 2000-01-01 14:20:00 UTC
irb(main):005:0> tz = TZInfo::Timezone.get("America/New_York")
=> #<TZInfo::DataTimezone: America/New_York>
irb(main):008:0> utc = tz.local_to_utc(t)
=> 2000-01-01 19:20:00 UTC
irb(main):009:0> tz.utc_to_local(utc)
=> 2000-01-01 14:20:00 -0500
irb(main):010:0>
local_to_utc
와반로하않의 를 하지 것utc_to_local
버그처럼 보일 수 있지만 적어도 문서화되어 있습니다. https://github.com/tzinfo/tzinfo 은 다음과 같이 말합니다.
시간 오프셋이 무시됩니다. 시간대의 로컬 시간인 것처럼 처리됩니다.
제가 전화를 해서 이 일을 할 수 있었습니다.change
원하는 시간대를 사용합니다.
>> t = Time.current.in_time_zone('America/New_York')
=> Mon, 08 Aug 2022 12:04:36.934007000 EDT -04:00
>> t.change(zone: 'Etc/UTC')
=> Mon, 08 Aug 2022 12:04:36.934007000 UTC +00:00
https://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html#method-i-change
def relative_time_in_time_zone(time, zone)
DateTime.parse(time.strftime("%d %b %Y %H:%M:%S #{time.in_time_zone(zone).formatted_offset}"))
end
일을 해결하기 위해 생각해 낸 빠른 작은 기능.더 효율적인 방법이 있는 사람은 게시하십시오!
저는 TimeZones와도 많은 시간을 보냈고 Ruby 1.9.3을 수정한 후 변환하기 전에 명명된 시간대 기호로 변환할 필요가 없다는 것을 깨달았습니다.
my_time = Time.now
west_coast_time = my_time.in_time_zone(-8) # Pacific Standard Time
east_coast_time = my_time.in_time_zone(-5) # Eastern Standard Time
즉, 원하는 지역에서 먼저 적절한 시간을 설정하는 데 집중할 수 있으며, 이에 대해 생각하는 방식(적어도 내 머릿속에서는 이러한 방식으로 분할)을 적용한 후 마지막에 비즈니스 논리를 검증할 영역으로 변환할 수 있습니다.
이것은 Ruby 2.3.1에서도 작동합니다.
저는 몇 가지 도우미 방법을 만들었는데, 그 중 하나는 루비/레일즈 - 시간의 시간대를 변경하지 않고 원래 게시물 작성자가 요청한 것과 동일한 작업을 수행합니다.
또한 저는 제가 관찰한 몇 가지 특성을 문서화했으며, 이러한 도우미에는 레일즈 프레임워크에서 즉시 사용할 수 없는 시간 변환을 사용하는 동안 적용 가능한 자동 일광 절약을 완전히 무시하는 방법이 포함되어 있습니다.
def utc_offset_of_given_time(time, ignore_dst: false)
# Correcting the utc_offset below
utc_offset = time.utc_offset
if !!ignore_dst && time.dst?
utc_offset_ignoring_dst = utc_offset - 3600 # 3600 seconds = 1 hour
utc_offset = utc_offset_ignoring_dst
end
utc_offset
end
def utc_offset_of_given_time_ignoring_dst(time)
utc_offset_of_given_time(time, ignore_dst: true)
end
def change_offset_in_given_time_to_given_utc_offset(time, utc_offset)
formatted_utc_offset = ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, false)
# change method accepts :offset option only on DateTime instances.
# and also offset option works only when given formatted utc_offset
# like -0500. If giving it number of seconds like -18000 it is not
# taken into account. This is not mentioned clearly in the documentation
# , though.
# Hence the conversion to DateTime instance first using to_datetime.
datetime_with_changed_offset = time.to_datetime.change(offset: formatted_utc_offset)
Time.parse(datetime_with_changed_offset.to_s)
end
def ignore_dst_in_given_time(time)
return time unless time.dst?
utc_offset = time.utc_offset
if utc_offset < 0
dst_ignored_time = time - 1.hour
elsif utc_offset > 0
dst_ignored_time = time + 1.hour
end
utc_offset_ignoring_dst = utc_offset_of_given_time_ignoring_dst(time)
dst_ignored_time_with_corrected_offset =
change_offset_in_given_time_to_given_utc_offset(dst_ignored_time, utc_offset_ignoring_dst)
# A special case for time in timezones observing DST and which are
# ahead of UTC. For e.g. Tehran city whose timezone is Iran Standard Time
# and which observes DST and which is UTC +03:30. But when DST is active
# it becomes UTC +04:30. Thus when a IRDT (Iran Daylight Saving Time)
# is given to this method say '05-04-2016 4:00pm' then this will convert
# it to '05-04-2016 5:00pm' and update its offset to +0330 which is incorrect.
# The updated UTC offset is correct but the hour should retain as 4.
if utc_offset > 0
dst_ignored_time_with_corrected_offset -= 1.hour
end
dst_ignored_time_with_corrected_offset
end
클래스 또는 모듈에서 위의 방법을 래핑한 후 레일 콘솔 또는 루비 스크립트에서 시도할 수 있는 예:
dd1 = '05-04-2016 4:00pm'
dd2 = '07-11-2016 4:00pm'
utc_zone = ActiveSupport::TimeZone['UTC']
est_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
tehran_zone = ActiveSupport::TimeZone['Tehran']
utc_dd1 = utc_zone.parse(dd1)
est_dd1 = est_zone.parse(dd1)
tehran_dd1 = tehran_zone.parse(dd1)
utc_dd1.dst?
est_dd1.dst?
tehran_dd1.dst?
ignore_dst = true
utc_to_est_time = utc_dd1.in_time_zone(est_zone.name)
if utc_to_est_time.dst? && !!ignore_dst
utc_to_est_time = ignore_dst_in_given_time(utc_to_est_time)
end
puts utc_to_est_time
이게 도움이 되길 바랍니다.
이것은 나에게 잘 먹혔습니다.
date = '23/11/2020'
time = '08:00'
h, m = time.split(':')
timezone = 'Europe/London'
date.to_datetime.in_time_zone(timezone).change(hour: h, min: m)
그러면 시간이 변경되지 않고 시간대가 'EST'로 변경됩니다.
time = DateTime.current
Time.find_zone("EST").local(
time.year,
time.month,
time.day,
time.hour,
time.min,
time.sec,
)
언급URL : https://stackoverflow.com/questions/16818180/ruby-rails-change-the-timezone-of-a-time-without-changing-the-value
'programing' 카테고리의 다른 글
해결 방법: "'@typescript-eslint/consistent-type-assertions' 규칙에 대한 정의를 찾을 수 없습니다." (0) | 2023.06.09 |
---|---|
Bash 별칭을 만들려면 어떻게 해야 합니까? (0) | 2023.06.04 |
루비에서 배열을 무작위로 정렬(스크램블)하는 방법은 무엇입니까? (0) | 2023.06.04 |
데이터 내보내기에서 MYSQL WORKBENCH 대 MARADB 문제 (0) | 2023.06.04 |
UITableView 테이블에서 AutoLayout을 사용할 수 있습니까?머리글 보기? (0) | 2023.06.04 |