日期为

时间:2017-10-06 08:59:01

标签: ruby

我在生日小工具上工作,显示最接近他生日的人的姓名。

我目前有以下代码;

<% 
def closest_birthdate(birthdates) 
 sorted_dates = birthdates.sort_by do |_, value| 
  (DateTime.parse(value) - DateTime.now).abs
 end 
 name, birthday = sorted_dates.first 
 "#{name} has his birthday on #{Date.parse(birthday).strftime('%m-%d')}"
end 
%>

<% hash = { 'Bart' =>     '2017-12-06', 
            'Thomas' =>   '2017-10-06',
            'William' =>  '2018-09-05',} %> 
<%= closest_birthdate(hash) %>

返回以下内容:

Thomas has his birthday on 10-06

现在,在他生日那天之后,我必须将年份从2017年改为2018年。 名称日期目前存储为字符串。

  1. 如何将字符串更改为日期?
  2. 我如何使用他们的实际出生日期,所以我们每次生日时都不必将2017年改为2018年?

3 个答案:

答案 0 :(得分:0)

没有标准对象作为(出生)日没有指定年份。所以你应该只保存月份和月份的数组。将它们保存为整数而不是字符串要好得多。

hash = {
  'Bart' => [12, 6],
  'Thomas' => [10, 6],
  'William' => [9, 5],
}

要将它们转换为具有年份规格的日期(假设为year = 2018),请执行以下操作:

require "date"
date = Date.new(year, *hash['Bart']) rescue nil

完全实现它将是这样的:

require "date"

def closest_birthdate(birthdates)
  year, month, day = Date.today.year, Date.today.month, Date.today.day
  name, (m, d) =
    birthdates
    .sort_by(&:last)
    .bsearch{|_, (m, d)| month <= m and day < d}
  return unless Date.new(year, m, d) rescue nil
  "#{name} has his birthday on #{year}-#{m}-#{d}"
end

closest_birthdate(hash)

答案 1 :(得分:0)

如果您不想更改结构,请尝试此操作:

<% 
def closest_birthdate(birthdates) 
 sorted_dates = birthdates.sort_by do |_, value| 
  array = value.split("-") # you got something like this [2017, 12, 06]
  (DateTime.parse("#{DateTime.now.year}-#{array[1]}-#{array[2]}") - DateTime.now).abs
 end 
 name, birthday = sorted_dates.first 
 "#{name} has his birthday on #{Date.parse(birthday).strftime('%m-%d')}"
end 
%>

<% hash = { 'Bart' =>     '1978-12-06', 
            'Thomas' =>   '1972-10-06',
            'William' =>  '1992-09-05',} %> 
<%= closest_birthdate(hash) %>

希望这有帮助。

答案 2 :(得分:0)

存储日期

可以通过Date创建Date::new个实例:

require 'date'

birthdate = Date.new(1978, 12, 6)
#=> #<Date: 1978-12-06 ...>

计算下一个生日

上述生日的下一个或即将到来的生日是2017-12-06,所以我们必须将今天和出生日期的月份和日期结合起来:

today = Date.today
#=> #<Date: 2017-10-06 ...>

next_birthday = Date.new(today.year, birthdate.month, birthdate.day)
#=> #<Date: 2017-12-06 ...>

如果生日已经在今年发生,会发生什么?

birthdate = Date.new(1985, 9, 5)
#=> #<Date: 1985-12-06 ...>

next_birthday = Date.new(today.year, birthdate.month, birthdate.day)
#=> #<Date: 2017-09-05 ...>

要实际获得下一个生日,我们必须在这种情况下添加一年:(即如果next_birthday恰好在今天之前)

next_birthday = next_birthday.next_year if next_birthday < today
#=> #<Date: 2018-09-05 ...>

找到最接近的生日

让我们将上述计算转移到一个方法中:

def next_birthday(birthdate, today = Date.today)
  date = Date.new(today.year, birthdate.month, birthdate.day)
  date < today ? date.next_year : date
end

要查找最近(即将到来)的生日,我们可以使用sort_byfirst

hash = {
  'Bart'    => Date.new(1978, 12, 6), 
  'Thomas'  => Date.new(1981, 10, 6),
  'William' => Date.new(1985, 9, 5)
}

hash.sort_by { |_name, birthdate| next_birthday(birthdate) }
#=> [
#  ["Thomas", #<Date: 1981-10-06 ...>],
#  ["Bart", #<Date: 1978-12-06 ...>],
#  ["William", #<Date: 1985-09-05 ...>]
# ]

hash.sort_by { |_name, birthdate| next_birthday(birthdate) }.first
#=> ["Thomas", #<Date: 1981-10-06 ...>]

min_by

hash.min_by { |_name, birthdate| next_birthday(birthdate) }
#=> ["Thomas", #<Date: 1981-10-06 ...>]

生成输出

name, birthdate = hash.min_by { |_name, birthdate| next_birthday(birthdate) }

puts "#{name}'s birthday is on #{birthdate.strftime('%m-%d')}"
# Thomas's birthday is on 10-06

我们还可以添加年龄:

age = next_birthday(birthdate).year - birthdate.year
#=> 36

puts "#{name} is turning #{age} on #{birthdate.strftime('%m-%d')}"
# Thomas is turning 36 on 10-06

边缘情况

2月29日仅发生在闰年:

Date.new(1984, 2, 29)
#=> #<Date: 1984-02-29 ...>

尝试在非闰年创建2月29日会导致错误:

Date.new(2017, 2, 29)
#=> ArgumentError: invalid date

除非今天的年份为leap?(截至2月28日或3月1日),否则您可以删除这些日期或进行调整。