dtg 4.0.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,3 +1,14 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
7
+
8
+ desc 'pretty up the lib'
9
+ task :pretty do
10
+ exec('rbprettier --write lib/**/*.rb')
11
+ end
1
12
  # desc "Explaining what the task does"
2
13
  # task :dtg do
3
14
  # # Task goes here
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dtg"
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__)
@@ -0,0 +1,8 @@
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
@@ -1,47 +1,66 @@
1
1
  # Ensure all of library added to gem
2
- $:.push File.expand_path("lib", __dir__)
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
4
 
4
5
  # Maintain your gem's version:
5
- require "dtg/version"
6
+ require 'dtg/version'
6
7
 
7
- # Describe your gem and declare its dependencies:
8
8
  Gem::Specification.new do |spec|
9
- spec.name = "dtg"
10
- spec.version = Dtg::VERSION
11
- spec.authors = ["SolarisFlare"]
12
- spec.email = ["shadowbomb20@gmail.com"]
13
- spec.homepage = "https://github.com/SolarisFlare/dtg/"
14
- spec.summary = "DTG converts from a DateTime to a DTG"
15
- spec.description = "A DTG is a DateTimeGroup which is used in the military to save time. DTG
9
+ spec.name = 'dtg'
10
+ spec.version = Dtg::VERSION
11
+ spec.authors = %w[SolarisFlare]
12
+ spec.email = %w[shadowbomb20@gmail.com]
13
+ spec.homepage = 'https://github.com/SolarisFlare/dtg/README.md'
14
+ spec.summary = 'DTG converts from a DateTime to a DTG'
15
+ spec.description =
16
+ 'A DTG is a DateTimeGroup which is used in the military to save time. DTG
16
17
  are saved in the format DDHHMML MMM YY, where D is day, H is hour, L is
17
18
  letter, M is month, and Y is year. The Month is the 3 character
18
19
  representation such as JAN for January, MAY for May, DEC for December and so
19
20
  on. Year is only the last two digits of the year e.g. 2019 is just 19. The
20
21
  letter is the zone code such as W for whiskey which is HST, Z for zulu which
21
- is GMT, A-Z are the zones used."
22
- spec.license = "MIT"
23
- spec.required_rubygems_version = Gem::Requirement.new(">= 0") if spec.respond_to? \
24
- :required_rubygems_version=
25
- spec.files = Dir["Gemfile", "dtg.gemspec", "Rakefile", "lib/**/*"]
26
- spec.test_files = Dir["spec/**/*"]
27
- spec.rubygems_version = %q{1.6.2}
28
-
29
- # Active support is necessary for ActiveSupport::TimeWithZone integration
30
- spec.add_dependency "activesupport"
22
+ is GMT, A-Z are the zones used.'
23
+ spec.license = 'MIT'
31
24
 
32
25
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
33
26
  # to allow pushing to a single host or delete this section to allow pushing to any host.
34
27
  if spec.respond_to?(:metadata)
35
- spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
28
+ spec.metadata['allowed_push_host'] = 'NOSERVER'
29
+ spec.metadata['homepage_uri'] = spec.homepage
30
+ spec.metadata['source_code_uri'] = 'https://github.com/SolarisFlare/dtg'
31
+ spec.metadata['changelog_uri'] =
32
+ 'https://github.com/SolarisFlare/dtg/CHANGELOG.md'
36
33
  else
37
- raise "RubyGems 2.0 or newer is required to protect against " \
38
- "public gem pushes."
34
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
35
+ 'public gem pushes.'
39
36
  end
40
37
 
41
- if spec.respond_to? :specification_version then
42
- spec.specification_version = 3
38
+ # Specify test files that do not belong added when building gem
39
+ spec.test_files = Dir['spec/**/*']
43
40
 
44
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
41
+ # Specify which files should be added to the gem when it is released.
42
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
43
+ spec.files =
44
+ Dir.chdir(File.expand_path('..', __FILE__)) do
45
+ `git ls-files -z`.split("\x0").reject do |f|
46
+ f.match(%r{^(test|spec|features)/})
47
+ end
45
48
  end
