diff --git a/README.md b/README.md index 449af95..264ac7f 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,24 @@ Faker::Company.logo #=> "https://pigment.github.com/fake-logos/logos/medium/colo ``` +### Faker::Date + +```crystal + +Faker::Date.birthday.to_s("%Y-%m-%d") #=> "1993-03-09" + +Faker::Date.between("2020-01-01", "2020-08-15").to_s("%Y-%m-%d") #=> "2020-03-29" + +Faker::Date.between_except("2020-01-01", "2020-08-15", "2020-05-10").to_s("%Y-%m-%d") #=> "2020-03-29" + +Faker::Date.forward(days: 30).to_s("%Y-%m-%d") #=> "2022-02-09" + +Faker::Date.backward(days: 30).to_s("%Y-%m-%d") #=> "2021-12-12" + +Faker::Date.in_date_period(year: 2005).to_s("%Y-%m-%d") #=> "2005-02-12" +``` + + ### Faker::Internet ```crystal diff --git a/spec/date_spec.cr b/spec/date_spec.cr new file mode 100644 index 0000000..a9aeb36 --- /dev/null +++ b/spec/date_spec.cr @@ -0,0 +1,106 @@ +require "./spec_helper" + +describe Faker::Date do + describe "#between" do + it "should return between date" do + from = Time.parse("2019-01-01", "%Y-%m-%d", Time::Location::UTC) + to = Time.parse("2022-01-01", "%Y-%m-%d", Time::Location::UTC) + + 100.times do + random_date = Faker::Date.between(from: from, to: to) + random_date.should be >= from + random_date.should be <= to + end + end + + it "should raise and exception on invalid date" do + from = "2019-01-01" + to = "0000-00-00" + + expect_raises(ArgumentError, "Invalid time") do + Faker::Date.between(from: from, to: to) + end + end + end + + describe "#between_except" do + it "should return between date except gvien one" do + from = "2012-01-01" + to = "2012-01-05" + excepted = "2012-01-03" + + 100.times do + random_date = Faker::Date.between_except(from: from, to: to, excepted: excepted) + random_date.should_not be_nil + random_date.should_not eq(Time.parse(excepted, "%Y-%m-%d", Time::Location::UTC)) + end + end + + it "should raise an excpetion when all args are the same" do + from = "2012-01-01" + to = "2012-01-01" + excepted = "2012-01-01" + + expect_raises(ArgumentError, "From date, to date and excepted date must not be the same") do + Faker::Date.between_except(from: from, to: to, excepted: excepted) + end + end + end + + describe "#birthday" do + it "should return a birthday" do + min = 40 + max = 90 + + t = Time.utc + birthday_min = Time.utc(t.year - max, t.month, t.day) + birthday_max = Time.utc(t.year - min, t.month, t.day) + + 100.times do + birthday = Faker::Date.birthday(min_age: min, max_age: max) + + birthday.should be >= birthday_min + birthday.should be <= birthday_max + end + end + + it "should return today when min_age and max_age are the same" do + min = 0 + max = 0 + + t = Time.utc + birthday = Faker::Date.birthday(min_age: min, max_age: max) + + birthday.should eq Time.utc(t.year, t.month, t.day) + end + end + + it "should return a forward date" do + today = Time.utc + + 100.times do + random_date = Faker::Date.forward(days: 5) + random_date.should be > today + end + end + + it "should return a backward date" do + today = Time.utc + + 100.times do + random_date = Faker::Date.backward(days: 5) + random_date.should be < today + end + end + + describe "#date_in_period" do + it "should work with default params" do + current_year = Time.utc.year + + 10.times do + date = Faker::Date.in_date_period + date.year.should eq(current_year) + end + end + end +end diff --git a/src/faker/date.cr b/src/faker/date.cr new file mode 100644 index 0000000..f32c129 --- /dev/null +++ b/src/faker/date.cr @@ -0,0 +1,74 @@ +module Faker + class Date < Base + def self.between(from : Time | String, to : Time | String) : Time + from = parse_date(from) + to = parse_date(to) + + Time.unix(Faker.rand_in_range(from.to_unix, to.to_unix)).at_beginning_of_day + end + + def self.between_except(from : Time | String, to : Time | String, excepted : Time | String) + raise ArgumentError.new("From date, to date and excepted date must not be the same") if from == to && to == excepted + + excepted = parse_date(excepted) + + loop do + date = between(from: from, to: to) + return date if date != excepted + end + end + + def self.birthday(min_age : Int32 = 18, max_age : Int32 = 65) : Time + today = Time.utc + + from = birthday_date(today, max_age) + to = birthday_date(today, min_age) + + between(from, to) + end + + def self.forward(days : Int32 = 365) : Time + from = Time.utc + 1.day + to = Time.utc + days.days + + between(from: from, to: to) + end + + def self.backward(days : Int32 = 365) : Time + from = Time.utc - days.days + to = Time.utc - 1.day + + between(from: from, to: to) + end + + def self.in_date_period(month : Int32? = nil, year : Int32 = Time.utc.year) : Time + from = Time.utc(year, month || 1, 1) + + to_month = month || 12 + end_day = Time.utc(year, to_month, 1).at_end_of_month.day + to = Time.utc(year, to_month, end_day) + + between(from: from, to: to) + end + + private def self.parse_date(date : String) : Time + Time.parse(date, "%Y-%m-%d", Time::Location::UTC) + end + + private def self.parse_date(date : Time) : Time + date + end + + private def self.birthday_date(date : Time, age : Int32) : Time + year = date.year - age + day = + if date.day == 29 && date.month == 2 && Time.leap_year?(year) + 28 + else + date.day + end + + Time.utc(year, date.month, day) + end + end +end