Não tenho certeza se essa deve ser uma pergunta separada, mas como você converte entre Data e Hora?
Andrew Grimm
8
As respostas aceitas e com a classificação mais alta não são mais as mais precisas nas versões modernas do Ruby. Veja as respostas de @theTinMan e de @PatrickMcKenzie abaixo.
Phrogz
Respostas:
50
Você precisará de duas conversões ligeiramente diferentes.
Para converter de Time para DateTimevocê, você pode alterar a classe Time da seguinte maneira:
require 'date'classTimedef to_datetime
# Convert seconds + microseconds into a fractional number of seconds
seconds = sec +Rational(usec,10**6)# Convert a UTC offset measured in minutes to one measured in a# fraction of a day.
offset =Rational(utc_offset,60*60*24)DateTime.new(year, month, day, hour, min, seconds, offset)endend
Ajustes semelhantes a Data permitirão a conversão DateTime para Time .
classDatedef to_gm_time
to_time(new_offset,:gm)enddef to_local_time
to_time(new_offset(DateTime.now.offset-offset),:local)end
private
def to_time(dest, method)#Convert a fraction of a day to a number of microseconds
usec =(dest.sec_fraction *60*60*24*(10**6)).to_i
Time.send(method, dest.year, dest.month, dest.day, dest.hour, dest.min,
dest.sec, usec)endend
Observe que você precisa escolher entre a hora local e a hora GM / UTC.
Ambos os trechos de código acima foram retirados do Ruby Cookbook da O'Reilly . Sua política de reutilização de código permite isso.
Isso será interrompido em 1.9, em que DateTime # sec_fraction retorna o número de milissegundos em um segundo. Para 1.9 que você deseja usar: usec = dest.sec_fraction * 10 ** 6
dkubb
185
require 'time'
require 'date'
t =Time.now
d =DateTime.now
dd =DateTime.parse(t.to_s)
tt =Time.parse(d.to_s)
+1 Isso pode não ser o mais eficiente na execução, mas funciona, é conciso e muito legível.
218 Walt Jones
6
Infelizmente, isso só funciona realmente quando se trata de horários locais. Se você começar com um DateTime ou Time com um fuso horário diferente, a função de análise será convertida em fuso horário local. Você basicamente perde o fuso horário original.
18710 Bernard
6
A partir do ruby 1.9.1, o DateTime.parse preserva o fuso horário. (Não tenho acesso a versões anteriores.) Time.parse não preserva o fuso horário, porque representa o time_t padrão POSIX, que acredito ser uma diferença inteira da época. Qualquer conversão para Time deve ter o mesmo comportamento.
anshul
1
Você está certo. DateTime.parse funciona em 1.9.1, mas não Time.parse. De qualquer forma, é menos propenso a erros (consistente) e provavelmente mais rápido usar DateTime.new (...) e Time.new (..). Veja minha resposta para o código de exemplo.
Bernard
1
Oi @anshul. Não estou sugerindo que estou afirmando :-). As informações de fuso horário não são mantidas ao usar Time.parse (). É fácil de testar. No código acima, substitua d = DateTime.now por d = DateTime.new (2010,01,01, 10,00,00, Rational (-2, 24)). Agora, o tt mostrará a data de conversão no fuso horário local. Você ainda pode fazer aritmética de datas e todas as informações, exceto a tz original, são perdidas. Esta informação é um contexto para a data e geralmente é importante. Veja aqui: stackoverflow.com/questions/279769/…
Bernard
63
Como uma atualização para o estado do ecossistema Ruby, Date, DateTimee Timeagora têm métodos para converter entre as várias classes. Usando Ruby 1.9.2+:
Opa Acabei de perceber que este é um problema do Ruby on Rails e não um problema do Ruby: stackoverflow.com/questions/11277454/… . Eles até tiveram um bug registrado contra esse método na linha 2.x e o marcaram como "não será corrigido". Decisão horrível IMHO. O comportamento do Rails quebra totalmente a interface Ruby subjacente.
Jesse Clark #
12
Infelizmente, o DateTime.to_time, Time.to_datetimeTime.parse funções e não retêm as informações do fuso horário. Tudo é convertido em fuso horário local durante a conversão. A aritmética de datas ainda funciona, mas você não poderá exibir as datas com seus fusos horários originais. Essa informação de contexto geralmente é importante. Por exemplo, se eu quiser ver as transações realizadas durante o horário comercial em Nova York, provavelmente prefiro vê-las exibidas em seus fusos horários originais, e não no fuso horário local na Austrália (12 horas antes de Nova York).
Os métodos de conversão abaixo mantêm essas informações tz.
require 'date'# Create a date in some foreign time zone (middle of the Atlantic)
d =DateTime.new(2010,01,01,10,00,00,Rational(-2,24))
puts d
# Convert DateTime to Time, keeping the original timezone
t =Time.new(d.year, d.month, d.day, d.hour, d.min, d.sec, d.zone)
puts t
# Convert Time to DateTime, keeping the original timezone
d =DateTime.new(t.year, t.month, t.day, t.hour, t.min, t.sec,Rational(t.gmt_offset /3600,24))
puts d
O tempo é complicado, mas não há desculpa para não fornecer conversão integrada entre diferentes classes de tempo internas. Você pode lançar um RangeException se tentar obter um time_t do UNIX para 4713 aC (embora um valor negativo do BigNum seja melhor), mas pelo menos forneça um método para ele.
Mark Reed
1
Time#to_datetimeparece preservar tz para mim:Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
Phrogz 7/12/12
O deslocamento UTC @Phrogz não é a mesma coisa que um fuso horário. Um é constante, o outro pode mudar em diferentes épocas do ano para o horário de verão. DateTime não tem uma zona, ele ignora o horário de verão. O tempo o respeita, mas apenas no TZ "local" (ambiente do sistema).
Andrew Vit
1
Melhorando a solução de Gordon Wilson, aqui está minha tentativa:
def to_time
#Convert a fraction of a day to a number of microseconds
usec =(sec_fraction *60*60*24*(10**6)).to_i
t =Time.gm(year, month, day, hour, min, sec, usec)
t - offset.abs.div(SECONDS_IN_DAY)end
Você receberá o mesmo horário no UTC, perdendo o fuso horário (infelizmente)
Além disso, se você tiver o ruby 1.9, tente o to_timemétodo
Ao fazer essas conversões, deve-se levar em consideração o comportamento dos fusos horários ao converter de um objeto para outro. Encontrei boas notas e exemplos neste post do stackoverflow .
Respostas:
Você precisará de duas conversões ligeiramente diferentes.
Para converter de
Time
paraDateTime
você, você pode alterar a classe Time da seguinte maneira:Ajustes semelhantes a Data permitirão a conversão
DateTime
paraTime
.Observe que você precisa escolher entre a hora local e a hora GM / UTC.
Ambos os trechos de código acima foram retirados do Ruby Cookbook da O'Reilly . Sua política de reutilização de código permite isso.
fonte
fonte
Como uma atualização para o estado do ecossistema Ruby,
Date
,DateTime
eTime
agora têm métodos para converter entre as várias classes. Usando Ruby 1.9.2+:fonte
1.9.3p327 :007 > ts = '2000-01-01 12:01:01 -0700' => "2000-01-01 12:01:01 -0700" 1.9.3p327 :009 > dt = ts.to_datetime => Sat, 01 Jan 2000 12:01:01 -0700 1.9.3p327 :010 > dt.to_time => Sat, 01 Jan 2000 12:01:01 -0700 1.9.3p327 :011 > dt.to_time.class => DateTime
Infelizmente, o
DateTime.to_time, Time.to_datetime
Time.parse
funções e não retêm as informações do fuso horário. Tudo é convertido em fuso horário local durante a conversão. A aritmética de datas ainda funciona, mas você não poderá exibir as datas com seus fusos horários originais. Essa informação de contexto geralmente é importante. Por exemplo, se eu quiser ver as transações realizadas durante o horário comercial em Nova York, provavelmente prefiro vê-las exibidas em seus fusos horários originais, e não no fuso horário local na Austrália (12 horas antes de Nova York).Os métodos de conversão abaixo mantêm essas informações tz.
Para Ruby 1.8, veja a resposta de Gordon Wilson . É do bom e velho e confiável Ruby Cookbook.
Para o Ruby 1.9, é um pouco mais fácil.
Isso imprime o seguinte
As informações originais originais do DateTime, incluindo o fuso horário, são mantidas.
fonte
Time#to_datetime
parece preservar tz para mim:Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
Melhorando a solução de Gordon Wilson, aqui está minha tentativa:
Você receberá o mesmo horário no UTC, perdendo o fuso horário (infelizmente)
Além disso, se você tiver o ruby 1.9, tente o
to_time
métodofonte
Ao fazer essas conversões, deve-se levar em consideração o comportamento dos fusos horários ao converter de um objeto para outro. Encontrei boas notas e exemplos neste post do stackoverflow .
fonte