Skip to content

Instantly share code, notes, and snippets.

@wacko
Last active January 3, 2020 23:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wacko/a7f5b2fd2cbc9e973d7b23c6d50c2ec1 to your computer and use it in GitHub Desktop.
Save wacko/a7f5b2fd2cbc9e973d7b23c6d50c2ec1 to your computer and use it in GitHub Desktop.
Class to represent a short date (MM/DD), without the year component
require 'date'
class ShortDate
attr_reader :month, :day
include Comparable
def initialize(string)
date = Date.strptime(string, '%m/%d')
@month, @day = date.month, date.day
rescue StandardError
end
def ==(other_day)
month == other_day.month && day == other_day.day
end
def <=>(other_day)
if month == other_day.month
day <=> other_day.day
else
month <=> other_day.month
end
end
def to_s
'%02u/%02u' % [month, day] if month && day
end
def valid?
@month && @day
end
end
require 'spec_helper'
require './lib/short_date'
RSpec.describe ShortDate do
it 'has day and month attributes' do
date = ShortDate.new("1/2")
expect(date.month).to eq 1
expect(date.day).to eq 2
end
it 'can be converted to a string' do
expect(ShortDate.new("10/11").to_s).to eq '10/11'
# invalid dates
expect(ShortDate.new("20/20").to_s).to be_nil
end
it 'is comparabable' do
# when date1.month < date2.month
expect(ShortDate.new("1/2")).to be <= ShortDate.new("2/1")
expect(ShortDate.new("1/2")).to be <= ShortDate.new("2/2")
expect(ShortDate.new("1/2")).to be <= ShortDate.new("2/3")
# when date1.month == date2.month
expect(ShortDate.new("2/2")).to be >= ShortDate.new("2/1")
expect(ShortDate.new("2/2")).to be == ShortDate.new("2/2")
expect(ShortDate.new("2/2")).to be <= ShortDate.new("2/3")
# when date1.month > date2.month
expect(ShortDate.new("3/2")).to be >= ShortDate.new("2/1")
expect(ShortDate.new("3/2")).to be >= ShortDate.new("2/2")
expect(ShortDate.new("3/2")).to be >= ShortDate.new("2/3")
# with leading zeroes
expect(ShortDate.new('04/06')).to be == ShortDate.new("4/6")
# '4/6/2000' still matches '%m/%d' ...
expect(ShortDate.new('4/6/2000')).to be == ShortDate.new("4/6")
end
it 'is validable' do
expect(ShortDate.new("1/1")).to be_valid
# invalid dates
expect(ShortDate.new("20/1")).to_not be_valid
expect(ShortDate.new("1/32")).to_not be_valid
expect(ShortDate.new("2/30")).to_not be_valid
# any other format will fail
expect(ShortDate.new('2000/4/6')).to_not be_valid
expect(ShortDate.new('Apr 6')).to_not be_valid
end
end
@wacko
Copy link
Author

wacko commented Jan 3, 2020

Example with Rails:

class RecurringEvent < ActiveRecord::Base
  composed_of :date, class_name: "ShortDate"
end

@wacko
Copy link
Author

wacko commented Jan 3, 2020

A simpler implementation, but without day/month attributes

require 'date'

class ShortDate
  attr_reader :date
  include Comparable

  def initialize(string)
    temp = Date.strptime(string, '%m/%d')
    @date = '%02u/%02u' % [temp.month, temp.day]
  rescue StandardError
  end

  def ==(other_day)
    date == other_day.date
  end

  def <=>(other_day)
    date <=> other_day.date
  end

  def to_s
    date
  end

  def valid?
    !date.nil?
  end

end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment