├── .rspec ├── .DS_Store ├── CHANGELOG.md ├── lib ├── date_by_example │ ├── version.rb │ ├── date.rb │ ├── time.rb │ ├── date_time.rb │ └── example_formatter.rb └── date_by_example.rb ├── date_by_example-0.1.0.gem ├── .travis.yml ├── Rakefile ├── bin ├── setup └── console ├── spec ├── date_by_example_spec.rb ├── spec_helper.rb └── example_formatter_spec.rb ├── .gitignore ├── Gemfile ├── LICENSE.txt ├── date_by_example.gemspec ├── Gemfile.lock ├── README.md ├── CODE_OF_CONDUCT.md └── .rubocop.yml /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noelrappin/date_by_example/HEAD/.DS_Store -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Version 0.1.1 6/22/2018 2 | 3 | * Adds "%l" for single digit hours 4 | -------------------------------------------------------------------------------- /lib/date_by_example/version.rb: -------------------------------------------------------------------------------- 1 | module DateByExample 2 | VERSION = "0.1.1".freeze 3 | end 4 | -------------------------------------------------------------------------------- /date_by_example-0.1.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noelrappin/date_by_example/HEAD/date_by_example-0.1.0.gem -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | rvm: 4 | - 2.5.1 5 | before_install: gem install bundler -v 1.16.1 6 | -------------------------------------------------------------------------------- /lib/date_by_example/date.rb: -------------------------------------------------------------------------------- 1 | class Date 2 | def by_example(example) 3 | ExampleFormatter.new(example).format(self) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/date_by_example/time.rb: -------------------------------------------------------------------------------- 1 | class Time 2 | def by_example(example) 3 | ExampleFormatter.new(example).format(self) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task default: :spec 7 | -------------------------------------------------------------------------------- /lib/date_by_example/date_time.rb: -------------------------------------------------------------------------------- 1 | class DateTime 2 | def by_example(example) 3 | ExampleFormatter.new(example).format(self) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /spec/date_by_example_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe DateByExample do 2 | it "has a version number" do 3 | expect(DateByExample::VERSION).not_to be nil 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | 10 | # rspec failure tracking 11 | .rspec_status 12 | .DS_Store 13 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } 4 | 5 | # Specify your gem's dependencies in date_by_example.gemspec 6 | gemspec 7 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "date_by_example" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | require "date_by_example" 3 | 4 | RSpec.configure do |config| 5 | # Enable flags like --only-failures and --next-failure 6 | config.example_status_persistence_file_path = ".rspec_status" 7 | 8 | # Disable RSpec exposing methods globally on `Module` and `main` 9 | config.disable_monkey_patching! 10 | 11 | config.expect_with :rspec do |c| 12 | c.syntax = :expect 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/date_by_example.rb: -------------------------------------------------------------------------------- 1 | require "date" 2 | require "date_by_example/date" 3 | require "date_by_example/date_time" 4 | require "date_by_example/time" 5 | require "date_by_example/version" 6 | require "date_by_example/example_formatter" 7 | require "benchmark" 8 | 9 | module DateByExample 10 | def self.benchmark 11 | dt = DateTime.new(2018, 6, 9, 13, 15) 12 | Benchmark.bm do |x| 13 | x.report do 14 | 1_000_000.times do 15 | ExampleFormatter.new("2 Jan 06 15:04").format(dt) 16 | end 17 | end 18 | end 19 | 20 | # GSUB version is 16.15 seconds 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Noel Rappin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/date_by_example/example_formatter.rb: -------------------------------------------------------------------------------- 1 | class ExampleFormatter 2 | attr_accessor :reference 3 | 4 | def initialize(reference) 5 | @reference = reference 6 | @format_string = nil 7 | end 8 | 9 | FORMATS = { 10 | ".000000000" => ".9N", 11 | "-07:00:00" => "%::z", 12 | ".000000" => ".%6N", 13 | "January" => "%B", 14 | "JANUARY" => "%^B", 15 | "Monday" => "%A", 16 | "MONDAY" => "%^A", 17 | "-07:00" => "%:z", 18 | "-7000" => "%z", 19 | "2006" => "%Y", 20 | ".000" => ".%L", 21 | "002" => "%j", 22 | "Jan" => "%b", 23 | "JAN" => "%^b", 24 | "Mon" => "%a", 25 | "MON" => "%^a", 26 | "MST" => "%Z", 27 | "15" => "%H", 28 | "06" => "%y", 29 | "01" => "%m", 30 | "02" => "%d", 31 | "03" => "%I", 32 | "PM" => "%p", 33 | "pm" => "%P", 34 | "04" => "%M", 35 | "05" => "%S", 36 | "1" => "%-m", 37 | "2" => "%-e", 38 | "3" => "%l"}.freeze 39 | 40 | FORMAT_MATCHER = Regexp.union(FORMATS.keys) 41 | 42 | def format_string 43 | @format_string ||= reference.gsub(FORMAT_MATCHER, FORMATS) 44 | end 45 | 46 | def format(date) 47 | date.strftime(format_string) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /date_by_example.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path("lib", __dir__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require "date_by_example/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "date_by_example" 7 | spec.version = DateByExample::VERSION 8 | spec.authors = ["Noel Rappin"] 9 | spec.email = ["noelrappin@gmail.com"] 10 | 11 | spec.summary = "Go style date formatting by example" 12 | spec.description = "Go style date formatting by example" 13 | spec.homepage = "http://www.github.com/noelrappin/date_by_example" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files -z`.split("\x0").reject do |f| 17 | f.match(%r{^(test|spec|features)/}) 18 | end 19 | spec.bindir = "exe" 20 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 21 | spec.require_paths = ["lib"] 22 | 23 | spec.add_development_dependency "bundler", "~> 1.16" 24 | spec.add_development_dependency "rake", "~> 10.0" 25 | spec.add_development_dependency "rspec", "~> 3.0" 26 | spec.add_development_dependency "rubocop", "~> 0.57" 27 | spec.add_development_dependency "rubocop-rspec", "~> 1.25" 28 | end 29 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | date_by_example (0.1.1) 5 | 6 | GEM 7 | remote: https://rubygems.org/ 8 | specs: 9 | ast (2.4.0) 10 | diff-lcs (1.3) 11 | jaro_winkler (1.5.1) 12 | parallel (1.12.1) 13 | parser (2.5.1.0) 14 | ast (~> 2.4.0) 15 | powerpack (0.1.1) 16 | rainbow (3.0.0) 17 | rake (10.5.0) 18 | rspec (3.7.0) 19 | rspec-core (~> 3.7.0) 20 | rspec-expectations (~> 3.7.0) 21 | rspec-mocks (~> 3.7.0) 22 | rspec-core (3.7.1) 23 | rspec-support (~> 3.7.0) 24 | rspec-expectations (3.7.0) 25 | diff-lcs (>= 1.2.0, < 2.0) 26 | rspec-support (~> 3.7.0) 27 | rspec-mocks (3.7.0) 28 | diff-lcs (>= 1.2.0, < 2.0) 29 | rspec-support (~> 3.7.0) 30 | rspec-support (3.7.1) 31 | rubocop (0.57.1) 32 | jaro_winkler (~> 1.5.1) 33 | parallel (~> 1.10) 34 | parser (>= 2.5) 35 | powerpack (~> 0.1) 36 | rainbow (>= 2.2.2, < 4.0) 37 | ruby-progressbar (~> 1.7) 38 | unicode-display_width (~> 1.0, >= 1.0.1) 39 | rubocop-rspec (1.26.0) 40 | rubocop (>= 0.53.0) 41 | ruby-progressbar (1.9.0) 42 | unicode-display_width (1.4.0) 43 | 44 | PLATFORMS 45 | ruby 46 | 47 | DEPENDENCIES 48 | bundler (~> 1.16) 49 | date_by_example! 50 | rake (~> 10.0) 51 | rspec (~> 3.0) 52 | rubocop (~> 0.57) 53 | rubocop-rspec (~> 1.25) 54 | 55 | BUNDLED WITH 56 | 1.16.2 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DateByExample 2 | 3 | Provides a Ruby implementation of Go-style date formatting by example 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | ```ruby 10 | gem 'date_by_example' 11 | ``` 12 | 13 | And then execute: 14 | 15 | $ bundle 16 | 17 | Or install it yourself as: 18 | 19 | $ gem install date_by_example 20 | 21 | ## Usage 22 | 23 | ### Basic usage 24 | 25 | This gem adds a `by_example` method to `Date`, `Time`, and `DateTime`. 26 | 27 | The argument to this method is the formatted version of a reference date. 28 | 29 | For example: 30 | 31 | ``` 32 | > d = Date.today 33 | > d.by_example("2006-01-02") => "2018-06-11" 34 | 35 | > t = DateTime.now 36 | > t.by_example("Jan 02 2006 @ 3:04 pm") => "Jun 11 2018 @ 3:52 pm" 37 | 38 | > t = Time.now 39 | > t.by_example("Jan 02 2006 @ 3:04 pm") => "Jun 11 2018 @ 3:53 pm" 40 | ``` 41 | 42 | The reference date is Jan 2, 2006 at 3:04:05 PM MST, which can be 43 | remembered as 1 2 3 4 5 6 -7. 44 | 45 | I realize that remembering the reference date is not the easy part, 46 | but I think it's easier than remembering all the strftime format 47 | strings 48 | 49 | ### Supported formats 50 | 51 | * Year: 2006 and 06 (but not Ruby's %c for the century) 52 | * Month: January, JANUARY, Jan, JAN, 1, and 01, but not " 1" for space padding 53 | * Day: 2, 02, 002 (for day of year), Monday, MONDAY, Mon, MON, but not " 2" for space padding 54 | * Hour: 15, 3, pm, PM 55 | * Minute: 04 56 | * Second: 05, 05.000 for milliseconds and 05.000000 and 05.000000000 57 | * Time Zone: -7000, -07:00, -07:00:00, MST 58 | 59 | ### Unsupported Formats 60 | 61 | This does not support Ruby's week based formats 62 | 63 | ### Alternate usage 64 | 65 | The slow part of using this gem is generating the format string from 66 | the example, if you want to reuse a format multiple times, you can do so 67 | by creating and reusing an `ExampleFormatter` 68 | 69 | ``` 70 | > ef = ExampleFormatter.new("01/02/06") 71 | > ef.format(Date.today) => "06/11/18" 72 | > ef.format(Time.now) => "06/11/18" 73 | ``` 74 | 75 | ## Development 76 | 77 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 78 | 79 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 80 | 81 | ## Contributing 82 | 83 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/date_by_example. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 84 | 85 | ## License 86 | 87 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 88 | 89 | ## Code of Conduct 90 | 91 | Everyone interacting in the DateByExample project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/date_by_example/blob/master/CODE_OF_CONDUCT.md). 92 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at noelrappin@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | require: 2 | - rubocop-rspec 3 | 4 | AllCops: 5 | Exclude: 6 | - "db/schema.rb" # You can't touch this 7 | - ".bundle/**/*" # Auto-generated 8 | - "bin/**/*" # Auto-generated 9 | - "vendor/**/*" # We cannot solve the world's problems 10 | TargetRubyVersion: 2.5 11 | 12 | Rails: 13 | Enabled: false 14 | 15 | Metrics/AbcSize: 16 | Enabled: false 17 | 18 | Metrics/BlockLength: 19 | Enabled: false 20 | 21 | Metrics/ClassLength: 22 | Enabled: false 23 | 24 | Metrics/LineLength: 25 | Enabled: false 26 | 27 | Metrics/MethodLength: 28 | Enabled: false 29 | 30 | Metrics/ParameterLists: 31 | Enabled: false 32 | 33 | Layout/AlignParameters: 34 | EnforcedStyle: with_fixed_indentation 35 | IndentationWidth: 2 36 | 37 | Style/CaseEquality: 38 | Enabled: false 39 | 40 | Layout/EmptyLinesAroundBlockBody: 41 | Exclude: 42 | - "spec/**/*" 43 | - "lib/tasks/*.rake" 44 | 45 | Layout/FirstParameterIndentation: 46 | IndentationWidth: 2 47 | 48 | Style/FrozenStringLiteralComment: 49 | Enabled: false 50 | 51 | Layout/IndentArray: 52 | IndentationWidth: 2 53 | 54 | Layout/IndentAssignment: 55 | IndentationWidth: 2 56 | 57 | Layout/IndentHash: 58 | IndentationWidth: 2 59 | 60 | Layout/MultilineMethodCallBraceLayout: 61 | EnforcedStyle: same_line 62 | 63 | Layout/MultilineMethodCallIndentation: 64 | EnforcedStyle: indented 65 | IndentationWidth: 2 66 | 67 | Layout/MultilineHashBraceLayout: 68 | EnforcedStyle: same_line 69 | 70 | Layout/MultilineOperationIndentation: 71 | EnforcedStyle: indented 72 | IndentationWidth: 2 73 | 74 | Naming/VariableNumber: 75 | EnforcedStyle: snake_case 76 | 77 | Style/SignalException: 78 | EnforcedStyle: only_raise 79 | 80 | Style/StringLiterals: 81 | EnforcedStyle: double_quotes 82 | 83 | Style/TrivialAccessors: 84 | ExactNameMatch: true 85 | 86 | Style/TrailingCommaInHashLiteral: 87 | EnforcedStyleForMultiline: no_comma 88 | 89 | Style/TrailingCommaInArrayLiteral: 90 | EnforcedStyleForMultiline: no_comma 91 | 92 | Style/TrailingCommaInArguments: 93 | EnforcedStyleForMultiline: no_comma 94 | 95 | Layout/SpaceInsideBlockBraces: 96 | EnforcedStyle: space 97 | EnforcedStyleForEmptyBraces: no_space 98 | SpaceBeforeBlockParameters: true 99 | 100 | Layout/SpaceInsideHashLiteralBraces: 101 | EnforcedStyle: no_space 102 | EnforcedStyleForEmptyBraces: no_space 103 | 104 | Style/Documentation: 105 | Enabled: false 106 | 107 | Style/BlockDelimiters: 108 | Exclude: 109 | - "spec/**/*" # because let statements use braces for multiline blocks 110 | 111 | Layout/BlockEndNewline: 112 | Exclude: 113 | - "spec/**/*" # because let statements use braces for multiline blocks 114 | 115 | Layout/MultilineBlockLayout: 116 | Exclude: 117 | - "spec/**/*" # because let statements use braces for multiline blocks 118 | 119 | Style/Semicolon: 120 | AllowAsExpressionSeparator: true 121 | Exclude: 122 | - "spec/**/*" # because sometimes we use this in expect or then blocks 123 | 124 | Style/RaiseArgs: 125 | Enabled: false 126 | 127 | Style/AccessModifierDeclarations: 128 | Enabled: false 129 | 130 | RSpec/ContextWording: 131 | Enabled: false 132 | 133 | RSpec/ExampleLength: 134 | Enabled: false 135 | 136 | RSpec/HookArgument: 137 | EnforcedStyle: "example" 138 | 139 | RSpec/MultipleExpectations: 140 | Enabled: false 141 | 142 | RSpec/NestedGroups: 143 | Enabled: false 144 | 145 | RSpec/DescribedClass: 146 | Enabled: false 147 | 148 | Style/DateTime: 149 | Enabled: false 150 | -------------------------------------------------------------------------------- /spec/example_formatter_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe ExampleFormatter do 2 | 3 | def format_string_for(str) 4 | ExampleFormatter.new(str).format_string 5 | end 6 | 7 | def format_date(date, format) 8 | ExampleFormatter.new(format).format(date) 9 | end 10 | 11 | describe "years" do 12 | 13 | specify { expect(format_string_for("2006")).to eq("%Y") } 14 | specify { expect(format_string_for("06")).to eq("%y") } 15 | # ruby allows "%C for century, but I think we can't allow that here 16 | # because 20 is be ambiguous with 201 17 | 18 | end 19 | 20 | describe "months" do 21 | 22 | specify { expect(format_string_for("01")).to eq("%m") } 23 | # ruby has "%_m" for space padding, but we're not doing that 24 | specify { expect(format_string_for("1")).to eq("%-m") } 25 | specify { expect(format_string_for("January")).to eq("%B") } 26 | specify { expect(format_string_for("JANUARY")).to eq("%^B") } 27 | specify { expect(format_string_for("Jan")).to eq("%b") } 28 | specify { expect(format_string_for("JAN")).to eq("%^b") } 29 | 30 | end 31 | 32 | describe "day of month" do 33 | 34 | specify { expect(format_string_for("02")).to eq("%d") } 35 | # ruby has "%e" for space padding, but we're not doing that 36 | specify { expect(format_string_for("2")).to eq("%-e") } 37 | specify { expect(format_string_for("002")).to eq("%j") } 38 | specify { expect(format_string_for("Monday")).to eq("%A") } 39 | specify { expect(format_string_for("MONDAY")).to eq("%^A") } 40 | specify { expect(format_string_for("Mon")).to eq("%a") } 41 | specify { expect(format_string_for("MON")).to eq("%^a") } 42 | # ruby's numerical days of the week %u, %w probably can't be done 43 | 44 | end 45 | 46 | describe "hours" do 47 | specify { expect(format_string_for("15")).to eq("%H") } 48 | # ruby has %k for blank padded 24 hour clock but I can't do that here 49 | specify { expect(format_string_for("03")).to eq("%I") } 50 | specify { expect(format_string_for("3")).to eq("%l") } 51 | # ruby has "%l" for space padding, but we're not doing that 52 | specify { expect(format_string_for("PM")).to eq("%p") } 53 | specify { expect(format_string_for("pm")).to eq("%P") } 54 | end 55 | 56 | describe "minutes and seconds" do 57 | specify { expect(format_string_for("04")).to eq("%M") } 58 | specify { expect(format_string_for("05")).to eq("%S") } 59 | specify { expect(format_string_for(".000")).to eq(".%L") } 60 | specify { expect(format_string_for(".000000")).to eq(".%6N") } 61 | specify { expect(format_string_for(".000000000")).to eq(".9N") } 62 | end 63 | 64 | describe "timezone" do 65 | specify { expect(format_string_for("-7000")).to eq("%z") } 66 | specify { expect(format_string_for("-07:00")).to eq("%:z") } 67 | specify { expect(format_string_for("-07:00:00")).to eq("%::z") } 68 | specify { expect(format_string_for("MST")).to eq("%Z") } 69 | end 70 | 71 | # other things that can't be done here 72 | # %G -- week-based year 73 | # %g -- last two digits of week based year 74 | # %V -- week number of week based year 75 | # %U -- week number of year (sunday based) 76 | # %W -- week number of the year (monday based) 77 | # %s -- seconds since the epoch 78 | 79 | describe "can do date formats" do 80 | let(:date) { DateTime.new(2018, 6, 10, 13, 15) } 81 | 82 | specify { expect(format_string_for("Jan 2, 2006")).to eq("%b %-e, %Y") } 83 | specify { expect(format_date(date, "Jan 2, 2006")).to eq("Jun 10, 2018") } 84 | specify { expect(format_date(date, "01/02/06")).to eq("06/10/18") } 85 | specify { expect(format_string_for("2 Jan 06 15:04")).to eq("%-e %b %y %H:%M") } 86 | specify { expect(format_date(date, "2 Jan 06 15:04")).to eq("10 Jun 18 13:15") } 87 | specify { expect(date.by_example("Jan 2, 2006")).to eq("Jun 10, 2018") } 88 | specify { expect(date.by_example("January 02, 2006 @ 03:04pm")).to eq("June 10, 2018 @ 01:15pm") } 89 | end 90 | 91 | end 92 | --------------------------------------------------------------------------------