46
- end
49
+ spec.bindir = 'exe'
50
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
51
+ spec.require_paths = %w[lib]
52
+
53
+ # Active support is necessary for ActiveSupport::TimeWithZone integration
54
+ spec.add_dependency 'activesupport'
55
+
56
+ # Bundler to manage gems ad versions
57
+ spec.add_development_dependency 'bundler', '~> 1.17'
58
+ # Rake to run tasks
59
+ spec.add_development_dependency 'rake', '~> 10.0'
60
+ # RSpec for testing suite
61
+ spec.add_development_dependency 'rspec', '~> 3.0'
62
+ # Prettier for better formatting
63
+ spec.add_development_dependency 'prettier'
64
+ # Coveralls for test suite reporting
65
+ spec.add_development_dependency 'coveralls'
47
66
  end
Binary file
data/lib/dtg.rb CHANGED
@@ -1,12 +1,25 @@
1
- require_relative "dtg/version"
2
- require_relative "dtg/date_time_group"
3
- require_relative "dtg/zones"
4
- require_relative "dtg/time_ext"
5
- require_relative "dtg/date_time_ext"
6
- require_relative "dtg/active_support/time_with_zone_ext"
1
+ # DTG version
2
+ require_relative 'dtg/version'
3
+ # Base module which contains all functionality
4
+ require_relative 'dtg/date_time_group'
5
+ # Zone codes and their offsets
6
+ require_relative 'dtg/zones'
7
+ # Format of DTG data (for conversion purposes)
8
+ require_relative 'dtg/format'
9
+ # Extension of DTG into Time object for native compatability
10
+ require_relative 'dtg/time_ext'
11
+ # Extension of DTG into DateTime object for native compatability
12
+ require_relative 'dtg/date_time_ext'
13
+ # Extension of DTG into ActiveSupport::TimeWithZone object for native compatability
14
+ require_relative 'dtg/active_support/time_with_zone_ext'
7
15
 
16
+ # Base module: Debug if active by calling Dtg.dtg to also check your current running version
8
17
  module Dtg
18
+ # Errors are nice
19
+ class Error < StandardError; end
20
+
21
+ # Announce DTG version and if incorporated properly into the application
9
22
  def self.dtg
10
- "DTG gem is active"
23
+ "DTG gem is active running version: #{VERSION}"
11
24
  end
12
25
  end
@@ -1,5 +1,5 @@
1
- require_relative "../date_time_group"
2
- require "active_support/time"
1
+ require_relative '../date_time_group'
2
+ require 'active_support/time'
3
3
 
4
4
  class ActiveSupport::TimeWithZone
5
5
  # Insert DTG Methods into this class
@@ -1,6 +1,6 @@
1
- require_relative "date_time_group"
2
- require "date"
3
- require "active_support/core_ext/date"
1
+ require_relative 'date_time_group'
2
+ require 'date'
3
+ require 'active_support/core_ext/date'
4
4
  # require "active_support/core_ext/date_and_time"
5
5
 
6
6
  class DateTime
@@ -1,15 +1,17 @@
1
- require_relative "zones"
1
+ require_relative 'zones'
2
+ require_relative 'format'
2
3
 
3
4
  module DateTimeGroup
4
5
  # Zones module has timezones (UTC_Zones) as dtg listings
5
6
  include Zones
7
+ include Format
6
8
 
7
9
  # Convert the object to the proper zone and then format as dtg in zone
8
10
  def to_dtg(zone = :z)
9
11
  convert(zone).format(zone)
10
12
  end
11
13
 
12
- # DTG Test to determine if was injected properly into class
14
+ # DTG Test to determine if was injected properly into class for native use
13
15
  def dtg
14
16
  "DTG gem is natively integrated with this class: #{self.class}"
15
17
  end
@@ -28,4 +30,54 @@ module DateTimeGroup
28
30
  raise "Error: #{zone} is not a valid zone" unless UTC_ZONES.key?(key)
