6

これを行うためのエレガントな方法を見つけることができないようです...

与えられた日付から、その月の第 2 または第 4 火曜日である次の火曜日をどのように見つけることができますか?

例えば:

与えられ2012-10-19てから戻る2012-10-23

また

与えられ2012-10-31てから戻る2012-11-13

      October               November        
Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa  
    1  2  3  4  5  6                 1  2  3  
 7  8  9 10 11 12 13     4  5  6  7  8  9 10 
14 15 16 17 18 19 20    11 12 13 14 15 16 17  
21 22 23 24 25 26 27    18 19 20 21 22 23 24 
28 29 30 31             25 26 27 28 29 30     
4

7 に答える 7

4

最終結果がどのように見えるかだけを確認したい場合は、一番下までスクロールしてください。

Ruby 1.9.3 で最近行った日付処理作業のコード スニペットを使用します。

へのいくつかのアップグレードDateTime:

require 'date'

class DateTime

  ALL_DAYS = [ 'sunday', 'monday', 'tuesday',
               'wednesday', 'thursday', 'friday', 'saturday' ]

  def next_week
    self + (7 - self.wday)
  end

  def next_wday (n)
    n > self.wday ? self + (n - self.wday) : self.next_week.next_day(n)
  end

  def nth_wday (n, i)
    current = self.next_wday(n)
    while (i > 0)
      current = current.next_wday(n)
      i = i - 1
    end
    current
  end

  def first_of_month
    self - self.mday + 1
  end

  def last_of_month
    self.first_of_month.next_month - 1
  end

end

method_missingトリック:

next_tuesdayまた、呼び出しをnext_wday(2) andnth_tuesday(2) nth_wday(2, 2)`にマップするためのいくつかのメソッド欠落トリックをクラスに追加しましたto。これにより、次のスニペットが見やすくなります。

class DateTime

  # ...

  def method_missing (sym, *args, &block)
    day = sym.to_s.gsub(/^(next|nth)_(?<day>[a-zA-Z]+)$/i, '\k<day>')
    dindex = ALL_DAYS.include?(day) ? ALL_DAYS.index(day.downcase) : nil
    if (sym =~ /^next_[a-zA-Z]+$/i) && dindex
      self.send(:next_wday, dindex)
    elsif (sym =~ /^nth_[a-zA-Z]+$/i) && dindex
      self.send(:nth_wday, dindex, args[0])
    else
      super(sym, *args, &block)
    end
  end

  def respond_to? (sym)
    day = sym.to_s.gsub(/^(next|nth)_(?<day>[a-zA-Z]+)$/i, '\k<day>')
    (((sym =~ /^next_[a-zA-Z]+$/i) || (sym =~ /^nth_[a-zA-Z]+$/i)) && ALL_DAYS.include?(day)) || super(sym)
  end

end

例:

与えられた日付:

today = DateTime.now
second_tuesday = (today.first_of_month - 1).nth_tuesday(2)
fourth_tuesday = (today.first_of_month - 1).nth_tuesday(4)

if today == second_tuesday
  puts "Today is the second tuesday of this month!"
elsif today == fourth_tuesday
  puts "Today is the fourth tuesday of this month!"
else
  puts "Today is not interesting."
end

、などmethod_missingの呼び出しを処理するように編集することもできます。後日書くことにした場合は、ここにコードを投稿します。:second_tuesday_of_this_month:fourth_tuesday_of_this_month

于 2012-10-19T23:53:19.417 に答える
2

ChronicまたはTickleを見てください。どちらも複雑な時間と日付を解析するための宝石です。特に Tickle は繰り返し時間を解析します (Chronic も使用していると思います)。

于 2012-10-19T19:56:39.853 に答える
1

この宝石をチェックしてください。答えがわかるかもしれません

https://github.com/mojombo/chronic/

于 2012-10-19T19:56:10.467 に答える
1

すでに Rails を使用しているため、インクルードは必要ありませんが、参考までに、これは純粋な Ruby でも機能します。

require 'rubygems'
require 'active_support/core_ext'

d = DateTime.parse('2012-10-19')
result = nil
valid_weeks = [d.beginning_of_month.cweek + 1, d.beginning_of_month.cweek + 3]
if valid_weeks.include?(d.next_week(:tuesday).cweek)
  result = d.next_week(:tuesday)
else
  result = d.next_week.next_week(:tuesday)
end

puts result
于 2012-10-19T21:06:28.290 に答える
0

そのため、月の特定の週の平日を解決するコードを次に示します (砂糖をほとんど使わずに求めたもの)。Rails フレームワーク内で実行している場合、問題は発生しないはずです。それ以外の場合は、active_support gem がインストールされていることを確認してください。メソッド名はばかげているので、自由に変更してください:)

利用方法:get_next_day_of_week(some_date, :friday, 1)

require 'rubygems'
require 'active_support/core_ext'

def get_next_day_of_week(date, day_name, count)
  next_date = date + (-date.days_to_week_start(day_name.to_sym) % 7)
  while (next_date.mday / 7) != count - 1 do
    next_date = next_date + 7
  end
  next_date
end 
于 2012-10-19T22:45:37.553 に答える
0

より興味深いロジックに分岐する必要がある場合は、おそらくライブラリを使用する必要があると思いますが、説明したものが必要なだけの場合は、以下のコードが役立つはずです

SECONDS_PER_DAY = 60 * 60 * 24
def find_tuesday_datenight(now)
  tuesdays = [*-31..62].map { |i| now + (SECONDS_PER_DAY * i) }
    .select { |d| d.tuesday? }
    .group_by { |d| d.month }
  [tuesdays[now.month][1], tuesdays[now.month][-2], tuesdays[(now.month + 1) % 12][1]]
    .find {|d| d.yday > now.yday }
end

先月と翌月をループし、火曜日を取得し、月ごとにグループ化し、現在の月の 2 番目と 2 番目の最後の火曜日 (実際に 4 番目の火曜日が必要な場合は、-2 を 3 に変更します) と 2 番目の火曜日を取得します。翌月の日付を選択し、指定された日付の後の最初の日付を選択します。

ここにいくつかのテスト、月に4回の火曜日、月に5回の火曜日、ランダム、およびあなたの例があります:

[[2013, 5, 1], [2013, 12, 1], [2012, 10, 1], [2012, 10, 19], [2012, 10, 31]].each do |t|
  puts "#{t} => #{find_tuesday_datenight(Time.new *t)}"
end

生産する

[2013, 5, 1] => 2013-05-14 00:00:00 +0800
[2013, 12, 1] => 2013-12-10 00:00:00 +0800
[2012, 10, 1] => 2012-10-09 00:00:00 +0800
[2012, 10, 19] => 2012-10-23 00:00:00 +0800
[2012, 10, 31] => 2012-11-13 00:00:00 +0800

私はそれが単純化される可能性があると確信しており、いくつかの提案を聞きたいです:)

于 2012-10-19T21:15:53.253 に答える