29
31
  key == :j ? self.dup : self.in_time_zone(UTC_ZONES[key])
30
32
  end
33
+
34
+ # Parse will strip the DTG into its different fields
35
+ def self.parse(dtg)
36
+ {
37
+ day: dtg[FORMAT[:day_range]],
38
+ hour: dtg[FORMAT[:hour_range]],
39
+ minute: dtg[FORMAT[:minute_range]],
40
+ zone: dtg[FORMAT[:zone_range]],
41
+ month: dtg[FORMAT[:month_range]],
42
+ year: dtg[FORMAT[:year_range]]
43
+ }
44
+ end
45
+
46
+ # From will convert from DTG to a Time (not enough data to recreate AS or DateTime)
47
+ def self.from_dtg(dtg)
48
+ dtg_hash = parse(dtg)
49
+ year = dtg_hash[:year].to_i
50
+ if (Time.now.year % 100) < year
51
+ year = Time.now.year
52
+ else
53
+ year_temp = Time.now.year
54
+ year += year_temp - year_temp % 100
55
+ end
56
+ zone = UTC_ZONES[dtg_hash[:zone].downcase.to_sym].to_s
57
+ if zone.blank?
58
+ zone = '+00:00'
59
+ elsif zone == 'UTC'
60
+ zone = '+00:00'
61
+ elsif zone.size == 2
62
+ zone = zone[0] + '0' + zone[1] + ':00'
63
+ else
64
+ zone += ':00'
65
+ end
66
+ # Year, month, Day, Hour, Minute, Second, Offset
67
+ Time.new(
68
+ year,
69
+ dtg_hash[:month],
70
+ dtg_hash[:day].to_i,
71
+ dtg_hash[:hour].to_i,
72
+ dtg_hash[:minute].to_i,
73
+ 0,
74
+ zone
75
+ )
76
+ end
77
+
78
+ # Change will convert a DTG into a different zone with respect to its zone code
79
+ def self.convert(dtg, zone = :w)
80
+ old = from_dtg(dtg)
81
+ old.to_dtg(zone)
82
+ end
31
83
  end
@@ -0,0 +1,59 @@
1
+ # Data about the format of a dtg to aid parsing
2
+ module Format
3
+ # Structure of a dtg
4
+ # 01234567890123
5
+ # DDHHMML MMM YY
6
+
7
+ FORMAT = {
8
+ # Size of
9
+ size: 14,
10
+ # Size of day field
11
+ size_day: 2,
12
+ # Size of hour field
13
+ size_hour: 2,
14
+ # Size of minute field
15
+ size_minute: 2,
16
+ # Size of zone field
17
+ size_zone: 1,
18
+ # Size of month field
19
+ size_month: 3,
20
+ # Size of year field
21
+ size_year: 2,
22
+ # Start index of day field
23
+ day_start: 0,
24
+ # End index of day field
25
+ day_end: 1,
26
+ # Index range of day field
27
+ day_range: 0..1,
28
+ # Start index of hour field
29
+ hour_start: 2,
30
+ # End index of hour field
31
+ hour_end: 3,
32
+ # Index range of hour field
33
+ hour_range: 2..3,
34
+ # Start index of minute field
35
+ minute_start: 4,
36
+ # End index of minute field
37
+ minute_end: 5,
38
+ # Index range of minute field
39
+ minute_range: 4..5,
40
+ # Start index of zone field
41
+ zone_start: 6,
42
+ # End index of zone field
43
+ zone_end: 6,
44
+ # Index range of zone field
45
+ zone_range: 6..6,
46
+ # Start index of month field
47
+ month_start: 8,
48
+ # End index of month field
49
+ month_end: 10,
50
+ # Index range of month field
51
+ month_range: 8..10,
52
+ # Start index of year field
53
+ year_start: 12,
54
+ # End index of year field
55
+ year_end: 13,
56
+ # Index range of year field
57
+ year_range: 12..13
58
+ }
59
+ end
@@ -1,5 +1,5 @@
1
- require_relative "date_time_group"
2
- require "active_support/core_ext/time"
1
+ require_relative 'date_time_group'
2
+ require 'active_support/core_ext/time'
3
3
 
4
4
  class Time
5
5
  # Insert DTG Methods into this class
@@ -1,4 +1,4 @@
1
1
  module Dtg
2
2
  # DTG version of gem
3
- VERSION = "4.0.1"
3
+ VERSION = '5.0.0'
4
4
  end
@@ -20,7 +20,7 @@ module Zones
20
20
  # I: India Time: UTC +09:00 (Tokyo, Japan)
21
21
  i: +9,
22
22
  # J: Juliet Time: (Local Time Zone)
23
- j: "",
23
+ j: '',
24
24
  # K: Kilo Time: UTC +10:00 (Sydney, Australia)
25
25
  k: +10,
26
26
  # L: Lima Time: UTC +11:00 (Honiara, Solomon Islands)
@@ -52,6 +52,6 @@ module Zones
52
52
  # Y: Yankee Time: UTC -12:00 (Suva, Fiji)
53
53
  y: -12,
54
54
  # Z: Zulu Time: UTC +-00:00 (Greenwich, England)
55
- z: "UTC",
55
+ z: 'UTC'
56
56
  }
57
57
  end
@@ -0,0 +1,176 @@
1
+ RSpec.describe ActiveSupport::TimeWithZone do
2
+ # Set Time Zone before tests
3
+ before { Time.zone = 'UTC' }
4
+
5
+ # ActiveSupport::TimeWithZone preferred method of instantiation is with Time.zone.now, not new
6
+ let(:time) { Time.zone.now { include DateTimeGroup } }
7
+
8
+ describe '#to_dtg' do
9
+ context 'when zone is a symbol' do
10
+ context 'when symbol is lowercase' do
11
+ it 'converts and formats as dtg' do
12
+ (:a..:z).to_set.delete(:j).each do |zone|
13
+ expect(time.to_dtg(zone)).to eq(
14
+ time.in_time_zone(Zones::UTC_ZONES[zone]).strftime(
15
+ "%d%H%M#{zone.upcase.to_s} %b %y"
16
+ )
17
+ )
18
+ end
19
+ # :j is separate because there is no local timezone identifier,
20
+ # it just gets returned and formatted
21
+ expect(time.to_dtg(:j)).to eq(time.format(:j))
22
+ end
23
+ end
24
+
25
+ context 'when symbol is uppercase' do
26
+ it 'converts and formats as dtg' do
27
+ (:A..:Z).to_set.delete(:J).each do |zone|
28
+ expect(time.to_dtg(zone)).to eq(
29
+ time.in_time_zone(Zones::UTC_ZONES[zone.downcase]).strftime(
30
+ "%d%H%M#{zone.to_s} %b %y"
31
+ )
32
+ )
33
+ end
34
+ # :J is separate because there is no local timezone identifier,
35
+ # it just gets returned and formatted
36
+ expect(time.to_dtg(:J)).to eq(time.format(:j))
37
+ end
38
+ end
39
+ end
40
+
41
+ context 'when zone is a single character string' do
42
+ context 'when string is lowercase' do
43
+ it 'converts and formats as dtg' do
44
+ ('a'..'z').to_set.delete('j').each do |zone|
45
+ expect(time.to_dtg(zone)).to eq(
46
+ time.in_time_zone(Zones::UTC_ZONES[zone.to_sym]).strftime(
47
+ "%d%H%M#{zone.upcase} %b %y"
48
+ )
49
+ )
50
+ end
51
+ # 'j' is separate because there is no local timezone identifier
52
+ # it just gets returned and formatted
53
+ expect(time.to_dtg('j')).to eq(time.format(:j))
54
+ end
55
+ end
56
+
57
+ context 'when string is uppercase' do
58
+ it 'converts and formats as dtg' do
59
+ ('A'..'Z').to_set.delete('J').each do |zone|
60
+ expect(time.to_dtg(zone)).to eq(
61
+ time.in_time_zone(Zones::UTC_ZONES[zone.downcase.to_sym])
62
+ .strftime("%d%H%M#{zone} %b %y")
63
+ )
64
+ end
65
+ # 'J' is separate because there is no local timezone identifier,
66
+ # it just gets returned and formatted
67
+ expect(time.to_dtg('J')).to eq(time.format(:j))
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ describe '#format' do
74
+ context 'when zone is a symbol' do
75
+ context 'when symbol is lowercase' do
76
+ it 'formats to dtg standard' do
77
+ (:a..:z).each do |zone|
78
+ expect(time.format(zone)).to eq(
79
+ time.strftime("%d%H%M#{zone.upcase.to_s} %b %y")
80
+ )
81
+ end
82
+ end
83
+ end
84
+
85
+ context 'when symbol is uppercase' do
86
+ it 'formats to dtg standard' do
87
+ (:A..:Z).each do |zone|
88
+ expect(time.format(zone)).to eq(
89
+ time.strftime("%d%H%M#{zone.to_s} %b %y")
90
+ )
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'when zone is a single character string' do
97
+ context 'when string is lowercase' do
98
+ it 'formats to dtg standard' do
99
+ ('a'..'z').each do |zone|
100
+ expect(time.format(zone)).to eq(
101
+ time.strftime("%d%H%M#{zone.upcase} %b %y")
102
+ )
103
+ end
104
+ end
105
+ end
106
+
107
+ context 'when string is uppercase' do
108
+ it 'formats to dtg standard' do
109
+ ('A'..'Z').each do |zone|
110
+ expect(time.format(zone)).to eq(
111
+ time.strftime("%d%H%M#{zone} %b %y")
112
+ )
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ describe '#convert' do
120
+ context 'when zone is a symbol' do
121
+ context 'when symbol is lowercase' do
122
+ it 'returns converted time to new zone' do
123
+ (:a..:z).to_set.delete(:j).each do |zone|
124
+ expect(time.convert(zone)).to eq(
125
+ time.in_time_zone(Zones::UTC_ZONES[zone])
126
+ )
127
+ end
128
+ # :j is separate because there is no local timezone identifier,
129
+ # it just gets returned and formatted
130
+ expect(time.convert(:j)).to eq(time)
131
+ end
132
+ end
133
+
134
+ context 'when symbol is uppercase' do
135
+ it 'returns converted time to new zone' do
136
+ (:A..:Z).to_set.delete(:J).each do |zone|
137
+ expect(time.convert(zone)).to eq(
138
+ time.in_time_zone(Zones::UTC_ZONES[zone.downcase])
139
+ )
140
+ end
141
+ # :J is separate because there is no local timezone identifier,
142
+ # it just gets returned and formatted
143
+ expect(time.convert(:J)).to eq(time)
144
+ end
145
+ end
146
+ end
147
+
148
+ context 'when zone is a single character string' do
149
+ context 'when string is lowercase' do
150
+ it 'returns converted time to new zone' do
151
+ ('a'..'z').to_set.delete('j').each do |zone|
152
+ expect(time.convert(zone)).to eq(
153
+ time.in_time_zone(Zones::UTC_ZONES[zone.to_sym])
154
+ )
155
+ end
156
+ # 'j' is separate because there is no local timezone identifier,
157
+ # it just gets returned and formatted
158
+ expect(time.convert('j')).to eq(time)
159
+ end
160
+ end
161
+
162
+ context 'when string is uppercase' do
163
+ it 'returns converted time to new zone' do
164
+ ('A'..'Z').to_set.delete('J').each do |zone|
165
+ expect(time.convert(zone)).to eq(
166
+ time.in_time_zone(Zones::UTC_ZONES[zone.downcase.to_sym])
167
+ )
168
+ end
169
+ # 'J' is separate because there is no local timezone identifier,
170
+ # it just gets returned and formatted
171
+ expect(time.convert('J')).to eq(time)
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end